From 3b16e7241e5e5f54a4dcd34ca9c87e2f2cafd9b0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 08:02:16 +0200 Subject: [PATCH 01/86] Autosync the updated translations (#3019) Co-authored-by: github-actions <> --- apps/desktop/src/locales/da/messages.json | 40 +++++++++++------------ apps/desktop/src/locales/de/messages.json | 2 +- apps/desktop/src/locales/eo/messages.json | 6 ++-- apps/desktop/src/locales/fi/messages.json | 18 +++++----- apps/desktop/src/locales/lv/messages.json | 2 +- apps/desktop/src/locales/ro/messages.json | 16 ++++----- apps/desktop/src/locales/sr/messages.json | 8 ++--- apps/desktop/src/locales/uk/messages.json | 24 +++++++------- 8 files changed, 58 insertions(+), 58 deletions(-) diff --git a/apps/desktop/src/locales/da/messages.json b/apps/desktop/src/locales/da/messages.json index 620cf57887f..cbf2b163a13 100644 --- a/apps/desktop/src/locales/da/messages.json +++ b/apps/desktop/src/locales/da/messages.json @@ -126,7 +126,7 @@ "message": "Minimér, når du kopierer til udklipsholder" }, "minimizeOnCopyToClipboardDesc": { - "message": "Minimér, når du kopierer et elements data til udklipsholderen." + "message": "Minimér programmet, når du kopierer et elements data til udklipsholderen." }, "toggleVisibility": { "message": "Slå synlighed til/fra" @@ -728,7 +728,7 @@ "message": "Er du sikker på, at du vil logge ud?" }, "logOut": { - "message": "Log af" + "message": "Log ud" }, "addNewLogin": { "message": "Tilføj nyt login" @@ -833,7 +833,7 @@ "message": "Boks timeout" }, "vaultTimeoutDesc": { - "message": "Vælg timeout for din boks, hvorefter den vil udføre den valgte handling." + "message": "Vælg hvornår din boks skal udføre timeout-handlingen." }, "immediately": { "message": "Straks" @@ -895,10 +895,10 @@ "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "enableFavicon": { - "message": "Show website icons" + "message": "Vis webstedsikoner" }, "faviconDesc": { - "message": "Show a recognizable image next to each login." + "message": "Vis et genkendeligt billede ud for hvert login." }, "enableMinToTray": { "message": "Minimer til bakkeikon" @@ -913,7 +913,7 @@ "message": "Når vinduet minimeres, vis i stedet et ikon på menulinjen." }, "enableCloseToTray": { - "message": "Luk til ikon i meddelelsesområdet" + "message": "Luk ned til ikon i meddelelsesområdet" }, "enableCloseToTrayDesc": { "message": "Når vinduet lukkes, vis i stedet et ikon i meddelelsesområdet." @@ -1278,34 +1278,34 @@ "description": "hCaptcha is the name of a website, should not be translated" }, "loadAccessibilityCookie": { - "message": "Load Accessibility Cookie" + "message": "Indlæs tilgængelighedscookie" }, "registerAccessibilityUser": { - "message": "Register as an accessibility user at", + "message": "Registrér som tilgængelighedsbruger på", "description": "ex. Register as an accessibility user at hcaptcha.com" }, "copyPasteLink": { - "message": "Copy and paste the link sent to your email below" + "message": "Kopiér og indsæt linket, der er sendt til din e-mail nedenfor" }, "enterhCaptchaUrl": { - "message": "Enter URL to load accessibility cookie for hCaptcha", + "message": "Indtast URL for at indlæse tilgængelighedscookie til hCaptcha", "description": "hCaptcha is the name of a website, should not be translated" }, "hCaptchaUrlRequired": { - "message": "hCaptcha Url is required", + "message": "hCaptcha-URL er påkrævet", "description": "hCaptcha is the name of a website, should not be translated" }, "invalidUrl": { "message": "Ugyldig URL" }, "done": { - "message": "Done" + "message": "Udført" }, "accessibilityCookieSaved": { - "message": "Accessibility cookie saved!" + "message": "Tilgængelighedscookie gemt!" }, "noAccessibilityCookieSaved": { - "message": "No accessibility cookie saved" + "message": "Ingen tilgængelighedscookie gemt" }, "warning": { "message": "ADVARSEL", @@ -1382,10 +1382,10 @@ "message": "lås din boks op" }, "autoPromptWindowsHello": { - "message": "Ask for Windows Hello on launch" + "message": "Bed om Windows Hello ved start" }, "autoPromptTouchId": { - "message": "Ask for Touch ID on launch" + "message": "Bed om Touch ID ved start" }, "lockWithMasterPassOnRestart": { "message": "Lås med hovedadgangskode ved genstart" @@ -1440,10 +1440,10 @@ "message": "Boks timeout-handling" }, "vaultTimeoutActionLockDesc": { - "message": "En låst boks kræver at du gentaster din hovedadgangskode for at tilgå den igen." + "message": "Hovedadgangskode eller anden oplåsningsmetode kræves for at få adgang til din boks igen." }, "vaultTimeoutActionLogOutDesc": { - "message": "En boks der er logget ud kræver, at du godkender igen for at få adgang til den." + "message": "Gengodkendelse kræves for at få adgang til din boks igen." }, "lock": { "message": "Lås", @@ -1547,7 +1547,7 @@ "message": "Servicevilkår og fortrolighedspolitik er ikke blevet bekræftet." }, "enableBrowserIntegration": { - "message": "Aktiver browserintegration" + "message": "Tillad browserintegration" }, "enableBrowserIntegrationDesc": { "message": "Browserintegration bruges til biometri i browseren." @@ -1568,7 +1568,7 @@ "message": "Kræv verifikation for browserintegration" }, "enableBrowserIntegrationFingerprintDesc": { - "message": "Aktivér et ekstra sikkerhedslag ved at kræve validering af fingeraftrykssætning, når du opretter en forbindelse mellem dit skrivebord og din browser. Når det er aktiveret, kræver dette brugerintervention og verifikation hver gang en forbindelse oprettes." + "message": "Tilføj et ekstra sikkerhedslag ved at kræve bekræftelse af fingeraftrykssætning, når du opretter forbindelse mellem dit skrivebord og din browser. Dette kræver brugerhandling og verifikation, hver gang en forbindelse oprettes." }, "approve": { "message": "Godkend" diff --git a/apps/desktop/src/locales/de/messages.json b/apps/desktop/src/locales/de/messages.json index 66e0d59ba3b..3643edda8e3 100644 --- a/apps/desktop/src/locales/de/messages.json +++ b/apps/desktop/src/locales/de/messages.json @@ -1214,7 +1214,7 @@ "description": "Domain name. Ex. website.com" }, "host": { - "message": "Server", + "message": "Host", "description": "A URL's host value. For example, the host of https://sub.domain.com:443 is 'sub.domain.com:443'." }, "exact": { diff --git a/apps/desktop/src/locales/eo/messages.json b/apps/desktop/src/locales/eo/messages.json index 8ab1d61861d..ff3c33a6a83 100644 --- a/apps/desktop/src/locales/eo/messages.json +++ b/apps/desktop/src/locales/eo/messages.json @@ -15,7 +15,7 @@ "message": "Types" }, "typeLogin": { - "message": "Login" + "message": "Saluto" }, "typeCard": { "message": "Card" @@ -719,7 +719,7 @@ "message": "Feature Unavailable" }, "loggedOut": { - "message": "Logged out" + "message": "Adiaŭita" }, "loginExpired": { "message": "Your login session has expired." @@ -728,7 +728,7 @@ "message": "Are you sure you want to log out?" }, "logOut": { - "message": "Log out" + "message": "Adiaŭi" }, "addNewLogin": { "message": "Add New Login" diff --git a/apps/desktop/src/locales/fi/messages.json b/apps/desktop/src/locales/fi/messages.json index 2bcaa9e8b70..cf147dd9384 100644 --- a/apps/desktop/src/locales/fi/messages.json +++ b/apps/desktop/src/locales/fi/messages.json @@ -668,7 +668,7 @@ "message": "Kaksivaiheisen kirjautumisen asetukset" }, "selfHostedEnvironment": { - "message": "Oma palvelinympäristö" + "message": "Itse ylläpidetty palvelinympäristö" }, "selfHostedEnvironmentFooter": { "message": "Määritä omassa palvelinympäristössäsi suoritettavan Bitwarden-asennuksen pääverkkotunnus." @@ -1437,13 +1437,13 @@ "message": "Yksi tai useampi organisaatiokäytäntö vaikuttaa generaattorisi asetuksiin." }, "vaultTimeoutAction": { - "message": "Holvin aikakatkaisun toiminto" + "message": "Holvin aikakatkaisutoiminto" }, "vaultTimeoutActionLockDesc": { - "message": "Holvin käyttö edellyttää pääsalasanaa tai muuta avaustapaa." + "message": "Holvisi käyttö edellyttää pääsalasanaa tai muuta avaustapaa." }, "vaultTimeoutActionLogOutDesc": { - "message": "Holvin käyttö edellyttää uuttaa todennusta." + "message": "Holvisi käyttö edellyttää uutta todennusta." }, "lock": { "message": "Lukitse", @@ -1478,10 +1478,10 @@ "message": "Poista pysyvästi" }, "vaultTimeoutLogOutConfirmation": { - "message": "Uloskirjautuminen estää pääsyn holviisi ja vaatii ajan umpeuduttua todennuksen internet-yhteyden välityksellä. Haluatko varmasti käyttää asetusta?" + "message": "Uloskirjautuminen estää pääsyn holviisi ja vaatii ajan umpeuduttua todennuksen Internet-yhteyden välityksellä. Haluatko varmasti käyttää asetusta?" }, "vaultTimeoutLogOutConfirmationTitle": { - "message": "Aikakatkaisun toiminnon vahvistus" + "message": "Aikakatkaisutoiminnon vahvistus" }, "enterpriseSingleSignOn": { "message": "Yrityksen kertakirjautuminen (SSO)" @@ -1785,7 +1785,7 @@ "message": "Minuuttia" }, "vaultTimeoutPolicyInEffect": { - "message": "Organisaatiosi käytännöt vaikuttavat holvisi aikakatkaisuun. Suurin sallittu viive on $HOURS$ tunti(a) ja $MINUTES$ minuutti(a)", + "message": "Organisaatiosi käytännöt vaikuttavat holvisi aikakatkaisuun. Suurin sallittu aika on $HOURS$ tunti(a) ja $MINUTES$ minuutti(a)", "placeholders": { "hours": { "content": "$1", @@ -1798,7 +1798,7 @@ } }, "vaultTimeoutTooLarge": { - "message": "Holvisi aikakatkaisuviive ylittää organisaatiosi asettamat rajoitukset." + "message": "Holvisi aikakatkaisu ylittää organisaatiosi asettamat rajoitukset." }, "resetPasswordPolicyAutoEnroll": { "message": "Automaattinen liitos" @@ -1822,7 +1822,7 @@ "message": "Pääsalasana on poistettu." }, "convertOrganizationEncryptionDesc": { - "message": "$ORGANIZATION$ käyttää kertakirjautumista (SSO) oman avainpalvelimensa kanssa. Organisaation jäsenet eivät enää tarvitse pääsalasanaa kirjautumiseen.", + "message": "$ORGANIZATION$ käyttää kertakirjautumista (SSO) itse ylläpidetyllä avainpalvelimella. Organisaation jäsenet eivät enää tarvitse pääsalasanaa kirjautumiseen.", "placeholders": { "organization": { "content": "$1", diff --git a/apps/desktop/src/locales/lv/messages.json b/apps/desktop/src/locales/lv/messages.json index bb7f13b17ef..22e0d207d2e 100644 --- a/apps/desktop/src/locales/lv/messages.json +++ b/apps/desktop/src/locales/lv/messages.json @@ -1798,7 +1798,7 @@ } }, "vaultTimeoutTooLarge": { - "message": "Glabātavas noildze pāŗsniedz apvienības uzstādītos ierobežojumus." + "message": "Glabātavas noildze pārsniedz apvienības uzstādītos ierobežojumus." }, "resetPasswordPolicyAutoEnroll": { "message": "Automātiska ievietošana sarakstā" diff --git a/apps/desktop/src/locales/ro/messages.json b/apps/desktop/src/locales/ro/messages.json index ddb50ca8905..e03051713a9 100644 --- a/apps/desktop/src/locales/ro/messages.json +++ b/apps/desktop/src/locales/ro/messages.json @@ -872,7 +872,7 @@ "message": "Când sistemul este inactiv" }, "onSleep": { - "message": "Când sistemul este în repaus" + "message": "Când sistemul intră în repaus" }, "onLocked": { "message": "La blocarea sistemului" @@ -946,7 +946,7 @@ "message": "Pornire automată la conectare" }, "openAtLoginDesc": { - "message": "Pornește aplicația Bitwarden Desktop automat la autentificare." + "message": "Pornește automat aplicația Bitwarden desktop la conectare." }, "alwaysShowDock": { "message": "Se afișează întotdeauna în Dock" @@ -1394,7 +1394,7 @@ "message": "Preferințe" }, "enableMenuBar": { - "message": "Activare icon în bara de meniu" + "message": "Afișare pictogramă în bara de meniu" }, "enableMenuBarDesc": { "message": "Afișează întotdeauna un icon în bara de meniu." @@ -1440,10 +1440,10 @@ "message": "Acțiune la expirarea seifului" }, "vaultTimeoutActionLockDesc": { - "message": "Un seif blocat necesită reintroducerea parolei principale pentru a-l accesa din nou." + "message": "Este necesară parola principală sau o altă metodă de deblocare pentru a vă accesa din nou seiful." }, "vaultTimeoutActionLogOutDesc": { - "message": "Un seif deconectat necesită reintroducerea parolei principale pentru a-l accesa din nou." + "message": "Este necesară o nouă autentificare pentru a vă accesa din nou seiful." }, "lock": { "message": "Blocare", @@ -1547,7 +1547,7 @@ "message": "Termeni de utilizare și Politica de confidențialitate nu au fost recunoscute." }, "enableBrowserIntegration": { - "message": "Activați integrarea browserului" + "message": "Permiteți integrarea în browser" }, "enableBrowserIntegrationDesc": { "message": "Integrarea browserului este folosită pentru biometria în browser." @@ -1568,7 +1568,7 @@ "message": "Necesită verificare pentru integrarea browserului" }, "enableBrowserIntegrationFingerprintDesc": { - "message": "Activează un nivel suplimentar de securitate prin solicitarea validării frazei de amprentă la stabilirea unei legături între desktop și browser. Când este activată, aceasta necesită intervenția utilizatorului și verificarea de fiecare dată când este stabilită o conexiune." + "message": "Adăugați un nivel suplimentar de securitate solicitând confirmarea frazei amprentă atunci când stabiliți un link între desktop și browser. Acest lucru necesită o acțiune și o verificare din partea utilizatorului la fiecare creare a unei conexiuni." }, "approve": { "message": "Aprobați" @@ -1798,7 +1798,7 @@ } }, "vaultTimeoutTooLarge": { - "message": "Timpul de expirare a seifului depășește restricțiile stabilite de organizația dvs." + "message": "Timpul de expirare al seifului depășește restricțiile stabilite de organizația dvs." }, "resetPasswordPolicyAutoEnroll": { "message": "Înregistrare automată" diff --git a/apps/desktop/src/locales/sr/messages.json b/apps/desktop/src/locales/sr/messages.json index 0d72e35badc..8d6eff428fc 100644 --- a/apps/desktop/src/locales/sr/messages.json +++ b/apps/desktop/src/locales/sr/messages.json @@ -895,10 +895,10 @@ "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "enableFavicon": { - "message": "Show website icons" + "message": "Прикажи иконе сајтова" }, "faviconDesc": { - "message": "Show a recognizable image next to each login." + "message": "Прикажи препознатљиву слику поред сваке ставке за пријаву." }, "enableMinToTray": { "message": "Минимизирај као иконицу у системској траци" @@ -1382,10 +1382,10 @@ "message": "Откључај свој сеф" }, "autoPromptWindowsHello": { - "message": "Ask for Windows Hello on launch" + "message": "Захтевај Windows Hello при покретању" }, "autoPromptTouchId": { - "message": "Ask for Touch ID on launch" + "message": "Захтевај Touch ID при покретању" }, "lockWithMasterPassOnRestart": { "message": "Закључајте са главном лозинком при поновном покретању" diff --git a/apps/desktop/src/locales/uk/messages.json b/apps/desktop/src/locales/uk/messages.json index a56e95e57e0..cd1665e48f7 100644 --- a/apps/desktop/src/locales/uk/messages.json +++ b/apps/desktop/src/locales/uk/messages.json @@ -126,7 +126,7 @@ "message": "Згортати при копіюванні в буфер обміну" }, "minimizeOnCopyToClipboardDesc": { - "message": "Згортати при копіюванні даних запису в буфер обміну." + "message": "Згортати під час копіювання даних запису до буфера обміну." }, "toggleVisibility": { "message": "Перемкнути видимість" @@ -833,7 +833,7 @@ "message": "Час очікування сховища" }, "vaultTimeoutDesc": { - "message": "Оберіть дію, яка виконається після завершення часу очікування вашого сховища." + "message": "Оберіть дію, яка виконається після завершення часу очікування сховища." }, "immediately": { "message": "Негайно" @@ -869,16 +869,16 @@ "message": "4 години" }, "onIdle": { - "message": "При бездіяльності системи" + "message": "Бездіяльність системи" }, "onSleep": { - "message": "При переході в режим сну" + "message": "Перехід у режим сну" }, "onLocked": { - "message": "При блокуванні системи" + "message": "Блокування системи" }, "onRestart": { - "message": "При перезапуску" + "message": "Перезапуск" }, "never": { "message": "Ніколи" @@ -946,7 +946,7 @@ "message": "Запускати автоматично при вході" }, "openAtLoginDesc": { - "message": "Запускати програму Bitwarden для комп'ютера автоматично при вході в систему." + "message": "Запускати програму Bitwarden для комп'ютера автоматично із входом у систему." }, "alwaysShowDock": { "message": "Завжди показувати в панелі Dock" @@ -1394,7 +1394,7 @@ "message": "Налаштування" }, "enableMenuBar": { - "message": "Увімкнути піктограму в панелі завдань" + "message": "Показувати піктограму в панелі завдань" }, "enableMenuBarDesc": { "message": "Завжди показувати піктограму в панелі завдань." @@ -1440,10 +1440,10 @@ "message": "Дія після часу очікування сховища" }, "vaultTimeoutActionLockDesc": { - "message": "Щоб відновити доступ до заблокованого сховища, необхідно повторно ввести головний пароль." + "message": "Щоб відновити доступ до сховища, необхідно ввести головний пароль або скористатись іншим способом розблокування." }, "vaultTimeoutActionLogOutDesc": { - "message": "Щоб відновити доступ до сховища після виходу, необхідно повторно авторизуватись." + "message": "Щоб відновити доступ до сховища, необхідно повторно авторизуватись." }, "lock": { "message": "Блокувати", @@ -1547,7 +1547,7 @@ "message": "Умови користування та політика приватності не погоджені." }, "enableBrowserIntegration": { - "message": "Увімкнути інтеграцію з браузером" + "message": "Дозволити інтеграцію з браузером" }, "enableBrowserIntegrationDesc": { "message": "Інтеграція з браузером використовується для біометрії в браузері." @@ -1568,7 +1568,7 @@ "message": "Вимагати підтвердження для інтеграції з браузером" }, "enableBrowserIntegrationFingerprintDesc": { - "message": "Увімкніть додатковий рівень безпеки, вимагаючи перевірку фрази відбитка при встановленні зв'язку між програмою на комп'ютері та браузером. Якщо увімкнено, вимагатиметься втручання користувача і перевірка щоразу при встановленні зв'язку." + "message": "Додайте ще один рівень безпеки, вимагаючи підтвердження фрази відбитка під час встановлення зв'язку між програмою на комп'ютері та браузером. Вимагатиметься дія користувача і перевірка щоразу під час встановлення зв'язку." }, "approve": { "message": "Схвалити" From 86eb6315e92407cf4d671923ba3eec3028770a3d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 08:04:00 +0200 Subject: [PATCH 02/86] Autosync the updated translations (#3020) Co-authored-by: github-actions <> --- apps/web/src/locales/da/messages.json | 14 +-- apps/web/src/locales/de/messages.json | 4 +- apps/web/src/locales/en_GB/messages.json | 2 +- apps/web/src/locales/eo/messages.json | 126 +++++++++++------------ apps/web/src/locales/et/messages.json | 4 +- apps/web/src/locales/fi/messages.json | 58 +++++------ apps/web/src/locales/it/messages.json | 2 +- apps/web/src/locales/lv/messages.json | 2 +- apps/web/src/locales/nn/messages.json | 26 ++--- apps/web/src/locales/ro/messages.json | 4 +- apps/web/src/locales/zh_TW/messages.json | 2 +- 11 files changed, 122 insertions(+), 122 deletions(-) diff --git a/apps/web/src/locales/da/messages.json b/apps/web/src/locales/da/messages.json index 1fb0926e424..92ff887e75c 100644 --- a/apps/web/src/locales/da/messages.json +++ b/apps/web/src/locales/da/messages.json @@ -1155,17 +1155,17 @@ "message": "Vis webstedsikoner" }, "faviconDesc": { - "message": "Vis genkendeligt billede ved hvert login." + "message": "Vis et genkendeligt billede ud for hvert login." }, "enableGravatars": { - "message": "Aktivér Gravatars", + "message": "Vis Gravatarer", "description": "Use avatar images loaded from gravatar.com." }, "enableGravatarsDesc": { "message": "Brug avatar billeder hentet fra gravatar.com." }, "enableFullWidth": { - "message": "Aktivér layout med fuld bredde", + "message": "Vis layout med fuld bredde", "description": "Allows scaling the web vault UI's width" }, "enableFullWidthDesc": { @@ -3175,7 +3175,7 @@ "message": "Boks timeout" }, "vaultTimeoutDesc": { - "message": "Vælg timeout for din boks, hvorefter den vil udføre den valgte handling." + "message": "Vælg hvornår din boks skal udføre timeout-handlingen." }, "oneMinute": { "message": "1 minut" @@ -3196,7 +3196,7 @@ "message": "4 timer" }, "onRefresh": { - "message": "Ved genstart af browseren" + "message": "Ved browser opdatering" }, "dateUpdated": { "message": "Opdateret", @@ -3406,10 +3406,10 @@ "message": "Boks timeout-handling" }, "vaultTimeoutActionLockDesc": { - "message": "En låst boks kræver at du gentaster din hovedadgangskode for at tilgå den igen." + "message": "Hovedadgangskode eller anden oplåsningsmetode kræves for at få adgang til din boks igen." }, "vaultTimeoutActionLogOutDesc": { - "message": "En boks der er logget ud kræver, at du godkender igen for at få adgang til den." + "message": "Gengodkendelse kræves for at få adgang til din boks igen." }, "lock": { "message": "Lås", diff --git a/apps/web/src/locales/de/messages.json b/apps/web/src/locales/de/messages.json index 99498d6ea08..242a25a4ef9 100644 --- a/apps/web/src/locales/de/messages.json +++ b/apps/web/src/locales/de/messages.json @@ -1152,10 +1152,10 @@ "message": "Ändern Sie die Sprache für den Web-Tresor." }, "enableFavicon": { - "message": "Show website icons" + "message": "Zeige Webseiten-Icons" }, "faviconDesc": { - "message": "Show a recognizable image next to each login." + "message": "Ein wiedererkennbares Bild neben jeden Zugangsdaten anzeigen." }, "enableGravatars": { "message": "Gravatare aktivieren", diff --git a/apps/web/src/locales/en_GB/messages.json b/apps/web/src/locales/en_GB/messages.json index 303589bd033..773af050b3e 100644 --- a/apps/web/src/locales/en_GB/messages.json +++ b/apps/web/src/locales/en_GB/messages.json @@ -1155,7 +1155,7 @@ "message": "Show website icons" }, "faviconDesc": { - "message": "Show a recognizable image next to each login." + "message": "Show a recognisable image next to each login." }, "enableGravatars": { "message": "Enable Gravatars", diff --git a/apps/web/src/locales/eo/messages.json b/apps/web/src/locales/eo/messages.json index a7c4f081971..63abd2c3d28 100644 --- a/apps/web/src/locales/eo/messages.json +++ b/apps/web/src/locales/eo/messages.json @@ -1,6 +1,6 @@ { "pageTitle": { - "message": "$APP_NAME$ Reta Volbo", + "message": "Kasa retejo de $APP_NAME$", "description": "The title of the website in the browser window.", "placeholders": { "app_name": { @@ -10,7 +10,7 @@ } }, "whatTypeOfItem": { - "message": "Kia speco de ero estas ĉi tio?" + "message": "Kia tipo de elemento estas ĉi tio?" }, "name": { "message": "Nomo" @@ -47,10 +47,10 @@ "message": "Notoj" }, "customFields": { - "message": "Propraj Kampoj" + "message": "Propraj kampoj" }, "cardholderName": { - "message": "Nomo de Kartposedanto" + "message": "Nomo de la posedanto de la karto" }, "number": { "message": "Numero" @@ -65,7 +65,7 @@ "message": "Sekureca Kodo (CVV)" }, "identityName": { - "message": "Identeca Nomo" + "message": "Nomo de la identilo" }, "company": { "message": "Kompanio" @@ -74,10 +74,10 @@ "message": "Socia Sekureca Numero" }, "passportNumber": { - "message": "Pasporta Numero" + "message": "Numero de pasporto" }, "licenseNumber": { - "message": "Permesila Numero" + "message": "Numero de permesilo" }, "email": { "message": "Retpoŝto" @@ -86,40 +86,40 @@ "message": "Telefono" }, "january": { - "message": "januaro" + "message": "Januaro" }, "february": { "message": "februaro" }, "march": { - "message": "marto" + "message": "Marto" }, "april": { - "message": "aprilo" + "message": "Aprilo" }, "may": { - "message": "majo" + "message": "Majo" }, "june": { - "message": "junio" + "message": "Junio" }, "july": { - "message": "julio" + "message": "Julio" }, "august": { - "message": "aŭgusto" + "message": "Aŭgusto" }, "september": { - "message": "septembro" + "message": "Septembro" }, "october": { - "message": "oktobro" + "message": "Oktobro" }, "november": { - "message": "novembro" + "message": "Novembro" }, "december": { - "message": "decembro" + "message": "Decembro" }, "title": { "message": "Titolo" @@ -137,19 +137,19 @@ "message": "Dr" }, "expirationMonth": { - "message": "Finiĝa Monato" + "message": "Monato de validoperiodo" }, "expirationYear": { - "message": "Finiĝa Jaro" + "message": "Jaro de validoperiodo" }, "authenticatorKeyTotp": { - "message": "Aŭtentiga Ŝlosilo (TOTP)" + "message": "Ŝlosilo de aŭtentigo (TOTP)" }, "folder": { "message": "Dosierujo" }, "newCustomField": { - "message": "Nova Propra Kampo" + "message": "Nova propra kampo" }, "value": { "message": "Valoro" @@ -167,7 +167,7 @@ "message": "Bulea" }, "cfTypeLinked": { - "message": "Linked", + "message": "Ligita", "description": "This describes a field that is 'linked' (related) to another field." }, "remove": { @@ -191,7 +191,7 @@ "description": "Domain name. Ex. website.com" }, "domainName": { - "message": "Domain Name", + "message": "Nomo de domajno", "description": "Domain name. Ex. website.com" }, "host": { @@ -202,18 +202,18 @@ "message": "Ĝusta" }, "startsWith": { - "message": "Komencas per" + "message": "Komencas kun" }, "regEx": { "message": "Regula esprimo", "description": "A programming term, also known as 'RegEx'." }, "matchDetection": { - "message": "Match Match", + "message": "Detektilo de interrespondo", "description": "URI match detection for auto-fill." }, "defaultMatchDetection": { - "message": "Defaŭlta kongrua detekto", + "message": "Implicita detektilo de interrespondo", "description": "Default URI match detection for auto-fill." }, "never": { @@ -227,7 +227,7 @@ "description": "Toggling an expand/collapse state." }, "generatePassword": { - "message": "Generi Pasvorton" + "message": "Generi pasvorton" }, "checkPassword": { "message": "Kontrolu ĉu pasvorto estis elmontrita." @@ -242,7 +242,7 @@ } }, "passwordSafe": { - "message": "Ĉi tiu pasvorto ne troviĝis en iuj konataj rompo de datumoj. Ĝi estu sekure uzebla." + "message": "Ĉi tiu pasvorto ne estas trovita en iuj konataj branĉoj de databazo. Devas esti sekure uzeble." }, "save": { "message": "Konservi" @@ -257,13 +257,13 @@ "message": "Fermi" }, "delete": { - "message": "Forigi" + "message": "Forviŝi" }, "favorite": { - "message": "Plej ŝatata" + "message": "Preferaĵo" }, "unfavorite": { - "message": "Malfavoras" + "message": "Forigi de preferaĵo" }, "edit": { "message": "Redakti" @@ -278,7 +278,7 @@ "message": "Serĉi Favoratojn" }, "searchType": { - "message": "Serĉspeco", + "message": "Serĉo en tipo", "description": "Search item type" }, "searchVault": { @@ -294,28 +294,28 @@ "message": "Tipoj" }, "typeLogin": { - "message": "Ensaluti" + "message": "Saluto" }, "typeCard": { "message": "Karto" }, "typeIdentity": { - "message": "Identeco" + "message": "Identilo" }, "typeSecureNote": { - "message": "Sekura Noto" + "message": "Sekura noto" }, "typeLoginPlural": { - "message": "Logins" + "message": "Salutoj" }, "typeCardPlural": { - "message": "Cards" + "message": "Kartoj" }, "typeIdentityPlural": { - "message": "Identities" + "message": "Identiloj" }, "typeSecureNotePlural": { - "message": "Secure Notes" + "message": "Sekuraj notoj" }, "folders": { "message": "Dosierujoj" @@ -546,16 +546,16 @@ "message": "Forigita dosierujo" }, "loggedOut": { - "message": "Elsalutita" + "message": "Adiaŭita" }, "loginExpired": { - "message": "Via ensaluta kunsido eksvalidiĝis." + "message": "Via seanco eksvalidiĝis." }, "logOutConfirmation": { - "message": "Ĉu vi certe volas elsaluti?" + "message": "Ĉu vi certas ke vi volas adiaŭi?" }, "logOut": { - "message": "Eliri" + "message": "Adiaŭi" }, "ok": { "message": "Bone" @@ -573,7 +573,7 @@ "message": "Krei konton" }, "logIn": { - "message": "Ensaluti" + "message": "Saluti" }, "submit": { "message": "Sendu" @@ -630,7 +630,7 @@ "message": "Majstra pasvorto devas havi almenaŭ 8 signojn." }, "masterPassDoesntMatch": { - "message": "Majstra pasvorta konfirmo ne kongruas." + "message": "La konfirmo de la ĉefa pasvorto ne interrespondas." }, "newAccountCreated": { "message": "Via nova konto kreiĝis! Vi nun povas ensaluti." @@ -736,7 +736,7 @@ "message": "Enmetu vian sekurecan ŝlosilon en la USB-havenon de via komputilo. Se ĝi havas butonon, tuŝu ĝin." }, "loginUnavailable": { - "message": "Ensaluto Neatingebla" + "message": "Saluto ne disponebla" }, "noTwoStepProviders": { "message": "Ĉi tiu konto havas du-paŝan ensaluton ebligita, tamen neniu el la agorditaj du-paŝaj provizantoj estas subtenata de ĉi tiu retumilo." @@ -745,7 +745,7 @@ "message": "Bonvolu uzi subtenatan tTT-legilon (kiel Chrome) kaj / aŭ aldoni pliajn provizantojn pli bone subtenatajn tra tTT-legiloj (kiel aŭtentikiga programo)." }, "twoStepOptions": { - "message": "Duŝtupaj Ensalutaj Elektoj" + "message": "Elektebloj de la du-faktora aŭtentigo" }, "recoveryCodeDesc": { "message": "Ĉu vi perdis aliron al ĉiuj viaj du-faktoraj provizantoj? Uzu vian reakiran kodon por malŝalti ĉiujn du-faktorajn provizantojn de via konto." @@ -965,16 +965,16 @@ } }, "loggedOutWarning": { - "message": "Daŭrigi vin elsalutos de via nuna sesio, postulante vin denove ensaluti. Aktivaj sesioj sur aliaj aparatoj povas daŭre resti aktivaj ĝis unu horo." + "message": "Prilabori vian adiaŭadon de la nuna seanco, necesigos vin saluti denove. La seancoj aktivaj sur aliaj aparatoj povas resti aktivaj ankoraŭ unu horon." }, "emailChanged": { "message": "Retpoŝto Ŝanĝis" }, "logBackIn": { - "message": "Bonvolu ensaluti denove." + "message": "Bonvolu saluti refoje." }, "logBackInOthersToo": { - "message": "Bonvolu ensaluti. Se vi uzas aliajn Bitwarden-programojn, elsalutu kaj reen al tiuj ankaŭ." + "message": "Bonvolu saluti refoje. Se vi uzas aliajn programojn de Bitwarden, adiaŭu kaj ankaŭ salutu ilin." }, "changeMasterPassword": { "message": "Ŝanĝi Majstran Pasvorton" @@ -1037,7 +1037,7 @@ "message": "Ĉu vi zorgas pri tio, ke via konto estas ensalutinta sur alia aparato? Sekvu sube por senrajtigi ĉiujn komputilojn aŭ aparatojn, kiujn vi antaŭe uzis. Ĉi tiu sekureca paŝo rekomendas se vi antaŭe uzis publikan komputilon aŭ hazarde konservis vian pasvorton sur aparato, kiu ne estas via. Ĉi tiu paŝo ankaŭ malplenigos ĉiujn antaŭe memoritajn du-paŝajn ensalutajn sesiojn. " }, "deauthorizeSessionsWarning": { - "message": "La daŭrigo ankaŭ elsalutos vin de via nuna sesio, postulante vin denove ensaluti. Oni ankaŭ petos vin du-ŝtupa ensaluto, se ĝi estas ebligita. Aktivaj sesioj sur aliaj aparatoj povas daŭre resti aktivaj ĝis ĝis unu horo. " + "message": "Se vi daŭrigos vian adiaŭadon de la nuna seanco, necesos vin saluti denove. Oni ankaŭ demandos de vi du-faktoran aŭtentigon, se la opcio estas ebligita. La seancoj aktivaj sur aliaj aparatoj povas resti daŭre aktivaj ankoraŭ unu horon." }, "sessionsDeauthorized": { "message": "Ĉiuj Sesioj Neaŭtorizitaj" @@ -1112,7 +1112,7 @@ "message": "Nenio estis importita." }, "importEncKeyError": { - "message": "Error decrypting the exported file. Your encryption key does not match the encryption key used export the data." + "message": "Eraro de deĉifrado de la elportaĵo. Via ŝlosilo de ĉifrado ne interrespondas kun la ŝlosilo de ĉifrado uzita por elporti la datenon." }, "selectFormat": { "message": "Elektu la formaton de la importa dosiero" @@ -1149,7 +1149,7 @@ "message": "Lingvo" }, "languageDesc": { - "message": "Ŝanĝi la lingvon uzatan de la retejo-volbo." + "message": "Ŝanĝi la lingvon uzatan por la retejo de la kaso." }, "enableFavicon": { "message": "Show website icons" @@ -1214,7 +1214,7 @@ "message": "Domajnoj ĝisdatigitaj" }, "twoStepLogin": { - "message": "Du-ŝtupa ensaluto" + "message": "Du-faktora aŭtentigo" }, "twoStepLoginDesc": { "message": "Sekurigu vian konton postulante plian paŝon kiam vi ensalutas." @@ -1453,7 +1453,7 @@ "message": "Web vault and browser extensions on a desktop/laptop with a WebAuthn enabled browser (Chrome, Opera, Vivaldi, or Firefox with FIDO U2F enabled)." }, "twoFactorRecoveryYourCode": { - "message": "Via Bitwarden-du-ŝtupa ensaluta reakiro-kodo" + "message": "Via kodo de senpaneigo de la du-faktora aŭtentigo de Bitwarden" }, "twoFactorRecoveryNoCode": { "message": "Vi ankoraŭ ne ebligis du-paŝajn ensalutajn provizantojn. Post kiam vi ebligis du-ŝtupan ensalut-provizanton, vi povas kontroli ĉi tie vian reakiran kodon." @@ -2383,10 +2383,10 @@ "message": "Ebligita / ĝisdatigita du-ŝtupa ensaluto." }, "disabled2fa": { - "message": "Malebligita du-ŝtupa ensaluto." + "message": "Du-faktora aŭtentigo malebligita." }, "recovered2fa": { - "message": "Rekuperita konto post du-ŝtupa ensaluto." + "message": "Konto senpaneigita el du-faktora aŭtentigo." }, "failedLogin": { "message": "Ensaluta provo malsukcesis kun malĝusta pasvorto." @@ -2857,10 +2857,10 @@ "message": "Se vi ne povas aliri vian konton per viaj normalaj du-ŝtupaj ensalutaj metodoj, vi povas uzi vian du-ŝtupan ensalutan rekuperan kodon por malŝalti ĉiujn du-ŝtupajn provizantojn en via konto." }, "recoverAccountTwoStep": { - "message": "Rekuperi Ensaluton Du-Paŝan" + "message": "Senpaneigi la du-faktoran aŭtentigon de la konto" }, "twoStepRecoverDisabled": { - "message": "Du-ŝtupa ensaluto estas malŝaltita en via konto." + "message": "Du-faktora aŭtentigo estas neebligita en via konto." }, "learnMore": { "message": "Lernu pli" @@ -2983,7 +2983,7 @@ "message": "Nomo de Konto-Posedanto" }, "bankAccountType": { - "message": "Kontospeco" + "message": "Tipo de konto" }, "bankAccountTypeCompany": { "message": "Kompanio (Komerco)" @@ -3528,7 +3528,7 @@ "message": "Identigilo" }, "organizationIdentifier": { - "message": "Organiza Identigilo" + "message": "Identigilo de la organizaĵo" }, "ssoLogInWithOrgIdentifier": { "message": "Ensalutu per la unika ensaluta portalo de via organizo. Bonvolu enigi la identigilon de via organizo por komenci." @@ -3871,7 +3871,7 @@ "message": "Krizaliro malakceptita" }, "passwordResetFor": { - "message": "Pasvorta restarigo por $USER $. Vi nun povas ensaluti per la nova pasvorto.", + "message": "Pravaloriziĝis la pasvorto de $USER$. Vi nun povas saluti per la nova pasvorto.", "placeholders": { "user": { "content": "$1", diff --git a/apps/web/src/locales/et/messages.json b/apps/web/src/locales/et/messages.json index 9406f13a093..193763ce43b 100644 --- a/apps/web/src/locales/et/messages.json +++ b/apps/web/src/locales/et/messages.json @@ -1152,10 +1152,10 @@ "message": "Siin saab veebihoidla keelt muuta." }, "enableFavicon": { - "message": "Show website icons" + "message": "Kuva veebilehtede ikoone" }, "faviconDesc": { - "message": "Show a recognizable image next to each login." + "message": "Kuva iga kirje kõrval lehekülje ikooni." }, "enableGravatars": { "message": "Luba Gravatarid", diff --git a/apps/web/src/locales/fi/messages.json b/apps/web/src/locales/fi/messages.json index 58323192e3f..b5a72a79306 100644 --- a/apps/web/src/locales/fi/messages.json +++ b/apps/web/src/locales/fi/messages.json @@ -1267,7 +1267,7 @@ "message": "Poista käytöstä" }, "deactivate": { - "message": "Poista aktivointi" + "message": "Deaktivoi" }, "twoStepLoginProviderEnabled": { "message": "Tämä kaksivaiheisen kirjautumisen todentaja on käytössä tililläsi." @@ -2236,7 +2236,7 @@ "message": "Jäsenellä ei ole enää organisaation käyttöoikeutta, mutta hän voi edelleen käyttää henkilökohtaista hoviaan." }, "activateUserConfirmation": { - "message": "Haluatko varmasti aktivoida käyttäjän ja myöntää heille organisaation käyttöoikeuden?" + "message": "Haluatko varmasti aktivoida käyttäjän ja myöntää hänelle käyttöoikeuden organisaatioon?" }, "removeUserConfirmationKeyConnector": { "message": "Varoitus! Tämä käyttäjä tarvitsee salauksensa hallintaan Key Connectoria. Käyttäjän poistaminen organisaatiostasi poistaa heidän tilinsä käytöstä pysvästi. Toimenpide on pysyvä, eikä sen peruminen ole mahdollista. Haluatko jatkaa?" @@ -2584,7 +2584,7 @@ } }, "deactivatedUserId": { - "message": "Käyttäjän $ID$ aktivointi poistettiin.", + "message": "Käyttäjä $ID$ on deaktivoitu.", "placeholders": { "id": { "content": "$1", @@ -2593,7 +2593,7 @@ } }, "activatedUserId": { - "message": "Käyttäjä $ID$ aktivointiin.", + "message": "Käyttäjä $ID$ on aktivoitu.", "placeholders": { "id": { "content": "$1", @@ -2602,7 +2602,7 @@ } }, "deactivateUserId": { - "message": "Poistetaanko käyttäjän $ID$ aktivointi?", + "message": "Deaktivoidaanko käyttäjä $ID$?", "placeholders": { "id": { "content": "$1", @@ -3403,13 +3403,13 @@ "message": "Käyttäjän asetus" }, "vaultTimeoutAction": { - "message": "Holvin aikakatkaisun toiminto" + "message": "Holvin aikakatkaisutoiminto" }, "vaultTimeoutActionLockDesc": { - "message": "Holvin käyttö edellyttää pääsalasanaa tai muuta avaustapaa." + "message": "Holvisi käyttö edellyttää pääsalasanaa tai muuta avaustapaa." }, "vaultTimeoutActionLogOutDesc": { - "message": "Holvin käyttö edellyttää uuttaa todennusta." + "message": "Holvisi käyttö edellyttää uutta todennusta." }, "lock": { "message": "Lukitse", @@ -3501,7 +3501,7 @@ "message": "Uloskirjautuminen estää pääsyn holviisi ja vaatii ajan umpeuduttua todennuksen internet-yhteyden välityksellä. Haluatko varmasti käyttää tätä asetusta?" }, "vaultTimeoutLogOutConfirmationTitle": { - "message": "Aikakatkaisun toiminnon vahvistus" + "message": "Aikakatkaisutoiminnon vahvistus" }, "hidePasswords": { "message": "Piilota salasanat" @@ -3667,7 +3667,7 @@ "message": "Poistettu käytöstä" }, "deactivated": { - "message": "Aktivointi poistettiin" + "message": "Deaktivoitu" }, "sendLink": { "message": "Send-linkki", @@ -4271,10 +4271,10 @@ "message": "Haluatko varmasti poistaa seuraavat käyttäjät? Toiminto saattaa kestää muutamia sekunteja, eikä sen keskeytys tai peruminen ole mahdollista." }, "deactivateUsersWarning": { - "message": "Haluatko varmasti poistaa seuraavien käyttäjien aktivoinnin? Heillä ei enää ole organisaation käyttöoikeutta, mutta he voivat edelleen käyttää henkilökohtaisia holvejaan. Toiminto saattaa kestää muutamia sekunteja, eikä sen keskeytys tai peruminen ole mahdollista." + "message": "Haluatko varmasti deaktivoida seuraavat käyttäjät? Heillä ei enää ole organisaation käyttöoikeutta, mutta he voivat edelleen käyttää henkilökohtaisia holvejaan. Toiminto saattaa kestää muutamia sekunteja, eikä sen keskeytys tai peruminen ole mahdollista." }, "activateUsersWarning": { - "message": "Haluatko varmasti aktivoida seuraavat käyttäjät ja myöntää heille organisaation käyttöoikeuden? Toiminto saattaa kestää muutamia sekunteja, eikä sen keskeytys tai peruminen ole mahdollista." + "message": "Haluatko varmasti aktivoida seuraavat käyttäjät ja myöntää heille käyttöoikeuden organisaatioon? Toiminto saattaa kestää muutamia sekunteja, eikä sitä ole mahdollista keskeyttää tai perua." }, "theme": { "message": "Teema" @@ -4307,7 +4307,7 @@ "message": "Poistettu onnistuneesti." }, "bulkDeactivatedMessage": { - "message": "Aktivoinnin poisto onnistui" + "message": "Deaktivointi onnistui" }, "bulkActivatedMessage": { "message": "Aktivointi onnistui" @@ -4322,7 +4322,7 @@ "message": "Poista käyttäjiä" }, "deactivateUsers": { - "message": "Poista käyttäjien aktivointi" + "message": "Deaktivoi käyttäjät" }, "activateUsers": { "message": "Aktivoi käyttäjät" @@ -4467,13 +4467,13 @@ "message": "Holvin aikakatkaisu" }, "maximumVaultTimeoutDesc": { - "message": "Määritä holvin aikakatkaisun enimmäisviive kaikille käyttäjille." + "message": "Määritä holvin aikakatkaisun enimmäisaika kaikille käyttäjille." }, "maximumVaultTimeoutLabel": { - "message": "Holvin aikakatkaisun enimmäisviive" + "message": "Holvin aikakatkaisun enimmäisaika" }, "invalidMaximumVaultTimeout": { - "message": "Virheellinen holvin aikakatkaisun enimmäisviive." + "message": "Virheellinen holvin aikakatkaisun enimmäisaika." }, "hours": { "message": "Tuntia" @@ -4482,7 +4482,7 @@ "message": "Minuuttia" }, "vaultTimeoutPolicyInEffect": { - "message": "Organisaatiosi käytännöt vaikuttavat holvisi aikakatkaisuun. Suurin sallittu viive on $HOURS$ tunti(a) ja $MINUTES$ minuutti(a)", + "message": "Organisaatiosi käytännöt vaikuttavat holvisi aikakatkaisuun. Suurin sallittu aika on $HOURS$ tunti(a) ja $MINUTES$ minuutti(a)", "placeholders": { "hours": { "content": "$1", @@ -4495,16 +4495,16 @@ } }, "customVaultTimeout": { - "message": "Mukautettu holvin aikakatkaisuviive" + "message": "Mukautettu holvin aikakatkaisu" }, "vaultTimeoutToLarge": { - "message": "Holvisi aikakatkaisuviive ylittää organisaatiosi asettamat rajoitukset." + "message": "Holvisi aikakatkaisu ylittää organisaatiosi asettamat rajoitukset." }, "vaultCustomTimeoutMinimum": { - "message": "Lyhin omavalintainen aikakatkaisuaika on 1 minuutti." + "message": "Mukautetun aikakatkaisun vähimmäisaika on 1 minuutti." }, "vaultTimeoutRangeError": { - "message": "Holvin aikakatkaisuaika ei ole sallitun alueen sisällä." + "message": "Holvin aikakatkaisu ei ole sallitun alueen sisällä." }, "disablePersonalVaultExport": { "message": "Poista henkilökohtaisen holvin vienti käytöstä" @@ -4777,7 +4777,7 @@ "message": "Virheellinen todennuskoodi" }, "convertOrganizationEncryptionDesc": { - "message": "$ORGANIZATION$ käyttää kertakirjautumista (SSO) itse ylläpitämänsä avainpalvelimen kanssa. Organisaation jäsenet eivät enää tarvitse pääsalasanaa kirjautumiseen.", + "message": "$ORGANIZATION$ käyttää kertakirjautumista (SSO) itse ylläpidetyllä avainpalvelimella. Organisaation jäsenet eivät enää tarvitse pääsalasanaa kirjautumiseen.", "placeholders": { "organization": { "content": "$1", @@ -4903,7 +4903,7 @@ "message": "Uudista tunniste" }, "rotateBillingSyncTokenWarning": { - "message": "Jos jatkat, on itse ylläpitämäsi palvelimen laskutuksen synkronointi määritettävä uudelleen." + "message": "Jos jatkat, tulee itse ylläpitämäsi palvelimen laskutuksen synkronointi määrittää uudelleen." }, "rotateBillingSyncTokenTitle": { "message": "Laskutuksen synkronointitunnisteen uudistus mitätöi edellisen tunnisteen." @@ -4912,7 +4912,7 @@ "message": "Itse ylläpidetty" }, "selfHostingEnterpriseOrganizationSectionCopy": { - "message": "Määrittääksesi organisaatiosi itse ylläpitämällesi palvelimelle, on lisenssitiedostosi tallennettava sinne. Sinun on määritettävä laskutuksen synkronointi, jotta ilmaiset Perheille-tilaukset ja edistyneet laskutusominaisuudet ovat itse ylläpitämäsi organisaation käytettävissä." + "message": "Määrittääksesi organisaation omalle palvelimellesi, tulee lisenssitiedosto tallentaa sinne. Sinun on määritettävä laskutuksen synkronointi, jotta ilmaiset Perheille-tilaukset ja edistyneet laskutusominaisuudet ovat itse ylläpitämäsi organisaation käytettävissä." }, "billingSyncApiKeyRotated": { "message": "Tunniste uudistettiin." @@ -4921,19 +4921,19 @@ "message": "Laskutuksen synkronointi" }, "billingSyncDesc": { - "message": "Laskutuksen synkronointi mahdollistaa jäsenille ilmaiset Perheille-tilaukset ja edistyneet laskutusominaisuudet liittämällä itse ylläpitämäsi Bitwarden-palvelimen Bitwardenin pilvipalvelimeen." + "message": "Laskutuksen synkronointi mahdollistaa jäsenille ilmaiset Perheille-tilaukset ja edistyneet laskutusominaisuudet liittämällä itse ylläpitämäsi Bitwarden-palvelin Bitwardenin pilvipalvelimeen." }, "billingSyncKeyDesc": { - "message": "Tämän lomakkeen täyttöön tarvitaan laskutuksen synkronointitunniste pilviorganisaatiosi tilausasetuksista." + "message": "Lomakkeen täyttö edellyttää laskutuksen synkronointitunnisteen pilviorganisaatiosi tilausasetuksista." }, "billingSyncKey": { "message": "Laskutuksen synkronointitunniste" }, "active": { - "message": "Käytössä" + "message": "Aktiivinen" }, "inactive": { - "message": "Ei käytössä" + "message": "Ei aktivoitu" }, "sentAwaitingSync": { "message": "Lähetetty (odottaa synkronointia)" diff --git a/apps/web/src/locales/it/messages.json b/apps/web/src/locales/it/messages.json index 29fe2728769..0745bc5b555 100644 --- a/apps/web/src/locales/it/messages.json +++ b/apps/web/src/locales/it/messages.json @@ -5117,7 +5117,7 @@ "Description": "Used as a prefix to indicate the last time a sync occured. Example \"Last sync 1968-11-16 00:00:00\"" }, "sponsorshipsSynced": { - "message": "Self-hosted sponsorships synced." + "message": "Sponsorizzazione self-hosted sincronizzata." }, "billingManagedByProvider": { "message": "Gestito da $PROVIDER$", diff --git a/apps/web/src/locales/lv/messages.json b/apps/web/src/locales/lv/messages.json index 8faa6ed01bc..4a206389ea5 100644 --- a/apps/web/src/locales/lv/messages.json +++ b/apps/web/src/locales/lv/messages.json @@ -4498,7 +4498,7 @@ "message": "Pielāgota glabātavas noildze" }, "vaultTimeoutToLarge": { - "message": "Glabātavas noildze pāŗsniedz apvienības uzstādīto ierobežojumu." + "message": "Glabātavas noildze pārsniedz apvienības uzstādītos ierobežojumus." }, "vaultCustomTimeoutMinimum": { "message": "Mazākā pieļaujamā pielāgotā noildze ir 1 minūte." diff --git a/apps/web/src/locales/nn/messages.json b/apps/web/src/locales/nn/messages.json index cee5cd365a6..77dd2db4f5f 100644 --- a/apps/web/src/locales/nn/messages.json +++ b/apps/web/src/locales/nn/messages.json @@ -177,7 +177,7 @@ "message": "Unassigned" }, "noneFolder": { - "message": "Ingen mappe", + "message": "Inga mappe", "description": "This is the folder for uncategorized items" }, "addFolder": { @@ -202,10 +202,10 @@ "message": "Exact" }, "startsWith": { - "message": "Starts with" + "message": "Byrjar med" }, "regEx": { - "message": "Regular expression", + "message": "Regulært uttrykk", "description": "A programming term, also known as 'RegEx'." }, "matchDetection": { @@ -251,7 +251,7 @@ "message": "Avbryt" }, "canceled": { - "message": "Canceled" + "message": "Brote av" }, "close": { "message": "Lat att" @@ -464,10 +464,10 @@ "message": "Sletta vedlegget" }, "deleteAttachmentConfirmation": { - "message": "Are you sure you want to delete this attachment?" + "message": "Er du trygg på at du vil sletta dette vedlegget?" }, "attachmentSaved": { - "message": "The attachment has been saved." + "message": "Vedlegget er vorte lagra." }, "file": { "message": "Fil" @@ -531,10 +531,10 @@ "message": "Flytta oppføringar" }, "overwritePasswordConfirmation": { - "message": "Are you sure you want to overwrite the current password?" + "message": "Er du trygg på at du vil skriva over passordet du har no?" }, "editedFolder": { - "message": "Edited folder" + "message": "Reidd mappa" }, "addedFolder": { "message": "Added folder" @@ -543,7 +543,7 @@ "message": "Are you sure you want to delete this folder?" }, "deletedFolder": { - "message": "Deleted folder" + "message": "Sletta mappe" }, "loggedOut": { "message": "Logged out" @@ -855,7 +855,7 @@ "message": "Copy Verification Code" }, "warning": { - "message": "Warning" + "message": "Åtvaring" }, "confirmVaultExport": { "message": "Confirm Vault Export" @@ -2239,7 +2239,7 @@ "message": "Are you sure you want to activate this user, granting them access to the organization?" }, "removeUserConfirmationKeyConnector": { - "message": "Warning! This user requires Key Connector to manage their encryption. Removing this user from your organization will permanently disable their account. This action cannot be undone. Do you want to proceed?" + "message": "Åtvaring! Dette brukarnamnet krev nykelkopling for å administrera krypteringa. Fjernar du denne brukaren frå verksemda di vil det deaktivera kontoen deira. Du kan ikkje angra på denne gjerda. Vil du halda fram?" }, "externalId": { "message": "External Id" @@ -3420,7 +3420,7 @@ "description": "Noun: A special folder for holding deleted items that have not yet been permanently deleted" }, "searchTrash": { - "message": "Søk i boss" + "message": "Leita i papirkorga" }, "permanentlyDelete": { "message": "Permanently Delete" @@ -3707,7 +3707,7 @@ "message": "Expired" }, "searchSends": { - "message": "Search Sends", + "message": "Leita i Send-ar", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendProtectedPassword": { diff --git a/apps/web/src/locales/ro/messages.json b/apps/web/src/locales/ro/messages.json index 41603080ef2..74444e8ed85 100644 --- a/apps/web/src/locales/ro/messages.json +++ b/apps/web/src/locales/ro/messages.json @@ -3175,7 +3175,7 @@ "message": "Timp de expirare seif" }, "vaultTimeoutDesc": { - "message": "Alegeți când se va efectua acțiunea selectată la expirarea seifului." + "message": "Alegeți când seiful dvs. va efectua acțiunea de expirare a seifului." }, "oneMinute": { "message": "1 minut" @@ -4498,7 +4498,7 @@ "message": "Expirare seif personalizată" }, "vaultTimeoutToLarge": { - "message": "Timpul de expirare a seifului depășește restricția stabilită de organizația dvs." + "message": "Timpul de expirare al seifului depășește restricția stabilită de organizația dvs." }, "vaultCustomTimeoutMinimum": { "message": "Durata minimă de expirare personalizată este de 1 minut." diff --git a/apps/web/src/locales/zh_TW/messages.json b/apps/web/src/locales/zh_TW/messages.json index 02b8c47d376..3761fec001f 100644 --- a/apps/web/src/locales/zh_TW/messages.json +++ b/apps/web/src/locales/zh_TW/messages.json @@ -1165,7 +1165,7 @@ "message": "載入 gravatar.com 上的頭像圖片。" }, "enableFullWidth": { - "message": "顯示全寬度版面配置", + "message": "顯示全寬度佈局", "description": "Allows scaling the web vault UI's width" }, "enableFullWidthDesc": { From a2360aebd20d83fe4816a28963527c8c69522180 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 08:06:15 +0200 Subject: [PATCH 03/86] Autosync the updated translations (#3021) Co-authored-by: github-actions <> --- apps/browser/src/_locales/ar/messages.json | 2 +- apps/browser/src/_locales/az/messages.json | 2 +- apps/browser/src/_locales/be/messages.json | 2 +- apps/browser/src/_locales/bg/messages.json | 2 +- apps/browser/src/_locales/bn/messages.json | 2 +- apps/browser/src/_locales/bs/messages.json | 2 +- apps/browser/src/_locales/ca/messages.json | 4 +- apps/browser/src/_locales/cs/messages.json | 4 +- apps/browser/src/_locales/da/messages.json | 44 +-- apps/browser/src/_locales/de/messages.json | 4 +- apps/browser/src/_locales/el/messages.json | 4 +- apps/browser/src/_locales/en_GB/messages.json | 2 +- apps/browser/src/_locales/en_IN/messages.json | 2 +- apps/browser/src/_locales/es/messages.json | 4 +- apps/browser/src/_locales/et/messages.json | 12 +- apps/browser/src/_locales/eu/messages.json | 270 +++++++++--------- apps/browser/src/_locales/fa/messages.json | 4 +- apps/browser/src/_locales/fi/messages.json | 16 +- apps/browser/src/_locales/fil/messages.json | 2 +- apps/browser/src/_locales/fr/messages.json | 4 +- apps/browser/src/_locales/he/messages.json | 4 +- apps/browser/src/_locales/hi/messages.json | 2 +- apps/browser/src/_locales/hr/messages.json | 4 +- apps/browser/src/_locales/hu/messages.json | 2 +- apps/browser/src/_locales/id/messages.json | 4 +- apps/browser/src/_locales/it/messages.json | 2 +- apps/browser/src/_locales/ja/messages.json | 2 +- apps/browser/src/_locales/ka/messages.json | 2 +- apps/browser/src/_locales/km/messages.json | 2 +- apps/browser/src/_locales/kn/messages.json | 2 +- apps/browser/src/_locales/ko/messages.json | 4 +- apps/browser/src/_locales/lt/messages.json | 2 +- apps/browser/src/_locales/lv/messages.json | 4 +- apps/browser/src/_locales/ml/messages.json | 2 +- apps/browser/src/_locales/nb/messages.json | 4 +- apps/browser/src/_locales/nl/messages.json | 2 +- apps/browser/src/_locales/nn/messages.json | 2 +- apps/browser/src/_locales/pl/messages.json | 2 +- apps/browser/src/_locales/pt_BR/messages.json | 20 +- apps/browser/src/_locales/ro/messages.json | 4 +- apps/browser/src/_locales/ru/messages.json | 4 +- apps/browser/src/_locales/si/messages.json | 4 +- apps/browser/src/_locales/sk/messages.json | 2 +- apps/browser/src/_locales/sl/messages.json | 2 +- apps/browser/src/_locales/sr/messages.json | 4 +- apps/browser/src/_locales/sv/messages.json | 4 +- apps/browser/src/_locales/th/messages.json | 2 +- apps/browser/src/_locales/tr/messages.json | 2 +- apps/browser/src/_locales/uk/messages.json | 12 +- apps/browser/src/_locales/vi/messages.json | 2 +- apps/browser/src/_locales/zh_CN/messages.json | 6 +- apps/browser/src/_locales/zh_TW/messages.json | 32 +-- 52 files changed, 268 insertions(+), 268 deletions(-) diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index 8fcb5822a75..63464b4de8f 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index e5bf3c3de01..670bda360e1 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Anbar vaxt bitişi, təşkilatınız tərəfindən tənzimlənən məhdudiyyətləri aşır." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index 061897a2a9b..4c7613f8e34 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index 0ddfe08b3cf..5d3cb13a47a 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Времето за достъп до трезора Ви превишава ограничението, определено от организацията Ви." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json index 1e301072251..39330004f62 100644 --- a/apps/browser/src/_locales/bn/messages.json +++ b/apps/browser/src/_locales/bn/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json index 8fcb5822a75..63464b4de8f 100644 --- a/apps/browser/src/_locales/bs/messages.json +++ b/apps/browser/src/_locales/bs/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index 8b1860cd025..5e848178824 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "El temps d'espera de la caixa forta supera les restriccions establertes per la vostra organització." + "vaultTimeoutTooLarge": { + "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { "message": "L'exportació de la caixa forta està desactivada" diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json index 21376841a65..e04da60e48f 100644 --- a/apps/browser/src/_locales/cs/messages.json +++ b/apps/browser/src/_locales/cs/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "Časový limit vašeho trezoru překračuje omezení stanovená vaší organizací." + "vaultTimeoutTooLarge": { + "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { "message": "Export trezoru zakázán" diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index b852955131e..b9c9a167c5c 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -218,7 +218,7 @@ "message": "Bitwarden web-boks" }, "importItems": { - "message": "Importer elementer" + "message": "Importér elementer" }, "select": { "message": "Vælg" @@ -568,22 +568,22 @@ "description": "This is the folder for uncategorized items" }, "enableAddLoginNotification": { - "message": "Ask to add login" + "message": "Bed om at tilføje login" }, "addLoginNotificationDesc": { - "message": "\"Tilføj login notifikation\" spørger dig automatisk om du vil gemme nye logins til din boks, når du logger ind med dem for første gang." + "message": "Bed om at tilføje et element, hvis et ikke findes i din boks." }, "showCardsCurrentTab": { - "message": "Show cards on Tab page" + "message": "Vis kort på fanebladet" }, "showCardsCurrentTabDesc": { - "message": "List card items on the Tab page for easy auto-fill." + "message": "Vis kortelementer på fanebladet for nem auto-udfyldning." }, "showIdentitiesCurrentTab": { - "message": "Show identities on Tab page" + "message": "Vis identiteter på fanebladet" }, "showIdentitiesCurrentTabDesc": { - "message": "List identity items on the Tab page for easy auto-fill." + "message": "Vis identitetselementer på fanebladet for nem auto-udfyldning." }, "clearClipboard": { "message": "Ryd udklipsholder", @@ -600,10 +600,10 @@ "message": "Gem" }, "enableChangedPasswordNotification": { - "message": "Ask to update existing login" + "message": "Bed om at opdatere eksisterende login" }, "changedPasswordNotificationDesc": { - "message": "Ask to update a login's password when a change is detected on a website." + "message": "Bed om at opdatere et logins adgangskode, når der registreres en ændring på en hjemmeside." }, "notificationChangeDesc": { "message": "Vil du opdatere denne adgangskode i Bitwarden?" @@ -612,10 +612,10 @@ "message": "Opdatér" }, "enableContextMenuItem": { - "message": "Show context menu options" + "message": "Vis indstillinger i kontekstmenuen" }, "contextMenuItemDesc": { - "message": "Use a secondary click to access password generation and matching logins for the website. " + "message": "Brug et sekundært klik for at få adgang til adgangskodegenerering og matchende logins til hjemmesiden." }, "defaultUriMatchDetection": { "message": "Standard URI matchmetode", @@ -807,13 +807,13 @@ "message": "Opdatering færdig" }, "enableAutoTotpCopy": { - "message": "Copy TOTP automatically" + "message": "Kopiér TOTP automatisk" }, "disableAutoTotpCopyDesc": { - "message": "Hvis dit login har en autentificeringsnøgle tilknyttet, kopieres TOTP verifikationskoden automatisk til din udklipsholder når du auto-udfylder login." + "message": "Hvis et login har en autentificeringsnøgle, så kopiér TOTP-bekræftelseskoden til din udklipsholder, når du auto-udfylder login." }, "enableAutoBiometricsPrompt": { - "message": "Ask for biometrics on launch" + "message": "Bed om biometri ved start" }, "premiumRequired": { "message": "Premium påkrævet" @@ -951,10 +951,10 @@ "message": "Miljøets URLs er blevet gemt." }, "enableAutoFillOnPageLoad": { - "message": "Aktivér Auto-udfyld ved sideindlæsning" + "message": "Auto-udfyld ved sideindlæsning" }, "enableAutoFillOnPageLoadDesc": { - "message": "Hvis en login-formular er opdaget, så udfør automatisk en auto-udfyld når hjemmesiden indlæses." + "message": "Hvis der registreres en loginformular, så auto-udfyld, når websiden indlæses." }, "experimentalFeature": { "message": "Dette er i øjeblikket en eksperimentel funktion. Brug på egen risiko." @@ -963,7 +963,7 @@ "message": "Standardindstilling for autofyld for loginelementer" }, "defaultAutoFillOnPageLoadDesc": { - "message": "Når du har aktiveret auto-udfyldning ved sideindlæsning, kan du aktivere eller deaktivere funktionen for individuelle loginelementer. Dette er standardindstillingen for loginelementer, der ikke er konfigureret separat." + "message": "Du kan deaktivere auto-udfyld ved sideindlæsning for individuelle login-elementer fra elementets redigeringsvisning." }, "itemAutoFillOnPageLoad": { "message": "Auto-udfyld ved sideindlæsning (hvis aktiveret i Indstillinger)" @@ -1034,16 +1034,16 @@ "message": "Denne browser kan ikke behandle U2F-anmodninger i dette popup-vindue. Vil du åbne denne popup i et nyt vindue, så du kan logge ind ved hjælp af U2F?" }, "enableFavicon": { - "message": "Show website icons" + "message": "Vis webstedsikoner" }, "faviconDesc": { - "message": "Show a recognizable image next to each login." + "message": "Vis et genkendeligt billede ud for hvert login." }, "enableBadgeCounter": { - "message": "Show badge counter" + "message": "Vis badge-tæller" }, "badgeCounterDesc": { - "message": "Indicate how many logins you have for the current web page." + "message": "Vis hvor mange logins du har til den aktuelle webside." }, "cardholderName": { "message": "Kortindehaverens navn" @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Din boks-timeout overskrider de begrænsninger, der er fastsat af din organisation." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index deb394e192d..5c0064aad37 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -1253,7 +1253,7 @@ "description": "Domain name. Ex. website.com" }, "host": { - "message": "Server", + "message": "Host", "description": "A URL's host value. For example, the host of https://sub.domain.com:443 is 'sub.domain.com:443'." }, "exact": { @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Dein Tresor-Timeout überschreitet die von deinem Unternehmen festgelegten Beschränkungen." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index a0cb192ad7b..2acec9fb149 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "Το χρονικό όριο του vault σας υπερβαίνει τους περιορισμούς που έχει ορίσει ο οργανισμός σας." + "vaultTimeoutTooLarge": { + "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { "message": "Εξαγωγή vault Απενεργοποιημένη" diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json index 8e8dd1a1d27..f9f82616207 100644 --- a/apps/browser/src/_locales/en_GB/messages.json +++ b/apps/browser/src/_locales/en_GB/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organisation." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json index f5f8847096e..6afd6fd2082 100644 --- a/apps/browser/src/_locales/en_IN/messages.json +++ b/apps/browser/src/_locales/en_IN/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index 7c7be429c62..4fb5cc81e8c 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "El tiempo de espera de tu caja fuerte excede las restricciones establecidas por tu organización." + "vaultTimeoutTooLarge": { + "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { "message": "Exportación de caja fuerte desactivada" diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json index a1be1609b7b..9a14970b63a 100644 --- a/apps/browser/src/_locales/et/messages.json +++ b/apps/browser/src/_locales/et/messages.json @@ -574,16 +574,16 @@ "message": "\"Lisa konto andmed\" teavitus ilmub pärast esimest sisselogimist ning võimaldab kontoandmeid automaatselt Bitwardenisse lisada." }, "showCardsCurrentTab": { - "message": "Kuva kaardiandmed hoidla vaates" + "message": "Kuva \"Kaart\" vaates kaardiandmed" }, "showCardsCurrentTabDesc": { - "message": "Kuvab hoidla lehel kaardiandmed, et neid saaks kiiresti sisestada" + "message": "Kuvab \"Kaart\" vaates kaardiandmeid, et neid saaks kiiresti sisestada" }, "showIdentitiesCurrentTab": { - "message": "Kuva hoidla vaates identiteete" + "message": "Kuva \"Kaart\" vaates identiteete" }, "showIdentitiesCurrentTabDesc": { - "message": "List identity items on the Tab page for easy auto-fill." + "message": "Kuvab \"Kaart\" vaates identiteete, et neid saaks kiiresti sisestada" }, "clearClipboard": { "message": "Lõikelaua sisu kustutamine", @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "Valitud hoidla ajalõpp ei ole organisatsiooni poolt määratud reeglitega kooskõlas. " + "vaultTimeoutTooLarge": { + "message": "Valitud hoidla ajalõpp ei ole organisatsiooni poolt määratud reeglitega kooskõlas." }, "vaultExportDisabled": { "message": "Hoidla eksportimine on väljalülitatud" diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index cb7ecda5b7d..c76ebdf6c2d 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -11,7 +11,7 @@ "description": "Extension description" }, "loginOrCreateNewAccount": { - "message": "Identifika zaitez edo sortu kontu berri bat zure kutxa gotorrera sartzeko." + "message": "Saioa hasi edo sortu kontu berri bat zure kutxa gotorrera sartzeko." }, "createAccount": { "message": "Sortu kontua" @@ -89,7 +89,7 @@ "message": "Kopiatu segurtasun kodea (CVV)" }, "autoFill": { - "message": "Osatze automatikoa" + "message": "Auto-betetzea" }, "generatePasswordCopied": { "message": "Sortu pasahitza (kopiatuta)" @@ -98,7 +98,7 @@ "message": "Eremu pertsonalizatuaren izena kopiatu" }, "noMatchingLogins": { - "message": "Bat datozen sarrerarik gabe" + "message": "Bat datozen saio-hasierarik gabe" }, "unlockVaultMenu": { "message": "Desblokeatu kutxa gotorra" @@ -107,10 +107,10 @@ "message": "Hasi saioa zure kutxa gotorrean" }, "autoFillInfo": { - "message": "Ez dago automatikoki betetzeko sarrerarik nabigatzailearen uneko fitxan." + "message": "Ez dago auto-betetzeko saio-hasierarik nabigatzailearen uneko fitxan." }, "addLogin": { - "message": "Sarrera gehitu" + "message": "Saio-hasiera gehitu" }, "addItem": { "message": "Gehitu elementua" @@ -140,7 +140,7 @@ "message": "Egiaztatze-kodea" }, "confirmIdentity": { - "message": "Jarraitzeko, berretsi zure nortasuna." + "message": "Jarraitzeko, berretsi zure identitatea." }, "account": { "message": "Kontua" @@ -157,7 +157,7 @@ "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "twoStepLogin": { - "message": "Bi pausoko saio hasiera" + "message": "Bi urratseko egiaztatzea" }, "logOut": { "message": "Itxi saioa" @@ -212,7 +212,7 @@ "description": "Short for 'Password Generator'." }, "passGenInfo": { - "message": "Pasahitz sendoak eta bakarrak sortzen ditu automatikoki zure sarbideetarako." + "message": "Automatikoki pasahitz sendo eta bakarrak sortzen ditu zure saio-hasieratarako." }, "bitWebVault": { "message": "Bitwarden kutxa gotorra" @@ -339,10 +339,10 @@ "message": "Zure web nabigatzaileak ez du onartzen arbelean erraz kopiatzea. Eskuz kopiatu." }, "verifyIdentity": { - "message": "Zure nortasuna egiaztatu" + "message": "Zure identitatea egiaztatu" }, "yourVaultIsLocked": { - "message": "Zure kutxa gotorra blokeatuta dago. Egiaztatu zure nortasuna jarraitzeko." + "message": "Zure kutxa gotorra blokeatuta dago. Egiaztatu zure identitatea jarraitzeko." }, "unlock": { "message": "Desblokeatu" @@ -455,7 +455,7 @@ } }, "autofillError": { - "message": "Ezin izan da orri honetan hautatutako elementua automatikoki bete. Kopiatu eta itsatsi informazioa dagokion tokian." + "message": "Ezin izan da orri honetan hautatutako elementua auto-bete. Kopiatu eta itsatsi informazioa dagokion tokian." }, "loggedOut": { "message": "Saioa itxita" @@ -485,34 +485,34 @@ "message": "Aldatu pasahitz nagusia" }, "changeMasterPasswordConfirmation": { - "message": "You can change your master password on the bitwarden.com web vault. Do you want to visit the website now?" + "message": "Zure pasahitz nagusia alda dezakezu bitwarden.com webgunean. Orain joan nahi duzu webgunera?" }, "twoStepLoginConfirmation": { - "message": "Two-step login makes your account more secure by requiring you to verify your login with another device such as a security key, authenticator app, SMS, phone call, or email. Two-step login can be enabled on the bitwarden.com web vault. Do you want to visit the website now?" + "message": "Bi urratseko egiaztatzea dela eta, zure kontua seguruagoa da, beste aplikazio/gailu batekin saioa hastea eskatzen baitizu; adibidez, segurtasun kode, egiaztatze aplikazio, SMS, telefono dei edo posta elektroniko bidez. Bi urratseko egiaztatzea bitwarden.com webgunean aktibatu daiteke. Orain joan nahi duzu webgunera?" }, "editedFolder": { - "message": "Edited folder" + "message": "Karpeta editatuta" }, "deleteFolderConfirmation": { - "message": "Are you sure you want to delete this folder?" + "message": "Ziur al zaude karpeta hau ezabatu nahi duzula?" }, "deletedFolder": { - "message": "Deleted folder" + "message": "Karpeta ezabatuta" }, "gettingStartedTutorial": { - "message": "Getting Started Tutorial" + "message": "Lehen urratsetako tutoriala" }, "gettingStartedTutorialVideo": { - "message": "Watch our getting started tutorial to learn how to get the most out of the browser extension." + "message": "Ikusi lehen urratsetako tutoriala nabigatzailearen gehigarriari ahalik eta etekin handiena nola atera ikasteko." }, "syncingComplete": { - "message": "Syncing complete" + "message": "Sinkronizatu da" }, "syncingFailed": { - "message": "Syncing failed" + "message": "Sinkronizazioak huts egin du" }, "passwordCopied": { - "message": "Password copied" + "message": "Pasahitza kopiatuta" }, "uri": { "message": "URI" @@ -528,162 +528,162 @@ } }, "newUri": { - "message": "New URI" + "message": "IRI berria" }, "addedItem": { - "message": "Added item" + "message": "Elementua gehituta" }, "editedItem": { - "message": "Edited item" + "message": "Elementua editatuta" }, "deleteItemConfirmation": { - "message": "Do you really want to send to the trash?" + "message": "Ziur zaude elementu hau zakarrontzira bidali nahi duzula?" }, "deletedItem": { - "message": "Sent item to trash" + "message": "Elementua zakarrontzira bidalia" }, "overwritePassword": { - "message": "Overwrite Password" + "message": "Berridatzi pasahitza" }, "overwritePasswordConfirmation": { - "message": "Are you sure you want to overwrite the current password?" + "message": "Ziur al zaude pasahitza berridatzi nahi duzula?" }, "overwriteUsername": { - "message": "Overwrite Username" + "message": "Erabiltzaile-izena berridatzi" }, "overwriteUsernameConfirmation": { - "message": "Are you sure you want to overwrite the current username?" + "message": "Ziur al zaude erabiltzaile-izena berridatzi nahi duzula?" }, "searchFolder": { - "message": "Search folder" + "message": "Bilatu karpeta" }, "searchCollection": { - "message": "Search collection" + "message": "Bilatu bilduma" }, "searchType": { - "message": "Search type" + "message": "Bilaketa mota" }, "noneFolder": { - "message": "No Folder", + "message": "Karpetarik ez", "description": "This is the folder for uncategorized items" }, "enableAddLoginNotification": { - "message": "Ask to add login" + "message": "Galdetu saio-hasiera gehitzeko" }, "addLoginNotificationDesc": { - "message": "Ask to add an item if one isn't found in your vault." + "message": "Elementu bat gehitu nahi duzun galdetu, elementu hau zure kutxa gotorrean ez badago." }, "showCardsCurrentTab": { - "message": "Show cards on Tab page" + "message": "Erakutsi txartelak fitxa orrian" }, "showCardsCurrentTabDesc": { - "message": "List card items on the Tab page for easy auto-fill." + "message": "Erakutsi elementuen txartelak fitxa orrian, erraz auto-betetzeko." }, "showIdentitiesCurrentTab": { - "message": "Show identities on Tab page" + "message": "Erakutsi identitateak fitxa orrian" }, "showIdentitiesCurrentTabDesc": { - "message": "List identity items on the Tab page for easy auto-fill." + "message": "Erakutsi identitateak fitxa orrian, erraz auto-betetzeko." }, "clearClipboard": { - "message": "Clear clipboard", + "message": "Hustu arbela", "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "clearClipboardDesc": { - "message": "Automatically clear copied values from your clipboard.", + "message": "Ezabatu automatikoki arbelean kopiatutako balioak.", "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "notificationAddDesc": { - "message": "Should Bitwarden remember this password for you?" + "message": "Bitwardenek pasahitz hau gogoratu beharko lizuke?" }, "notificationAddSave": { - "message": "Save" + "message": "Gorde" }, "enableChangedPasswordNotification": { - "message": "Ask to update existing login" + "message": "Galdetu uneko saio-hasiera eguneratzeko" }, "changedPasswordNotificationDesc": { - "message": "Ask to update a login's password when a change is detected on a website." + "message": "Galdetu saio-hasiera baten pasahitza eguneratzeko, webgune batean aldaketaren bat atzematen denean." }, "notificationChangeDesc": { - "message": "Do you want to update this password in Bitwarden?" + "message": "Bitwardenen pasahitz hau eguneratu nahi duzu?" }, "notificationChangeSave": { - "message": "Update" + "message": "Eguneratu" }, "enableContextMenuItem": { - "message": "Show context menu options" + "message": "Erakutsi laster-menuko aukerak" }, "contextMenuItemDesc": { - "message": "Use a secondary click to access password generation and matching logins for the website. " + "message": "Erabili bigarren mailako klika webgunerako pasahitzak eta saio-hasierak sortzeko." }, "defaultUriMatchDetection": { - "message": "Default URI match detection", + "message": "Lehenetsitako detekzioa URI kointzidentziarako", "description": "Default URI match detection for auto-fill." }, "defaultUriMatchDetectionDesc": { - "message": "Choose the default way that URI match detection is handled for logins when performing actions such as auto-fill." + "message": "Hautatu auto-betetzea bezalako saio-hasierako ekintzetarako erabiliko den URI kointzidentzia detektatzeko modu lehenetsia." }, "theme": { - "message": "Theme" + "message": "Gaia" }, "themeDesc": { - "message": "Change the application's color theme." + "message": "Aldatu aplikaziorako kolore gaia." }, "dark": { - "message": "Dark", + "message": "Iluna", "description": "Dark color" }, "light": { - "message": "Light", + "message": "Argia", "description": "Light color" }, "solarizedDark": { - "message": "Solarized dark", + "message": "Solarized iluna", "description": "'Solarized' is a noun and the name of a color scheme. It should not be translated." }, "exportVault": { - "message": "Export vault" + "message": "Esportatu kutxa gotorra" }, "fileFormat": { - "message": "File Format" + "message": "Fitxategiaren formatua" }, "warning": { - "message": "WARNING", + "message": "KONTUZ", "description": "WARNING (should stay in capitalized letters if the language permits)" }, "confirmVaultExport": { - "message": "Confirm Vault Export" + "message": "Baieztatu kutxa gotorra esportatzea" }, "exportWarningDesc": { - "message": "This export contains your vault data in an unencrypted format. You should not store or send the exported file over unsecure channels (such as email). Delete it immediately after you are done using it." + "message": "Esportazio honek kutxa gotorraren datuak zifratu gabeko formatuan biltzen ditu. Ez zenuke gorde edo kanal ez-seguruetaik (posta elektronikoa, adibidez) bidali behar. Erabili eta berehala ezabatu." }, "encExportKeyWarningDesc": { - "message": "This export encrypts your data using your account's encryption key. If you ever rotate your account's encryption key you should export again since you will not be able to decrypt this export file." + "message": "Esportazio honek zure datuak enkriptatzen ditu zure kontuaren zifratze-kodea erabiliz. Inoiz zure kontuko zifratze-gakoa aldatuz gero, berriro esportatu beharko duzu, ezin izango baituzu fitxategi hori deszifratu." }, "encExportAccountWarningDesc": { - "message": "Account encryption keys are unique to each Bitwarden user account, so you can't import an encrypted export into a different account." + "message": "Kontua zifratzeko gakoak Bitwarden erabiltzaile bakoitzarentzako bakarrik dira; beraz, ezin da inportatu beste kontu batean zifratutako esportazio bat." }, "exportMasterPassword": { - "message": "Enter your master password to export your vault data." + "message": "Sartu pasahitz nagusia kutxa gotorreko datuak esportatzeko." }, "shared": { - "message": "Shared" + "message": "Partekatua" }, "learnOrg": { - "message": "Learn about organizations" + "message": "Erakundeak ezagutu" }, "learnOrgConfirmation": { - "message": "Bitwarden allows you to share your vault items with others by using an organization. Would you like to visit the bitwarden.com website to learn more?" + "message": "Bitwardek kutxa gotorreko elementuak beste batzuekin partekatzeko aukera ematen dizu erakunde bat erabiliz. Gehiago jakiteko, bitwarden.com webgunea bisitatu nahi duzu?" }, "moveToOrganization": { - "message": "Move to Organization" + "message": "Mugitu erakundera" }, "share": { - "message": "Share" + "message": "Partekatu" }, "movedItemToOrg": { - "message": "$ITEMNAME$ moved to $ORGNAME$", + "message": "$ITEMNAME$ $ORGNAME$-ra mugituta", "placeholders": { "itemname": { "content": "$1", @@ -696,94 +696,94 @@ } }, "moveToOrgDesc": { - "message": "Choose an organization that you wish to move this item to. Moving to an organization transfers ownership of the item to that organization. You will no longer be the direct owner of this item once it has been moved." + "message": "Aukeratu elementu hau zein erakundetara eraman nahi duzun. Erakunde batera pasatzeak elementuaren jabetza erakunde horretara transferitzen du. Zu ez zara elementu honen jabe zuzena izango mugitzen duzunean." }, "learnMore": { - "message": "Learn more" + "message": "Gehiago ikasi" }, "authenticatorKeyTotp": { - "message": "Authenticator Key (TOTP)" + "message": "Egiaztatze kodea (TOTP)" }, "verificationCodeTotp": { - "message": "Verification Code (TOTP)" + "message": "Egiaztatze kodea" }, "copyVerificationCode": { - "message": "Copy Verification Code" + "message": "Kopiatu egiaztatze kodea" }, "attachments": { - "message": "Attachments" + "message": "Eranskinak" }, "deleteAttachment": { - "message": "Delete attachment" + "message": "Ezabatu eranskinak" }, "deleteAttachmentConfirmation": { - "message": "Are you sure you want to delete this attachment?" + "message": "Ziur zaude eranskina ezabatu nahi duzula?" }, "deletedAttachment": { - "message": "Deleted attachment" + "message": "Eranskina ezabatuta" }, "newAttachment": { - "message": "Add New Attachment" + "message": "Gehitu eranskin berria" }, "noAttachments": { - "message": "No attachments." + "message": "Ez dago eranskinik" }, "attachmentSaved": { - "message": "The attachment has been saved." + "message": "Eranskina gorde da." }, "file": { - "message": "File" + "message": "Fitxategia" }, "selectFile": { - "message": "Select a file." + "message": "Hautatu fitxategia." }, "maxFileSize": { - "message": "Maximum file size is 500 MB." + "message": "Eranskinaren gehienezko tamaina 500MB." }, "featureUnavailable": { - "message": "Feature Unavailable" + "message": "Ezaugarria ez dago erabilgarri" }, "updateKey": { - "message": "You cannot use this feature until you update your encryption key." + "message": "Ezin duzu ezaugarri hau erabili enkriptazio kodea eguneratu arte." }, "premiumMembership": { - "message": "Premium membership" + "message": "Premium bazkidea" }, "premiumManage": { - "message": "Manage Membership" + "message": "Bazkidetza kudeatu" }, "premiumManageAlert": { - "message": "You can manage your membership on the bitwarden.com web vault. Do you want to visit the website now?" + "message": "Zure bazkidetza bitwarden.com webguneko kutxa gotorrean kudeatu dezakezu. Orain bisitatu nahi duzu webgunea?" }, "premiumRefresh": { - "message": "Refresh Membership" + "message": "Eguneratu bazkidetza" }, "premiumNotCurrentMember": { - "message": "You are not currently a premium member." + "message": "Orain ez zara premium bazkide." }, "premiumSignUpAndGet": { - "message": "Sign up for a premium membership and get:" + "message": "Erregistra zaitez premium bazkide gisa eta honakoa lortu:" }, "ppremiumSignUpStorage": { - "message": "1 GB encrypted storage for file attachments." + "message": "Eranskinentzako 1GB-eko enkriptatutako biltegia." }, "ppremiumSignUpTwoStep": { - "message": "Additional two-step login options such as YubiKey, FIDO U2F, and Duo." + "message": "YubiKey, FIDO U2F eta Duo bezalako saio-hasieratarako bi urratseko egiaztatze aukerak." }, "ppremiumSignUpReports": { - "message": "Password hygiene, account health, and data breach reports to keep your vault safe." + "message": "Pasahitzaren higienea, kontuaren egoera eta datu-bortxaketen txostenak, kutxa gotorra seguru mantentzeko." }, "ppremiumSignUpTotp": { - "message": "TOTP verification code (2FA) generator for logins in your vault." + "message": "TOTP (2FA) egiaztatze kode sortzailea gotor kutxako erregistroetarako." }, "ppremiumSignUpSupport": { - "message": "Priority customer support." + "message": "Lehentasunezko bezeroarentzako arreta." }, "ppremiumSignUpFuture": { - "message": "All future premium features. More coming soon!" + "message": "Etorkizuneko premium ezaugarri guztiak. Laister gehiago!" }, "premiumPurchase": { - "message": "Purchase Premium" + "message": "Premium erosi" }, "premiumPurchaseAlert": { "message": "You can purchase premium membership on the bitwarden.com web vault. Do you want to visit the website now?" @@ -810,7 +810,7 @@ "message": "Copy TOTP automatically" }, "disableAutoTotpCopyDesc": { - "message": "If a login has an authenticator key, copy the TOTP verification code to your clip-board when you auto-fill the login." + "message": "Saio-hasiera batek egiaztatze kodea badu, TOTP egiaztatze kodea arbelean automatikoki kopiatuko da saio-hasiera bat auto-betetzean." }, "enableAutoBiometricsPrompt": { "message": "Ask for biometrics on launch" @@ -849,13 +849,13 @@ "message": "Send verification code email again" }, "useAnotherTwoStepMethod": { - "message": "Use another two-step login method" + "message": "Erabili bi urratseko egiaztatzeko beste modu bat." }, "insertYubiKey": { - "message": "Insert your YubiKey into your computer's USB port, then touch its button." + "message": "Sartu zure YubiKey-a ordenagailuko USB portuan, ondoren, sakatu bere botoia." }, "insertU2f": { - "message": "Insert your security key into your computer's USB port. If it has a button, touch it." + "message": "Sartu zure segurtasun giltza ordenagailuaren USB portuan. Botoia badu, sakatu ezazu." }, "webAuthnNewTab": { "message": "To start the WebAuthn 2FA verification. Click the button below to open a new tab and follow the instructions provided in the new tab." @@ -867,16 +867,16 @@ "message": "Authenticate WebAuthn" }, "loginUnavailable": { - "message": "Login Unavailable" + "message": "Ez dago eskuragarri saio-hasierarik" }, "noTwoStepProviders": { - "message": "This account has two-step login enabled, however, none of the configured two-step providers are supported by this web browser." + "message": "Kontu honek bi urratseko egiaztatzea du gaituta, baina konfiguratutako bi urratseko egiaztatzea ez da web-nabigatzaile honekin bateragarria." }, "noTwoStepProviders2": { "message": "Please use a supported web browser (such as Chrome) and/or add additional providers that are better supported across web browsers (such as an authenticator app)." }, "twoStepOptions": { - "message": "Two-step Login Options" + "message": "Bi urratseko egiaztatzearen aukerak" }, "recoveryCodeDesc": { "message": "Lost access to all of your two-factor providers? Use your recovery code to disable all two-factor providers from your account." @@ -892,10 +892,10 @@ "description": "'Authy' and 'Google Authenticator' are product names and should not be translated." }, "yubiKeyTitle": { - "message": "YubiKey OTP Security Key" + "message": "YubiKey OTP segurtasun giltza" }, "yubiKeyDesc": { - "message": "Use a YubiKey to access your account. Works with YubiKey 4, 4 Nano, 4C, and NEO devices." + "message": "Erabili YubiKey zure kontuan sartzeko. YubiKey 4, 4 Nano, 4C eta NEO gailuekin dabil." }, "duoDesc": { "message": "Verify with Duo Security using the Duo Mobile app, SMS, phone call, or U2F security key.", @@ -951,31 +951,31 @@ "message": "The environment URLs have been saved." }, "enableAutoFillOnPageLoad": { - "message": "Auto-fill on page load" + "message": "Auto-bete orrialdea kargatzean" }, "enableAutoFillOnPageLoadDesc": { - "message": "If a login form is detected, auto-fill when the web page loads." + "message": "Saio-hasierako formulario bat detektatzen bada, auto-bete webgunea kargatzen denean." }, "experimentalFeature": { "message": "This is currently an experimental feature. Use at your own risk." }, "defaultAutoFillOnPageLoad": { - "message": "Default autofill setting for login items" + "message": "Saio-hasierako elementuetarako lehenetsitako auto-betetzearen konfigurazioa" }, "defaultAutoFillOnPageLoadDesc": { - "message": "You can turn off auto-fill on page load for individual login items from the item's Edit view." + "message": "Orrialdearen kargatze aukeretan auto-betetzea aktibatu ondoren, banakako saio-hasierak aktibatu edo desaktibatu ditzakezu." }, "itemAutoFillOnPageLoad": { - "message": "Auto-fill on page load (if enabled in Options)" + "message": "Auto-bete orrialdea kargatzean (ezarpenetan gaituta badago)" }, "autoFillOnPageLoadUseDefault": { "message": "Use default setting" }, "autoFillOnPageLoadYes": { - "message": "Auto-fill on page load" + "message": "Auto-bete orrialdea kargatzean" }, "autoFillOnPageLoadNo": { - "message": "Do not auto-fill on page load" + "message": "Ez auto-bete orrialdea kargatzean" }, "commandOpenPopup": { "message": "Open vault popup" @@ -984,7 +984,7 @@ "message": "Open vault in sidebar" }, "commandAutofillDesc": { - "message": "Auto-fill the last used login for the current website" + "message": "Uneko webgunerako erabilitako azken saio-hastea auto-bete" }, "commandGeneratePasswordDesc": { "message": "Generate and copy a new random password to the clipboard" @@ -1037,13 +1037,13 @@ "message": "Show website icons" }, "faviconDesc": { - "message": "Show a recognizable image next to each login." + "message": "Erakutsi irudi bat saio-hasiera bakoitzaren ondoan." }, "enableBadgeCounter": { "message": "Show badge counter" }, "badgeCounterDesc": { - "message": "Indicate how many logins you have for the current web page." + "message": "Adierazi zenbat saio-hasiera dituzun uneko webgunerako." }, "cardholderName": { "message": "Cardholder Name" @@ -1181,10 +1181,10 @@ "message": "Type" }, "typeLogin": { - "message": "Login" + "message": "Saio-hasiera" }, "typeLogins": { - "message": "Logins" + "message": "Saio-hasierak" }, "typeSecureNote": { "message": "Secure Note" @@ -1220,7 +1220,7 @@ "message": "Identities" }, "logins": { - "message": "Logins" + "message": "Saio-hasierak" }, "secureNotes": { "message": "Secure Notes" @@ -1267,11 +1267,11 @@ "description": "A programming term, also known as 'RegEx'." }, "matchDetection": { - "message": "Match Detection", + "message": "Detekzio modua", "description": "URI match detection for auto-fill." }, "defaultMatchDetection": { - "message": "Default match detection", + "message": "Lehenetsitako detekzio modua", "description": "Default URI match detection for auto-fill." }, "toggleOptions": { @@ -1424,13 +1424,13 @@ "message": "Timeout Action Confirmation" }, "autoFillAndSave": { - "message": "Auto-fill and Save" + "message": "Auto-bete eta gorde" }, "autoFillSuccessAndSavedUri": { - "message": "Auto-filled Item and Saved URI" + "message": "Elementua auto-betea eta URIa gordeta" }, "autoFillSuccess": { - "message": "Auto-filled Item" + "message": "Elementua auto-beteta" }, "setMasterPassword": { "message": "Set Master Password" @@ -1547,7 +1547,7 @@ "message": "Permission not provided" }, "nativeMessaginPermissionErrorDesc": { - "message": "Without permission to communicate with the Bitwarden Desktop Application we cannot provide biometrics in the browser extension. Please try again." + "message": "Mahaigaineko Bitwarden aplikazioarekin komunikatzeko baimenik gabe, ezin diogu datu biometrikorik eman nabigatzailearen gehigarriari. Mesedez, saiatu berriro." }, "nativeMessaginPermissionSidebarTitle": { "message": "Permission request error" @@ -1565,7 +1565,7 @@ "message": "Excluded domains" }, "excludedDomainsDesc": { - "message": "Bitwarden will not ask to save login details for these domains. You must refresh the page for changes to take effect." + "message": "Bitwardenek ez du eskatuko domeinu horietarako saio-hasierako xehetasunak gordetzea. Orrialdea eguneratu behar duzu aldaketek eragina izan dezaten." }, "excludedDomainsInvalidDomain": { "message": "$DOMAIN$ is not a valid domain", @@ -1747,10 +1747,10 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendLinuxChromiumFileWarning": { - "message": "In order to choose a file, open the extension in the sidebar (if possible) or pop out to a new window by clicking this banner." + "message": "Fitxategi bat aukeratzeko, ireki gehigarria alboko barran (ahal bada) edo atera leiho berri batera banner honetan klik eginez." }, "sendFirefoxFileWarning": { - "message": "In order to choose a file using Firefox, open the extension in the sidebar or pop out to a new window by clicking this banner." + "message": "Firefox erabiliz fitxategi bat aukeratzeko, ireki gehigarria alboko barratik edo ireki beste leiho bat banner hau sakatuz." }, "sendSafariFileWarning": { "message": "In order to choose a file using Safari, pop out to a new window by clicking this banner." @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { @@ -1960,9 +1960,9 @@ "message": "API Access Token" }, "apiKey": { - "message": "API Key" + "message": "API Kodea" }, "ssoKeyConnectorError": { - "message": "Key Connector error: make sure Key Connector is available and working correctly." + "message": "Errore bat gertatu da konektore giltzan: ziurtatu giltza konektorea erabilgarri dagoela eta behar bezala dabilela." } } diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index 15b7b803753..f244356988a 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "مهلت زمانی شما بیش از محدودیت های تعیین شده توسط سازمانتان است." + "vaultTimeoutTooLarge": { + "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { "message": "صادرات گاوصندوق غیرفعال شده است" diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index 310f9eca1cc..012a4f52b48 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -918,7 +918,7 @@ "message": "Todennuskoodit lähetetään sinulle sähköpostitse." }, "selfHostedEnvironment": { - "message": "Oma palvelinympäristö" + "message": "Itse ylläpidetty palvelinympäristö" }, "selfHostedEnvironmentFooter": { "message": "Määritä omassa palvelinympäristössäsi suoritettavan Bitwarden-asennuksen pääverkkotunnus." @@ -1386,7 +1386,7 @@ "message": "Yksi tai useampi organisaatiokäytäntö vaikuttaa generaattorisi asetuksiin." }, "vaultTimeoutAction": { - "message": "Holvin aikakatkaisun toiminto" + "message": "Holvin aikakatkaisutoiminto" }, "lock": { "message": "Lukitse", @@ -1418,10 +1418,10 @@ "message": "Kohde palautettu" }, "vaultTimeoutLogOutConfirmation": { - "message": "Uloskirjautuminen estää pääsyn holviisi ja vaatii ajan umpeuduttua todennuksen internet-yhteyden välityksellä. Haluatko varmasti käyttää tätä asetusta?" + "message": "Uloskirjautuminen estää pääsyn holviisi ja vaatii ajan umpeuduttua todennuksen Internet-yhteyden välityksellä. Haluatko varmasti käyttää asetusta?" }, "vaultTimeoutLogOutConfirmationTitle": { - "message": "Aikakatkaisun toiminnon vahvistus" + "message": "Aikakatkaisutoiminnon vahvistus" }, "autoFillAndSave": { "message": "Täytä automaattisesti ja tallenna" @@ -1834,7 +1834,7 @@ "message": "Minuuttia" }, "vaultTimeoutPolicyInEffect": { - "message": "Organisaatiosi käytännöt vaikuttavat holvisi aikakatkaisuun. Suurin sallittu viive on $HOURS$ tunti(a) ja $MINUTES$ minuutti(a)", + "message": "Organisaatiosi käytännöt vaikuttavat holvisi aikakatkaisuun. Suurin sallittu aika on $HOURS$ tunti(a) ja $MINUTES$ minuutti(a)", "placeholders": { "hours": { "content": "$1", @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "Holvisi aikakatkaisuviive ylittää organisaatiosi asettamat rajoitukset." + "vaultTimeoutTooLarge": { + "message": "Holvisi aikakatkaisu ylittää organisaatiosi asettamat rajoitukset." }, "vaultExportDisabled": { "message": "Holvin vienti on poistettu käytöstä" @@ -1862,7 +1862,7 @@ "message": "Yksilöllistä tunnistetta ei löytynyt." }, "convertOrganizationEncryptionDesc": { - "message": "$ORGANIZATION$ käyttää kertakirjautumista (SSO) oman avainpalvelimensa kanssa. Organisaation jäsenet eivät enää tarvitse pääsalasanaa kirjautumiseen.", + "message": "$ORGANIZATION$ käyttää kertakirjautumista (SSO) itse ylläpidetyllä avainpalvelimella. Organisaation jäsenet eivät enää tarvitse pääsalasanaa kirjautumiseen.", "placeholders": { "organization": { "content": "$1", diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json index 1eab3d718c0..779da3b0875 100644 --- a/apps/browser/src/_locales/fil/messages.json +++ b/apps/browser/src/_locales/fil/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json index 3cbccf45690..c45ca835d39 100644 --- a/apps/browser/src/_locales/fr/messages.json +++ b/apps/browser/src/_locales/fr/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "Le délai d'expiration de votre coffre dépasse les restrictions définies par votre organisation." + "vaultTimeoutTooLarge": { + "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { "message": "Export du coffre désactivé" diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json index d50dd3045d8..7449dc8a77d 100644 --- a/apps/browser/src/_locales/he/messages.json +++ b/apps/browser/src/_locales/he/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "Your vault timeout exceeds the restrictions set by your organization." + "vaultTimeoutTooLarge": { + "message": "הזמן הקצוב לכספת שלך חורג מהמגבלות שנקבעו על ידי הארגון שלך." }, "vaultExportDisabled": { "message": "Vault Export Disabled" diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json index f9cd4d1fa99..238d3c73232 100644 --- a/apps/browser/src/_locales/hi/messages.json +++ b/apps/browser/src/_locales/hi/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json index a85fd4a650e..b9648605c26 100644 --- a/apps/browser/src/_locales/hr/messages.json +++ b/apps/browser/src/_locales/hr/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "Vrijeme isteka premašuje ograničenje koju je postavila tvoja organizacija." + "vaultTimeoutTooLarge": { + "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { "message": "Izvoz trezora onemogućen" diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json index f74e2f4ae66..ac6940136af 100644 --- a/apps/browser/src/_locales/hu/messages.json +++ b/apps/browser/src/_locales/hu/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "A széf időkorlátja túllépi a szervezet által beállított korlátozást." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json index 3a46c3958df..e8e338c1674 100644 --- a/apps/browser/src/_locales/id/messages.json +++ b/apps/browser/src/_locales/id/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "Waktu tunggu brankas Anda melebihi batasan yang diatur organisasi Anda." + "vaultTimeoutTooLarge": { + "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { "message": "Ekspor Brankas Dinonaktifkan" diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index cb21c1a2a0b..ab6da9e057d 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Il timeout della tua cassaforte supera i limiti impostati dalla tua organizzazione." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index 2ee4916870a..f61b3f6b5ef 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "保管庫のタイムアウトが組織によって設定された制限を超えています。" }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json index 1469a4e6279..d45e8468364 100644 --- a/apps/browser/src/_locales/ka/messages.json +++ b/apps/browser/src/_locales/ka/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json index 8fcb5822a75..63464b4de8f 100644 --- a/apps/browser/src/_locales/km/messages.json +++ b/apps/browser/src/_locales/km/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json index ad29134d88d..cbf71f2f6cc 100644 --- a/apps/browser/src/_locales/kn/messages.json +++ b/apps/browser/src/_locales/kn/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index 0cc063e4d4d..6cf1a1331af 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "볼트 제한 시간이 조직에서 설정한 제한을 초과합니다." + "vaultTimeoutTooLarge": { + "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { "message": "보관함 내보내기 비활성화됨" diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json index c599f5c9bc9..b488de31869 100644 --- a/apps/browser/src/_locales/lt/messages.json +++ b/apps/browser/src/_locales/lt/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index 0a3e3b98a3d..bbf814b33db 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "Glabātavas noildze pāŗsniedz apvienības uzstādītos ierobežojumus." + "vaultTimeoutTooLarge": { + "message": "Glabātavas noildze pārsniedz apvienības uzstādītos ierobežojumus." }, "vaultExportDisabled": { "message": "Glabātavas izgūšana ir atspējota" diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json index 5f781ed6bdb..4829546df1f 100644 --- a/apps/browser/src/_locales/ml/messages.json +++ b/apps/browser/src/_locales/ml/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json index f4e1baf0efa..f2be7e9a821 100644 --- a/apps/browser/src/_locales/nb/messages.json +++ b/apps/browser/src/_locales/nb/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "Tidsavbruddet ditt for hvelvet overstiger begrensningene som er satt av organisasjonen din." + "vaultTimeoutTooLarge": { + "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { "message": "Hvelveksportering er skrudd av" diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json index a383527cad9..cc9e53fb97f 100644 --- a/apps/browser/src/_locales/nl/messages.json +++ b/apps/browser/src/_locales/nl/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Je kluis time-out is hoger dan het maximum van jouw organisatie." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json index 8fcb5822a75..63464b4de8f 100644 --- a/apps/browser/src/_locales/nn/messages.json +++ b/apps/browser/src/_locales/nn/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index 11c8d457606..893aee37c3f 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Czas blokowania sejfu przekracza limit określony przez organizację." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index 831ecfe1c43..d16802f3297 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -364,7 +364,7 @@ "message": "Senha mestra inválida" }, "vaultTimeout": { - "message": "Tempo limite do cofre." + "message": "Cofre - tempo esgotado" }, "lockNow": { "message": "Bloquear Agora" @@ -552,7 +552,7 @@ "message": "Sobrescrever Usuário" }, "overwriteUsernameConfirmation": { - "message": "Tem certeza que deseja substituir o usuário atual?" + "message": "Tem certeza que deseja sobrescrever o usuário atual?" }, "searchFolder": { "message": "Pesquisar pasta" @@ -574,16 +574,16 @@ "message": "A \"Notificação de Adicionar Login\" pede para salvar automaticamente novas logins para o seu cofre quando você inicia uma sessão em um site pela primeira vez." }, "showCardsCurrentTab": { - "message": "Mostrar cartões na aba atual" + "message": "Mostrar cartões em páginas com guias." }, "showCardsCurrentTabDesc": { - "message": "Listar itens do cartão na Aba para facilitar preenchimento automático." + "message": "Exibir itens de cartão em páginas com abas para simplificar o preenchimento automático" }, "showIdentitiesCurrentTab": { - "message": "Mostrar identidades na aba atual" + "message": "Exibir Identidades na Aba Atual" }, "showIdentitiesCurrentTabDesc": { - "message": "List identity items on the Tab page for easy auto-fill." + "message": "Liste os itens de identidade na aba atual para facilitar preenchimento automático." }, "clearClipboard": { "message": "Limpar Área de Transferência", @@ -600,10 +600,10 @@ "message": "Salvar" }, "enableChangedPasswordNotification": { - "message": "Ask to update existing login" + "message": "Pedir para atualizar os dados de login existentes" }, "changedPasswordNotificationDesc": { - "message": "Ask to update a login's password when a change is detected on a website." + "message": "Peça para atualizar a senha de login quando uma mudança for detectada em um site." }, "notificationChangeDesc": { "message": "Você quer atualizar esta senha no Bitwarden?" @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "O tempo limite do seu cofre excede as restrições definidas por sua organização." + "vaultTimeoutTooLarge": { + "message": "Seu tempo de espera no cofre excede as restrições estabelecidas por sua organização." }, "vaultExportDisabled": { "message": "Exportação de Cofre Desativada" diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json index a260f46af95..e14e0703904 100644 --- a/apps/browser/src/_locales/ro/messages.json +++ b/apps/browser/src/_locales/ro/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "Timpul de expirare a seifului depășește restricțiile stabilite de organizația dvs." + "vaultTimeoutTooLarge": { + "message": "Timpul de expirare al seifului depășește restricțiile stabilite de organizația dvs." }, "vaultExportDisabled": { "message": "Export de seif dezactivat" diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json index d507c95aa64..dc66b5c423b 100644 --- a/apps/browser/src/_locales/ru/messages.json +++ b/apps/browser/src/_locales/ru/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "Время ожидания превышает ограничения, установленные вашей организацией." + "vaultTimeoutTooLarge": { + "message": "Тайм-аут вашего хранилища превышает ограничения, установленные вашей организацией." }, "vaultExportDisabled": { "message": "Экспорт хранилища отключен" diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json index 5849355ecbf..f4b24172ce8 100644 --- a/apps/browser/src/_locales/si/messages.json +++ b/apps/browser/src/_locales/si/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "ඔබේ සුරක්ෂිතාගාරය කාලය ඔබේ සංවිධානය විසින් නියම කර ඇති සීමාවන් ඉක්මවා යයි." + "vaultTimeoutTooLarge": { + "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { "message": "ආබාධිත අපනයන සුරක්ෂිතාගාරය" diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json index 7afc581fdc1..687c49f807b 100644 --- a/apps/browser/src/_locales/sk/messages.json +++ b/apps/browser/src/_locales/sk/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Časový limit vášho trezora prekračuje obmedzenia nastavené vašou organizáciou." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index 814776b346a..de480a328f6 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index 40722a4da8e..99b83d09af2 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "Време истека вашег сефа је премашило дозвољена ограничења од стране ваше организације." + "vaultTimeoutTooLarge": { + "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { "message": "Извоз сефа онемогућен" diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index 3ea4caa0ed1..8ad84e58e77 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "Ditt valvs tid för timeout överskrider de begränsningar som fastställts av din organisation." + "vaultTimeoutTooLarge": { + "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { "message": "Valvexport inaktiverad" diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json index ebf4779b11a..814eac51b95 100644 --- a/apps/browser/src/_locales/th/messages.json +++ b/apps/browser/src/_locales/th/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index c44e99086c1..c5d38c8cacd 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Kasa zaman aşımınız, kuruluşunuz tarafından belirlenen kısıtlamaları aşıyor." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json index 13dda620af0..c976f2d3d80 100644 --- a/apps/browser/src/_locales/uk/messages.json +++ b/apps/browser/src/_locales/uk/messages.json @@ -643,7 +643,7 @@ "description": "'Solarized' is a noun and the name of a color scheme. It should not be translated." }, "exportVault": { - "message": "Експорт сховища" + "message": "Експортувати сховище" }, "fileFormat": { "message": "Формат файлу" @@ -810,7 +810,7 @@ "message": "Автоматично копіювати коди TOTP" }, "disableAutoTotpCopyDesc": { - "message": "Якщо ваш запис має вкладений ключ авторизації, код підтвердження TOTP автоматично копіюється до буфера обміну щоразу при автозаповненні." + "message": "Якщо запис має ключ авторизації, копіювати код підтвердження TOTP до буфера обміну під час автозаповнення." }, "enableAutoBiometricsPrompt": { "message": "Запитувати біометрію під час запуску" @@ -954,7 +954,7 @@ "message": "Автозаповнення на сторінці" }, "enableAutoFillOnPageLoadDesc": { - "message": "При виявленні форми входу виконувати автоматичне її заповнення під час завантаження сторінки." + "message": "Якщо виявлено форму входу, автоматично заповнювати її під час завантаження вебсторінки." }, "experimentalFeature": { "message": "Це експериментальна функція. При її використанні ви берете ризик на себе." @@ -963,10 +963,10 @@ "message": "Типове налаштування автозаповнення для записів входу" }, "defaultAutoFillOnPageLoadDesc": { - "message": "Після увімкнення автозаповнення на сторінці ви можете увімкнути чи вимкнути цю функцію для окремих записів входу. Це налаштування є типовим для записів входу, які не мають окремого налаштування." + "message": "Ви можете вимкнути цю функцію для окремих записів входу в меню запису \"Змінити\"." }, "itemAutoFillOnPageLoad": { - "message": "Автозаповнення на сторінці (якщо не увімкнено в налаштуваннях)" + "message": "Автозаповнення на сторінці (якщо увімкнено в налаштуваннях)" }, "autoFillOnPageLoadUseDefault": { "message": "Типове налаштування" @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Час очікування сховища перевищує обмеження, встановлені вашою організацією." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json index dec923fb217..5878d809866 100644 --- a/apps/browser/src/_locales/vi/messages.json +++ b/apps/browser/src/_locales/vi/messages.json @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index 41217fd6287..f5c13b3adfc 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -571,7 +571,7 @@ "message": "要求添加登录" }, "addLoginNotificationDesc": { - "message": "在密码库中找不到项目时询问添加一个项目。" + "message": "在密码库中找不到匹配项目时询问添加一个。" }, "showCardsCurrentTab": { "message": "在标签页上显示支付卡" @@ -954,7 +954,7 @@ "message": "页面加载时自动填充" }, "enableAutoFillOnPageLoadDesc": { - "message": "网页加载时如果检测到登录表单,则自动填充。" + "message": "网页加载时如果检测到登录表单,则执行自动填充。" }, "experimentalFeature": { "message": "目前这是一项实验功能。使用需自担风险。" @@ -1846,7 +1846,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "您的密码库超时时间超出了组织设置的限制。" }, "vaultExportDisabled": { diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json index 257394a02c7..384a62cda2c 100644 --- a/apps/browser/src/_locales/zh_TW/messages.json +++ b/apps/browser/src/_locales/zh_TW/messages.json @@ -568,22 +568,22 @@ "description": "This is the folder for uncategorized items" }, "enableAddLoginNotification": { - "message": "Ask to add login" + "message": "詢問新增登入資料" }, "addLoginNotificationDesc": { - "message": "當您首次登入時,「新增登入資料通知」會自動提醒您在密碼庫中新增登入資料。" + "message": "在密碼庫中找不到相符的項目時詢問是否新增項目。" }, "showCardsCurrentTab": { "message": "於分頁頁面顯示支付卡" }, "showCardsCurrentTabDesc": { - "message": "List card items on the Tab page for easy auto-fill." + "message": "於分頁頁面顯示支付卡以便於自動填入。" }, "showIdentitiesCurrentTab": { "message": "於分頁頁面顯示身分" }, "showIdentitiesCurrentTabDesc": { - "message": "List identity items on the Tab page for easy auto-fill." + "message": "於分頁頁面顯示身分以便於自動填入。" }, "clearClipboard": { "message": "清除剪貼簿", @@ -600,10 +600,10 @@ "message": "儲存" }, "enableChangedPasswordNotification": { - "message": "Ask to update existing login" + "message": "詢問更新現有的登入資料" }, "changedPasswordNotificationDesc": { - "message": "Ask to update a login's password when a change is detected on a website." + "message": "偵測到網站密碼變更時,詢問是否更新登入資料密碼。" }, "notificationChangeDesc": { "message": "是否要在 Bitwarden 中更新此密碼?" @@ -612,10 +612,10 @@ "message": "更新" }, "enableContextMenuItem": { - "message": "Show context menu options" + "message": "顯示內容選單選項" }, "contextMenuItemDesc": { - "message": "Use a secondary click to access password generation and matching logins for the website. " + "message": "使用輔助點選(右鍵選單)來存取密碼產生器和登入目前分頁中的網站。" }, "defaultUriMatchDetection": { "message": "預設的 URI 一致性偵測", @@ -639,7 +639,7 @@ "description": "Light color" }, "solarizedDark": { - "message": "Solarized Dark", + "message": "Solarized Dark 主題", "description": "'Solarized' is a noun and the name of a color scheme. It should not be translated." }, "exportVault": { @@ -813,7 +813,7 @@ "message": "若登入資料已包含驗證器金鑰,在自動填入此登入資料時,TOTP 驗證碼將複製至您的剪貼簿。" }, "enableAutoBiometricsPrompt": { - "message": "Ask for biometrics on launch" + "message": "啟動時要求生物特徵辨識" }, "premiumRequired": { "message": "需要進階會員資格" @@ -954,7 +954,7 @@ "message": "頁面載入時自動填入" }, "enableAutoFillOnPageLoadDesc": { - "message": "如果網頁載入時偵測到登入表單,則自動執行表單填入。" + "message": "網頁載入時如果偵測到登入表單,則執行自動填入。" }, "experimentalFeature": { "message": "這目前是一項實驗性功能。要使用需自行承擔風險。" @@ -963,7 +963,7 @@ "message": "登入項目的預設自動填入設定" }, "defaultAutoFillOnPageLoadDesc": { - "message": "啟用頁面載入時自動填入後,您可以為單個登入項目啟用或停用此功能。這是未單獨設定的登入項目的預設設定。" + "message": "您可以從項目的編輯檢視中為單個登入項目關閉頁面載入時自動填入。" }, "itemAutoFillOnPageLoad": { "message": "頁面載入時自動填入(如果選項中已啟用)" @@ -1040,10 +1040,10 @@ "message": "在每個登入資料旁顯示一個可辨識的圖片。" }, "enableBadgeCounter": { - "message": "Show badge counter" + "message": "顯示圖示計數器" }, "badgeCounterDesc": { - "message": "Indicate how many logins you have for the current web page." + "message": "顯示可用於目前網頁的登入資料數量。" }, "cardholderName": { "message": "持卡人姓名" @@ -1846,8 +1846,8 @@ } } }, - "vaultTimeoutToLarge": { - "message": "您的密碼庫逾時時間超過組織限制。" + "vaultTimeoutTooLarge": { + "message": "您的密碼庫逾時時間超過組織設定的限制。" }, "vaultExportDisabled": { "message": "密碼庫匯出已停用" From 6bcde3a84cb216ad9b5f4e4f807e35300b6233c2 Mon Sep 17 00:00:00 2001 From: Joseph Flinn <58369717+joseph-flinn@users.noreply.github.com> Date: Fri, 1 Jul 2022 08:44:20 -0700 Subject: [PATCH 04/86] Fix Choco Release & Update Dry Run logic (#3017) * disabling snap for testing * adding in environment logging * adding in some Dry Run logic * adding more protected dry run logic * skipping long running steps for testing purposes * testing out windowws-2022 runner * Trying a different GitHub Action expression syntax * manually disabling jobs because I don't have time to figure out GitHub's weird syntax * updating nuget on windows-2019 * disabling the nuget version 6 * trying more GitHub Action syntax * disabling choco for testing * running test on Dry Run release * changing the double quotes to single quotes inside the GitHub Action expression * removing testing code * updating more dry run logic * reverting a branch name change --- .github/workflows/release-browser.yml | 16 +++++++++++++++- .github/workflows/release-cli.yml | 12 +++++++++++- .github/workflows/release-desktop.yml | 19 ++++++++++++++++++- .github/workflows/release-web.yml | 12 ++++++++++++ 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release-browser.yml b/.github/workflows/release-browser.yml index b18002f1d46..da8780599c9 100644 --- a/.github/workflows/release-browser.yml +++ b/.github/workflows/release-browser.yml @@ -90,7 +90,8 @@ jobs: - setup - locales-test steps: - - name: Download latest RC build artifacts + - name: Download latest Release build artifacts + if: ${{ github.event.inputs.release_type != 'Dry Run' }} uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8 with: workflow: build-browser.yml @@ -102,6 +103,19 @@ jobs: dist-firefox-*.zip, dist-edge-*.zip' + - name: Download latest master build artifacts + if: ${{ github.event.inputs.release_type == 'Dry Run' }} + uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8 + with: + workflow: build-browser.yml + workflow_conclusion: success + branch: master + artifacts: 'browser-source-*.zip, + dist-chrome-*.zip, + dist-opera-*.zip, + dist-firefox-*.zip, + dist-edge-*.zip' + - name: Rename build artifacts env: PACKAGE_VERSION: ${{ needs.setup.outputs.release-version }} diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml index fe9b02f2a75..de2b279a25e 100644 --- a/.github/workflows/release-cli.yml +++ b/.github/workflows/release-cli.yml @@ -48,7 +48,8 @@ jobs: monorepo: true monorepo-project: cli - - name: Download all artifacts + - name: Download all Release artifacts + if: ${{ github.event.inputs.release_type != 'Dry Run' }} uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8 with: workflow: build-cli.yml @@ -56,6 +57,15 @@ jobs: workflow_conclusion: success branch: ${{ github.ref_name }} + - name: Download all artifacts + if: ${{ github.event.inputs.release_type == 'Dry Run' }} + uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8 + with: + workflow: build-cli.yml + path: apps/cli + workflow_conclusion: success + branch: master + - name: Create release if: ${{ github.event.inputs.release_type != 'Dry Run' }} uses: ncipollo/release-action@58ae73b360456532aafd58ee170c045abbeaee37 # v1.10.0 diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml index 189f6a59578..67bcab7a779 100644 --- a/.github/workflows/release-desktop.yml +++ b/.github/workflows/release-desktop.yml @@ -78,6 +78,7 @@ jobs: secrets: "aws-electron-access-id, aws-electron-access-key, aws-electron-bucket-name" - name: Download all artifacts + if: ${{ github.event.inputs.release_type != 'Dry Run' }} uses: bitwarden/gh-actions/download-artifacts@23433be15ed6fd046ce12b6889c5184a8d9c8783 with: workflow: build-desktop.yml @@ -85,6 +86,15 @@ jobs: branch: ${{ github.ref_name }} path: apps/desktop/artifacts + - name: Download all artifacts + if: ${{ github.event.inputs.release_type == 'Dry Run' }} + uses: bitwarden/gh-actions/download-artifacts@23433be15ed6fd046ce12b6889c5184a8d9c8783 + with: + workflow: build-desktop.yml + workflow_conclusion: success + branch: master + path: apps/desktop/artifacts + - name: Rename .pkg to .pkg.archive env: PKG_VERSION: ${{ steps.version.outputs.version }} @@ -92,6 +102,7 @@ jobs: run: mv Bitwarden-${{ env.PKG_VERSION }}-universal.pkg Bitwarden-${{ env.PKG_VERSION }}-universal.pkg.archive - name: Publish artifacts to S3 + if: ${{ github.event.inputs.release_type != 'Dry Run' }} env: AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.aws-electron-access-id }} AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.aws-electron-access-key }} @@ -106,7 +117,7 @@ jobs: - name: Create release uses: ncipollo/release-action@95215a3cb6e6a1908b3c44e00b4fdb15548b1e09 # v2.8.5 - if: ${{ steps.release-channel.outputs.channel }} == "latest" + if: ${{ steps.release-channel.outputs.channel == 'latest' && github.event.inputs.release_type != 'Dry Run' }} env: PKG_VERSION: ${{ steps.version.outputs.version }} RELEASE_CHANNEL: ${{ steps.release-channel.outputs.channel }} @@ -200,6 +211,11 @@ jobs: - name: Checkout Repo uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # v2.3.4 + - name: Print Environment + run: | + dotnet --version + dotnet nuget --version + - name: Login to Azure uses: Azure/login@24848bc889cfc0a8313c2b3e378ac0d625b9bc16 with: @@ -213,6 +229,7 @@ jobs: secrets: "cli-choco-api-key" - name: Setup Chocolatey + shell: pwsh run: choco apikey --key $env:CHOCO_API_KEY --source https://push.chocolatey.org/ env: CHOCO_API_KEY: ${{ steps.retrieve-secrets.outputs.cli-choco-api-key }} diff --git a/.github/workflows/release-web.yml b/.github/workflows/release-web.yml index 3dd5971c90e..33b711306b1 100644 --- a/.github/workflows/release-web.yml +++ b/.github/workflows/release-web.yml @@ -222,6 +222,7 @@ jobs: - cfpages-deploy steps: - name: Download latest build artifacts + if: ${{ github.event.inputs.release_type != 'Dry Run' }} uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8 with: workflow: build-web.yml @@ -231,6 +232,17 @@ jobs: artifacts: "web-*-selfhosted-COMMERCIAL.zip, web-*-selfhosted-open-source.zip" + - name: Download latest build artifacts + if: ${{ github.event.inputs.release_type == 'Dry Run' }} + uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8 + with: + workflow: build-web.yml + path: apps/web/artifacts + workflow_conclusion: success + branch: master + artifacts: "web-*-selfhosted-COMMERCIAL.zip, + web-*-selfhosted-open-source.zip" + - name: Rename assets working-directory: apps/web/artifacts run: | From c1ace45915c8d33d70fc738bd5b5e95e4123b5db Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Mon, 4 Jul 2022 11:00:13 +0200 Subject: [PATCH 05/86] [SM-71] Update all badges to use component library (#2999) --- .../manage/entity-users.component.html | 10 ++-- .../manage/people.component.html | 18 +++--- .../manage/policies.component.html | 2 +- .../manage/user-add-edit.component.html | 4 +- .../organization-subscription.component.html | 2 +- .../organizations/tools/tools.component.html | 2 +- apps/web/src/app/oss.module.ts | 8 ++- .../exposed-passwords-report.component.html | 2 +- .../inactive-two-factor-report.component.html | 2 +- .../reused-passwords-report.component.html | 2 +- .../weak-passwords-report.component.html | 2 +- .../settings/emergency-access.component.html | 56 ++++++++++--------- .../web/src/app/vault/add-edit.component.html | 4 +- apps/web/src/scss/buttons.scss | 49 ---------------- apps/web/src/scss/styles.scss | 17 +++--- .../providers/manage/people.component.html | 12 ++-- 16 files changed, 74 insertions(+), 118 deletions(-) diff --git a/apps/web/src/app/modules/organizations/manage/entity-users.component.html b/apps/web/src/app/modules/organizations/manage/entity-users.component.html index f4c157a9413..92f95bae3b3 100644 --- a/apps/web/src/app/modules/organizations/manage/entity-users.component.html +++ b/apps/web/src/app/modules/organizations/manage/entity-users.component.html @@ -64,9 +64,7 @@ (click)="filterSelected(true)" > {{ "selected" | i18n }} - {{ - selectedCount - }} + {{ selectedCount }} @@ -115,12 +113,14 @@ {{ u.email }} {{ "invited" | i18n }} {{ "accepted" | i18n }} diff --git a/apps/web/src/app/organizations/manage/people.component.html b/apps/web/src/app/organizations/manage/people.component.html index 902dd85d6e4..a20a95d20aa 100644 --- a/apps/web/src/app/organizations/manage/people.component.html +++ b/apps/web/src/app/organizations/manage/people.component.html @@ -9,7 +9,7 @@ (click)="filter(null)" > {{ "all" | i18n }} - {{ allCount }} + {{ allCount }}
@@ -156,13 +152,13 @@ {{ u.email }} - {{ + {{ "invited" | i18n }} - {{ + {{ "accepted" | i18n }} - {{ + {{ "deactivated" | i18n }} {{ u.name }} diff --git a/apps/web/src/app/organizations/manage/policies.component.html b/apps/web/src/app/organizations/manage/policies.component.html index 0f8b890c8f6..f1941d097d5 100644 --- a/apps/web/src/app/organizations/manage/policies.component.html +++ b/apps/web/src/app/organizations/manage/policies.component.html @@ -14,7 +14,7 @@ {{ p.name | i18n }} - {{ + {{ "enabled" | i18n }} {{ p.description | i18n }} diff --git a/apps/web/src/app/organizations/manage/user-add-edit.component.html b/apps/web/src/app/organizations/manage/user-add-edit.component.html index a11aeda15b6..50a1a8bf1eb 100644 --- a/apps/web/src/app/organizations/manage/user-add-edit.component.html +++ b/apps/web/src/app/organizations/manage/user-add-edit.component.html @@ -11,7 +11,9 @@
@@ -137,10 +135,10 @@ {{ u.email }} - {{ + {{ "invited" | i18n }} - {{ + {{ "accepted" | i18n }} {{ u.name }} From a024a066c2025dad7b7236e96b067d3115709764 Mon Sep 17 00:00:00 2001 From: Joseph Flinn <58369717+joseph-flinn@users.noreply.github.com> Date: Tue, 5 Jul 2022 07:42:02 -0700 Subject: [PATCH 06/86] Fixing the choco and the npm releases (#3034) --- .github/workflows/release-cli.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml index de2b279a25e..3b4f8e9a90c 100644 --- a/.github/workflows/release-cli.yml +++ b/.github/workflows/release-cli.yml @@ -167,7 +167,7 @@ jobs: uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8 with: workflow: build-cli.yml - path: apps/cli + path: apps/cli/dist workflow_conclusion: success branch: ${{ github.ref_name }} artifacts: bitwarden-cli.${{ env._PKG_VERSION }}.nupkg @@ -190,6 +190,18 @@ jobs: - name: Checkout repo uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 + - name: Login to Azure + uses: Azure/login@24848bc889cfc0a8313c2b3e378ac0d625b9bc16 + with: + creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }} + + - name: Retrieve secrets + id: retrieve-secrets + uses: Azure/get-keyvault-secrets@b5c723b9ac7870c022b8c35befe620b7009b336f + with: + keyvault: "bitwarden-prod-kv" + secrets: "cli-npm-api-key" + - name: Download artifacts uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8 with: @@ -202,7 +214,7 @@ jobs: - name: Setup NPM run: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc env: - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + NPM_TOKEN: ${{ steps.retrieve-secrets.outputs.cli-npm-api-key }} - name: Install Husky run: npm install -g husky From 9d1312f2afba492bd062509cfa668c221b397b09 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 08:47:28 -0700 Subject: [PATCH 07/86] Bumped desktop version to 2022.6.1 (#3033) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- apps/desktop/src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/src/package.json b/apps/desktop/src/package.json index 18684e027c2..7108dae48c9 100644 --- a/apps/desktop/src/package.json +++ b/apps/desktop/src/package.json @@ -2,7 +2,7 @@ "name": "@bitwarden/desktop", "productName": "Bitwarden", "description": "A secure and free password manager for all of your devices.", - "version": "2022.6.0", + "version": "2022.6.1", "author": "Bitwarden Inc. (https://bitwarden.com)", "homepage": "https://bitwarden.com", "license": "GPL-3.0", From fb70d8a2d3a7492272a916444d6775800666bc3b Mon Sep 17 00:00:00 2001 From: Robyn MacCallum Date: Tue, 5 Jul 2022 15:25:14 -0400 Subject: [PATCH 08/86] Merge Feature/trial initiation (#3036) * [SG-74] Trial Initiation Component with Vertical Stepper (#2913) * Vertical stepper PoC * Convert stepper css to tailwind * trial component start * trial component params * tailwind-ify header * Support teams, enterprise, and families layout param and more layout ui work * Some more theming fixes * Rename TrialModule to TrialInitiationModule * Stepper fixes, plus more functionality demo * Cleanup * layout params and placeholders * Only allow trial route to be hit if not logged in * fix typo * Use background-alt2 color for header * Move vertical stepper out of trial-initiation * Create components for the different plan types * Remove width on steps * Remove content projection for label * Tailwind style fixes * Extract step content into a component * Remove layout param for now * Remove step tags * remove pointer classes from step button * Remove most tailwind important designations * Update apps/web/src/app/modules/vertical-stepper/vertical-step.component.ts Co-authored-by: Oscar Hinton * Tailwind and layout fixes * Remove container * lint & prettier fixes * Remove extra CdkStep declaration * Styles fixes * Style logo directly * Remove 0 margin on image * Fix tiling and responsiveness * Minor padding fixes for org pages * Update apps/web/src/app/modules/trial-initiation/trial-initiation.component.html Co-authored-by: Oscar Hinton * prettier fix Co-authored-by: Oscar Hinton * [SG-65] Reusable Registration Form (#2946) * created reusable registration form * fixed conflicts * replicated reactive form changes in other clients * removed comments * client template cleanup * client template cleanup * removed comments in template file * changed to component suffix * switched show password to use component * comments resolution * comments resolution * added toast disable functionality * removed unused locale * mode custom input validator generic * fixed button * fixed linter * removed horizontal rule * switched to button component Co-authored-by: Oscar Hinton Co-authored-by: gbubemismith --- apps/browser/src/_locales/en/messages.json | 9 +- .../popup/accounts/register.component.html | 35 +--- .../src/popup/accounts/register.component.ts | 6 + .../src/app/accounts/register.component.html | 40 ++--- .../src/app/accounts/register.component.ts | 6 + apps/desktop/src/locales/en/messages.json | 9 +- .../src/app/accounts/register.component.html | 158 +--------------- .../src/app/accounts/register.component.ts | 27 +-- .../app/modules/loose-components.module.ts | 12 +- .../register-form.component.html | 121 +++++++++++++ .../register-form/register-form.component.ts | 87 +++++++++ .../register-form/register-form.module.ts | 12 ++ apps/web/src/app/modules/shared.module.ts | 9 +- .../enterprise-content.component.html | 11 ++ .../enterprise-content.component.ts | 7 + .../families-content.component.html | 13 ++ .../families-content.component.ts | 7 + .../teams-content.component.html | 10 ++ .../teams-content.component.ts | 7 + .../trial-initiation.component.html | 58 ++++++ .../trial-initiation.component.ts | 25 +++ .../trial-initiation.module.ts | 24 +++ .../vertical-step-content.component.html | 45 +++++ .../vertical-step-content.component.ts | 20 +++ .../vertical-step.component.html | 7 + .../vertical-step.component.ts | 11 ++ .../vertical-stepper.component.html | 22 +++ .../vertical-stepper.component.ts | 29 +++ .../vertical-stepper.module.ts | 14 ++ apps/web/src/app/oss-routing.module.ts | 7 + apps/web/src/app/oss.module.ts | 3 + apps/web/src/locales/en/messages.json | 39 +++- .../src/components/register.component.ts | 169 ++++++++++-------- .../src/services/jslib-services.module.ts | 6 + .../validators/fieldsInputCheck.validator.ts | 37 ++++ .../formValidationErrors.service.ts | 13 ++ .../services/formValidationErrors.service.ts | 31 ++++ .../src/form-field/error.component.ts | 2 + 38 files changed, 834 insertions(+), 314 deletions(-) create mode 100644 apps/web/src/app/modules/register-form/register-form.component.html create mode 100644 apps/web/src/app/modules/register-form/register-form.component.ts create mode 100644 apps/web/src/app/modules/register-form/register-form.module.ts create mode 100644 apps/web/src/app/modules/trial-initiation/enterprise-content.component.html create mode 100644 apps/web/src/app/modules/trial-initiation/enterprise-content.component.ts create mode 100644 apps/web/src/app/modules/trial-initiation/families-content.component.html create mode 100644 apps/web/src/app/modules/trial-initiation/families-content.component.ts create mode 100644 apps/web/src/app/modules/trial-initiation/teams-content.component.html create mode 100644 apps/web/src/app/modules/trial-initiation/teams-content.component.ts create mode 100644 apps/web/src/app/modules/trial-initiation/trial-initiation.component.html create mode 100644 apps/web/src/app/modules/trial-initiation/trial-initiation.component.ts create mode 100644 apps/web/src/app/modules/trial-initiation/trial-initiation.module.ts create mode 100644 apps/web/src/app/modules/vertical-stepper/vertical-step-content.component.html create mode 100644 apps/web/src/app/modules/vertical-stepper/vertical-step-content.component.ts create mode 100644 apps/web/src/app/modules/vertical-stepper/vertical-step.component.html create mode 100644 apps/web/src/app/modules/vertical-stepper/vertical-step.component.ts create mode 100644 apps/web/src/app/modules/vertical-stepper/vertical-stepper.component.html create mode 100644 apps/web/src/app/modules/vertical-stepper/vertical-stepper.component.ts create mode 100644 apps/web/src/app/modules/vertical-stepper/vertical-stepper.module.ts create mode 100644 libs/angular/src/validators/fieldsInputCheck.validator.ts create mode 100644 libs/common/src/abstractions/formValidationErrors.service.ts create mode 100644 libs/common/src/services/formValidationErrors.service.ts diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 63464b4de8f..baa4e0066c3 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { diff --git a/apps/browser/src/popup/accounts/register.component.html b/apps/browser/src/popup/accounts/register.component.html index fc9c4e7990d..4c8ec89aac9 100644 --- a/apps/browser/src/popup/accounts/register.component.html +++ b/apps/browser/src/popup/accounts/register.component.html @@ -1,4 +1,4 @@ -
+
{{ "cancel" | i18n }} @@ -18,16 +18,7 @@
- +
@@ -44,11 +35,8 @@ @@ -60,7 +48,7 @@ appStopClick appBlurClick appA11yTitle="{{ 'toggleVisibility' | i18n }}" - (click)="togglePassword(false)" + (click)="togglePassword()" [attr.aria-pressed]="showPassword" >
@@ -110,7 +96,7 @@ appStopClick appBlurClick appA11yTitle="{{ 'toggleVisibility' | i18n }}" - (click)="togglePassword(true)" + (click)="togglePassword()" [attr.aria-pressed]="showPassword" >
- +
- +
- + diff --git a/apps/web/src/app/accounts/register.component.ts b/apps/web/src/app/accounts/register.component.ts index 3ae38f960e2..c4d60c47367 100644 --- a/apps/web/src/app/accounts/register.component.ts +++ b/apps/web/src/app/accounts/register.component.ts @@ -1,4 +1,5 @@ import { Component } from "@angular/core"; +import { FormBuilder } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; import { first } from "rxjs/operators"; @@ -7,6 +8,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuthService } from "@bitwarden/common/abstractions/auth.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; +import { FormValidationErrorsService } from "@bitwarden/common/abstractions/formValidationErrors.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; @@ -25,6 +27,7 @@ import { RouterService } from "../services/router.service"; templateUrl: "register.component.html", }) export class RegisterComponent extends BaseRegisterComponent { + email = ""; showCreateOrgMessage = false; layout = ""; enforcedPolicyOptions: MasterPasswordPolicyOptions; @@ -32,6 +35,8 @@ export class RegisterComponent extends BaseRegisterComponent { private policies: Policy[]; constructor( + formValidationErrorService: FormValidationErrorsService, + formBuilder: FormBuilder, authService: AuthService, router: Router, i18nService: I18nService, @@ -47,6 +52,8 @@ export class RegisterComponent extends BaseRegisterComponent { private routerService: RouterService ) { super( + formValidationErrorService, + formBuilder, authService, router, i18nService, @@ -126,24 +133,4 @@ export class RegisterComponent extends BaseRegisterComponent { await super.ngOnInit(); } - - async submit() { - if ( - this.enforcedPolicyOptions != null && - !this.policyService.evaluateMasterPassword( - this.masterPasswordScore, - this.masterPassword, - this.enforcedPolicyOptions - ) - ) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("masterPasswordPolicyRequirementsNotMet") - ); - return; - } - - await super.submit(); - } } diff --git a/apps/web/src/app/modules/loose-components.module.ts b/apps/web/src/app/modules/loose-components.module.ts index 7fdce78d5df..37a87cee364 100644 --- a/apps/web/src/app/modules/loose-components.module.ts +++ b/apps/web/src/app/modules/loose-components.module.ts @@ -22,7 +22,6 @@ import { VerifyRecoverDeleteComponent } from "../accounts/verify-recover-delete. import { NestedCheckboxComponent } from "../components/nested-checkbox.component"; import { OrganizationSwitcherComponent } from "../components/organization-switcher.component"; import { PasswordRepromptComponent } from "../components/password-reprompt.component"; -import { PasswordStrengthComponent } from "../components/password-strength.component"; import { PremiumBadgeComponent } from "../components/premium-badge.component"; import { FooterComponent } from "../layouts/footer.component"; import { FrontendLayoutComponent } from "../layouts/frontend-layout.component"; @@ -158,6 +157,7 @@ import { FolderAddEditComponent } from "../vault/folder-add-edit.component"; import { ShareComponent } from "../vault/share.component"; import { PipesModule } from "./pipes/pipes.module"; +import { RegisterFormModule } from "./register-form/register-form.module"; import { SharedModule } from "./shared.module"; import { VaultFilterModule } from "./vault-filter/vault-filter.module"; import { OrganizationBadgeModule } from "./vault/modules/organization-badge/organization-badge.module"; @@ -165,7 +165,13 @@ import { OrganizationBadgeModule } from "./vault/modules/organization-badge/orga // Please do not add to this list of declarations - we should refactor these into modules when doing so makes sense until there are none left. // If you are building new functionality, please create or extend a feature module instead. @NgModule({ - imports: [SharedModule, VaultFilterModule, OrganizationBadgeModule, PipesModule], + imports: [ + SharedModule, + VaultFilterModule, + OrganizationBadgeModule, + PipesModule, + RegisterFormModule, + ], declarations: [ PremiumBadgeComponent, AcceptEmergencyComponent, @@ -263,7 +269,6 @@ import { OrganizationBadgeModule } from "./vault/modules/organization-badge/orga PasswordGeneratorHistoryComponent, PasswordGeneratorPolicyComponent, PasswordRepromptComponent, - PasswordStrengthComponent, PaymentComponent, PaymentMethodComponent, PersonalOwnershipPolicyComponent, @@ -418,7 +423,6 @@ import { OrganizationBadgeModule } from "./vault/modules/organization-badge/orga PasswordGeneratorHistoryComponent, PasswordGeneratorPolicyComponent, PasswordRepromptComponent, - PasswordStrengthComponent, PaymentComponent, PaymentMethodComponent, PersonalOwnershipPolicyComponent, diff --git a/apps/web/src/app/modules/register-form/register-form.component.html b/apps/web/src/app/modules/register-form/register-form.component.html new file mode 100644 index 00000000000..b4f2877ef15 --- /dev/null +++ b/apps/web/src/app/modules/register-form/register-form.component.html @@ -0,0 +1,121 @@ +
+
+
+ + {{ "emailAddress" | i18n }} + + {{ "emailAddressDesc" | i18n }} + +
+ +
+ + {{ "name" | i18n }} + + {{ "yourNameDesc" | i18n }} + +
+ +
+ + + + {{ "masterPass" | i18n }} + + + + Important: + {{ "masterPassImportant" | i18n }} + + + + +
+ +
+ + {{ "reTypeMasterPass" | i18n }} + + + +
+ +
+ + {{ "masterPassHint" | i18n }} + + {{ "masterPassHintDesc" | i18n }} + +
+ +
+ +
+ +
+
+ +
+ + {{ "acceptPolicies" | i18n }}
+ {{ + "termsOfService" | i18n + }}, + {{ + "privacyPolicy" | i18n + }} +
+
+ +
+ {{ "createAccount" | i18n }} + + + {{ "logIn" | i18n }} + +
+ +
+
diff --git a/apps/web/src/app/modules/register-form/register-form.component.ts b/apps/web/src/app/modules/register-form/register-form.component.ts new file mode 100644 index 00000000000..519a185fa13 --- /dev/null +++ b/apps/web/src/app/modules/register-form/register-form.component.ts @@ -0,0 +1,87 @@ +import { Component, Input } from "@angular/core"; +import { FormBuilder } from "@angular/forms"; +import { Router } from "@angular/router"; + +import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/components/register.component"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { AuthService } from "@bitwarden/common/abstractions/auth.service"; +import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; +import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; +import { FormValidationErrorsService } from "@bitwarden/common/abstractions/formValidationErrors.service"; +import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/abstractions/log.service"; +import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; +import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; +import { PolicyService } from "@bitwarden/common/abstractions/policy.service"; +import { StateService } from "@bitwarden/common/abstractions/state.service"; +import { MasterPasswordPolicyOptions } from "@bitwarden/common/models/domain/masterPasswordPolicyOptions"; + +@Component({ + selector: "app-register-form", + templateUrl: "./register-form.component.html", +}) +export class RegisterFormComponent extends BaseRegisterComponent { + @Input() queryParamEmail: string; + @Input() enforcedPolicyOptions: MasterPasswordPolicyOptions; + + showErrorSummary = false; + + constructor( + formValidationErrorService: FormValidationErrorsService, + formBuilder: FormBuilder, + authService: AuthService, + router: Router, + i18nService: I18nService, + cryptoService: CryptoService, + apiService: ApiService, + stateService: StateService, + platformUtilsService: PlatformUtilsService, + passwordGenerationService: PasswordGenerationService, + private policyService: PolicyService, + environmentService: EnvironmentService, + logService: LogService + ) { + super( + formValidationErrorService, + formBuilder, + authService, + router, + i18nService, + cryptoService, + apiService, + stateService, + platformUtilsService, + passwordGenerationService, + environmentService, + logService + ); + } + + async ngOnInit() { + await super.ngOnInit(); + + if (this.queryParamEmail) { + this.formGroup.get("email")?.setValue(this.queryParamEmail); + } + } + + async submit() { + if ( + this.enforcedPolicyOptions != null && + !this.policyService.evaluateMasterPassword( + this.masterPasswordScore, + this.formGroup.get("masterPassword")?.value, + this.enforcedPolicyOptions + ) + ) { + this.platformUtilsService.showToast( + "error", + this.i18nService.t("errorOccurred"), + this.i18nService.t("masterPasswordPolicyRequirementsNotMet") + ); + return; + } + + await super.submit(false); + } +} diff --git a/apps/web/src/app/modules/register-form/register-form.module.ts b/apps/web/src/app/modules/register-form/register-form.module.ts new file mode 100644 index 00000000000..0c6c919ef16 --- /dev/null +++ b/apps/web/src/app/modules/register-form/register-form.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from "@angular/core"; + +import { SharedModule } from "../shared.module"; + +import { RegisterFormComponent } from "./register-form.component"; + +@NgModule({ + imports: [SharedModule], + declarations: [RegisterFormComponent], + exports: [RegisterFormComponent], +}) +export class RegisterFormModule {} diff --git a/apps/web/src/app/modules/shared.module.ts b/apps/web/src/app/modules/shared.module.ts index a8801e8196b..1bfbe632918 100644 --- a/apps/web/src/app/modules/shared.module.ts +++ b/apps/web/src/app/modules/shared.module.ts @@ -61,10 +61,13 @@ import { BadgeModule, ButtonModule, CalloutModule, - MenuModule, + FormFieldModule, SubmitButtonModule, + MenuModule, } from "@bitwarden/components"; +import { PasswordStrengthComponent } from "../components/password-strength.component"; + registerLocaleData(localeAf, "af"); registerLocaleData(localeAz, "az"); registerLocaleData(localeBe, "be"); @@ -117,6 +120,7 @@ registerLocaleData(localeZhCn, "zh-CN"); registerLocaleData(localeZhTw, "zh-TW"); @NgModule({ + declarations: [PasswordStrengthComponent], imports: [ CommonModule, DragDropModule, @@ -132,6 +136,7 @@ registerLocaleData(localeZhTw, "zh-TW"); BadgeModule, ButtonModule, MenuModule, + FormFieldModule, SubmitButtonModule, ], exports: [ @@ -149,6 +154,8 @@ registerLocaleData(localeZhTw, "zh-TW"); BadgeModule, ButtonModule, MenuModule, + FormFieldModule, + PasswordStrengthComponent, SubmitButtonModule, ], providers: [DatePipe], diff --git a/apps/web/src/app/modules/trial-initiation/enterprise-content.component.html b/apps/web/src/app/modules/trial-initiation/enterprise-content.component.html new file mode 100644 index 00000000000..2da9a72cab1 --- /dev/null +++ b/apps/web/src/app/modules/trial-initiation/enterprise-content.component.html @@ -0,0 +1,11 @@ +

You've chosen Bitwarden for Enterprise

+
+

What you can do with Bitwarden for Enterprise

+
+ +
+

Collaborate and share securely

+

Deploy and manage quickly and easily

+

Access anywhere on any device

+

Create your account to get started

+
diff --git a/apps/web/src/app/modules/trial-initiation/enterprise-content.component.ts b/apps/web/src/app/modules/trial-initiation/enterprise-content.component.ts new file mode 100644 index 00000000000..847b3c3088a --- /dev/null +++ b/apps/web/src/app/modules/trial-initiation/enterprise-content.component.ts @@ -0,0 +1,7 @@ +import { Component } from "@angular/core"; + +@Component({ + selector: "app-enterprise-content", + templateUrl: "enterprise-content.component.html", +}) +export class EnterpriseContentComponent {} diff --git a/apps/web/src/app/modules/trial-initiation/families-content.component.html b/apps/web/src/app/modules/trial-initiation/families-content.component.html new file mode 100644 index 00000000000..d2fc304e9e1 --- /dev/null +++ b/apps/web/src/app/modules/trial-initiation/families-content.component.html @@ -0,0 +1,13 @@ +

You've chosen Bitwarden for Families

+
+

+ Trusted by millions of individuals, teams, and organizations worldwide for secure password + storage and sharing. +

+
+
+

Collaborate and share securely

+

Deploy and manage quickly and easily

+

Access anywhere on any device

+

Create your account to get started

+
diff --git a/apps/web/src/app/modules/trial-initiation/families-content.component.ts b/apps/web/src/app/modules/trial-initiation/families-content.component.ts new file mode 100644 index 00000000000..1a13be80e67 --- /dev/null +++ b/apps/web/src/app/modules/trial-initiation/families-content.component.ts @@ -0,0 +1,7 @@ +import { Component } from "@angular/core"; + +@Component({ + selector: "app-families-content", + templateUrl: "families-content.component.html", +}) +export class FamiliesContentComponent {} diff --git a/apps/web/src/app/modules/trial-initiation/teams-content.component.html b/apps/web/src/app/modules/trial-initiation/teams-content.component.html new file mode 100644 index 00000000000..6183618dee8 --- /dev/null +++ b/apps/web/src/app/modules/trial-initiation/teams-content.component.html @@ -0,0 +1,10 @@ +

You've chosen Bitwarden for Teams

+
+

What you can do with Btiwarden for Teams

+
+
+

Collaborate and share securely

+

Deploy and manage quickly and easily

+

Access anywhere on any device

+

Create your account to get started

+
diff --git a/apps/web/src/app/modules/trial-initiation/teams-content.component.ts b/apps/web/src/app/modules/trial-initiation/teams-content.component.ts new file mode 100644 index 00000000000..5c97695deff --- /dev/null +++ b/apps/web/src/app/modules/trial-initiation/teams-content.component.ts @@ -0,0 +1,7 @@ +import { Component } from "@angular/core"; + +@Component({ + selector: "app-teams-content", + templateUrl: "teams-content.component.html", +}) +export class TeamsContentComponent {} diff --git a/apps/web/src/app/modules/trial-initiation/trial-initiation.component.html b/apps/web/src/app/modules/trial-initiation/trial-initiation.component.html new file mode 100644 index 00000000000..7e6be8485cf --- /dev/null +++ b/apps/web/src/app/modules/trial-initiation/trial-initiation.component.html @@ -0,0 +1,58 @@ +
+ +
+
+ Bitwarden + +
+ + + + + + +
+
+
+
+
+
+

+ Start your 7-Day free trial of Bitwarden for {{ org }} +

+
+ + + + +

This is content of "Step 1" that has editable set to false

+ +
+ + +

This is content of "Step 2"

+ +
+ + +

This is content of "Step 3"

+ + +
+ + +

This is any content of "Step 4"

+ +
+
+
+
+
+
diff --git a/apps/web/src/app/modules/trial-initiation/trial-initiation.component.ts b/apps/web/src/app/modules/trial-initiation/trial-initiation.component.ts new file mode 100644 index 00000000000..b3b00f1771d --- /dev/null +++ b/apps/web/src/app/modules/trial-initiation/trial-initiation.component.ts @@ -0,0 +1,25 @@ +import { Component, OnInit } from "@angular/core"; +import { ActivatedRoute } from "@angular/router"; +import { first } from "rxjs"; + +@Component({ + selector: "app-trial", + templateUrl: "trial-initiation.component.html", +}) +export class TrialInitiationComponent implements OnInit { + email = ""; + org = "teams"; + + constructor(private route: ActivatedRoute) {} + + ngOnInit(): void { + this.route.queryParams.pipe(first()).subscribe((qParams) => { + if (qParams.email != null && qParams.email.indexOf("@") > -1) { + this.email = qParams.email; + } + if (qParams.org) { + this.org = qParams.org; + } + }); + } +} diff --git a/apps/web/src/app/modules/trial-initiation/trial-initiation.module.ts b/apps/web/src/app/modules/trial-initiation/trial-initiation.module.ts new file mode 100644 index 00000000000..35370acb50b --- /dev/null +++ b/apps/web/src/app/modules/trial-initiation/trial-initiation.module.ts @@ -0,0 +1,24 @@ +import { CdkStepperModule } from "@angular/cdk/stepper"; +import { NgModule } from "@angular/core"; + +import { FormFieldModule } from "@bitwarden/components"; + +import { SharedModule } from "../shared.module"; +import { VerticalStepperModule } from "../vertical-stepper/vertical-stepper.module"; + +import { EnterpriseContentComponent } from "./enterprise-content.component"; +import { FamiliesContentComponent } from "./families-content.component"; +import { TeamsContentComponent } from "./teams-content.component"; +import { TrialInitiationComponent } from "./trial-initiation.component"; + +@NgModule({ + imports: [SharedModule, CdkStepperModule, VerticalStepperModule, FormFieldModule], + declarations: [ + TrialInitiationComponent, + EnterpriseContentComponent, + FamiliesContentComponent, + TeamsContentComponent, + ], + exports: [TrialInitiationComponent], +}) +export class TrialInitiationModule {} diff --git a/apps/web/src/app/modules/vertical-stepper/vertical-step-content.component.html b/apps/web/src/app/modules/vertical-stepper/vertical-step-content.component.html new file mode 100644 index 00000000000..91e214097db --- /dev/null +++ b/apps/web/src/app/modules/vertical-stepper/vertical-step-content.component.html @@ -0,0 +1,45 @@ +
+ +
diff --git a/apps/web/src/app/modules/vertical-stepper/vertical-step-content.component.ts b/apps/web/src/app/modules/vertical-stepper/vertical-step-content.component.ts new file mode 100644 index 00000000000..8a074073dbf --- /dev/null +++ b/apps/web/src/app/modules/vertical-stepper/vertical-step-content.component.ts @@ -0,0 +1,20 @@ +import { Component, EventEmitter, Input, Output } from "@angular/core"; + +import { VerticalStep } from "./vertical-step.component"; + +@Component({ + selector: "app-vertical-step-content", + templateUrl: "vertical-step-content.component.html", +}) +export class VerticalStepContentComponent { + @Output() onSelectStep = new EventEmitter(); + + @Input() disabled = false; + @Input() selected = false; + @Input() step: VerticalStep; + @Input() stepNumber: number; + + selectStep() { + this.onSelectStep.emit(); + } +} diff --git a/apps/web/src/app/modules/vertical-stepper/vertical-step.component.html b/apps/web/src/app/modules/vertical-stepper/vertical-step.component.html new file mode 100644 index 00000000000..8d963d6c55f --- /dev/null +++ b/apps/web/src/app/modules/vertical-stepper/vertical-step.component.html @@ -0,0 +1,7 @@ + +
+ +
+
diff --git a/apps/web/src/app/modules/vertical-stepper/vertical-step.component.ts b/apps/web/src/app/modules/vertical-stepper/vertical-step.component.ts new file mode 100644 index 00000000000..42c0eca5e87 --- /dev/null +++ b/apps/web/src/app/modules/vertical-stepper/vertical-step.component.ts @@ -0,0 +1,11 @@ +import { CdkStep } from "@angular/cdk/stepper"; +import { Component, Input } from "@angular/core"; + +@Component({ + selector: "app-vertical-step", + templateUrl: "vertical-step.component.html", + providers: [{ provide: CdkStep, useExisting: VerticalStep }], +}) +export class VerticalStep extends CdkStep { + @Input() subLabel = ""; +} diff --git a/apps/web/src/app/modules/vertical-stepper/vertical-stepper.component.html b/apps/web/src/app/modules/vertical-stepper/vertical-stepper.component.html new file mode 100644 index 00000000000..2051cfb47d8 --- /dev/null +++ b/apps/web/src/app/modules/vertical-stepper/vertical-stepper.component.html @@ -0,0 +1,22 @@ +
+
    +
  • + +
    +
    +
  • +
+
diff --git a/apps/web/src/app/modules/vertical-stepper/vertical-stepper.component.ts b/apps/web/src/app/modules/vertical-stepper/vertical-stepper.component.ts new file mode 100644 index 00000000000..2c66dae7be1 --- /dev/null +++ b/apps/web/src/app/modules/vertical-stepper/vertical-stepper.component.ts @@ -0,0 +1,29 @@ +import { CdkStepper } from "@angular/cdk/stepper"; +import { Component, Input } from "@angular/core"; + +@Component({ + selector: "app-vertical-stepper", + templateUrl: "vertical-stepper.component.html", + providers: [{ provide: CdkStepper, useExisting: VerticalStepperComponent }], +}) +export class VerticalStepperComponent extends CdkStepper { + @Input() + activeClass = "active"; + + isNextButtonHidden() { + return !(this.steps.length === this.selectedIndex + 1); + } + + isStepDisabled(index: number) { + if (this.selectedIndex !== index) { + return this.selectedIndex === index - 1 + ? !this.steps.find((_, i) => i == index - 1)?.completed + : true; + } + return false; + } + + selectStepByIndex(index: number): void { + this.selectedIndex = index; + } +} diff --git a/apps/web/src/app/modules/vertical-stepper/vertical-stepper.module.ts b/apps/web/src/app/modules/vertical-stepper/vertical-stepper.module.ts new file mode 100644 index 00000000000..71207aa4313 --- /dev/null +++ b/apps/web/src/app/modules/vertical-stepper/vertical-stepper.module.ts @@ -0,0 +1,14 @@ +import { NgModule } from "@angular/core"; + +import { SharedModule } from "../shared.module"; + +import { VerticalStepContentComponent } from "./vertical-step-content.component"; +import { VerticalStep } from "./vertical-step.component"; +import { VerticalStepperComponent } from "./vertical-stepper.component"; + +@NgModule({ + imports: [SharedModule], + declarations: [VerticalStepperComponent, VerticalStep, VerticalStepContentComponent], + exports: [VerticalStepperComponent, VerticalStep], +}) +export class VerticalStepperModule {} diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts index 8b2e6a6f923..a98cbad1d2b 100644 --- a/apps/web/src/app/oss-routing.module.ts +++ b/apps/web/src/app/oss-routing.module.ts @@ -24,6 +24,7 @@ import { VerifyRecoverDeleteComponent } from "./accounts/verify-recover-delete.c import { HomeGuard } from "./guards/home.guard"; import { FrontendLayoutComponent } from "./layouts/frontend-layout.component"; import { UserLayoutComponent } from "./layouts/user-layout.component"; +import { TrialInitiationComponent } from "./modules/trial-initiation/trial-initiation.component"; import { IndividualVaultModule } from "./modules/vault/modules/individual-vault/individual-vault.module"; import { OrganizationsRoutingModule } from "./organizations/organization-routing.module"; import { AcceptFamilySponsorshipComponent } from "./organizations/sponsorships/accept-family-sponsorship.component"; @@ -64,6 +65,12 @@ const routes: Routes = [ canActivate: [UnauthGuard], data: { titleId: "createAccount" }, }, + { + path: "trial", + component: TrialInitiationComponent, + canActivate: [UnauthGuard], + data: { titleId: "startTrial" }, + }, { path: "sso", component: SsoComponent, diff --git a/apps/web/src/app/oss.module.ts b/apps/web/src/app/oss.module.ts index 6a0d27af1a1..af19fa08d04 100644 --- a/apps/web/src/app/oss.module.ts +++ b/apps/web/src/app/oss.module.ts @@ -5,6 +5,7 @@ import { OrganizationManageModule } from "./modules/organizations/manage/organiz import { OrganizationUserModule } from "./modules/organizations/users/organization-user.module"; import { PipesModule } from "./modules/pipes/pipes.module"; import { SharedModule } from "./modules/shared.module"; +import { TrialInitiationModule } from "./modules/trial-initiation/trial-initiation.module"; import { VaultFilterModule } from "./modules/vault-filter/vault-filter.module"; import { OrganizationBadgeModule } from "./modules/vault/modules/organization-badge/organization-badge.module"; @@ -12,6 +13,7 @@ import { OrganizationBadgeModule } from "./modules/vault/modules/organization-ba imports: [ SharedModule, LooseComponentsModule, + TrialInitiationModule, VaultFilterModule, OrganizationBadgeModule, PipesModule, @@ -21,6 +23,7 @@ import { OrganizationBadgeModule } from "./modules/vault/modules/organization-ba exports: [ SharedModule, LooseComponentsModule, + TrialInitiationModule, VaultFilterModule, OrganizationBadgeModule, PipesModule, diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 0e32e2dd533..9d54a00450c 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Create Account" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Log In" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "A master password hint can help you remember your password if you forget it." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/libs/angular/src/components/register.component.ts b/libs/angular/src/components/register.component.ts index 3f5339c9165..15694ec8383 100644 --- a/libs/angular/src/components/register.component.ts +++ b/libs/angular/src/components/register.component.ts @@ -1,10 +1,19 @@ import { Directive, OnInit } from "@angular/core"; +import { FormBuilder, Validators } from "@angular/forms"; import { Router } from "@angular/router"; +import { + validateInputsDoesntMatch, + validateInputsMatch, +} from "@bitwarden/angular/validators/fieldsInputCheck.validator"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuthService } from "@bitwarden/common/abstractions/auth.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; +import { + AllValidationErrors, + FormValidationErrorsService, +} from "@bitwarden/common/abstractions/formValidationErrors.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; @@ -19,22 +28,38 @@ import { CaptchaProtectedComponent } from "./captchaProtected.component"; @Directive() export class RegisterComponent extends CaptchaProtectedComponent implements OnInit { - name = ""; - email = ""; - masterPassword = ""; - confirmMasterPassword = ""; - hint = ""; showPassword = false; formPromise: Promise; masterPasswordScore: number; referenceData: ReferenceEventRequest; showTerms = true; - acceptPolicies = false; + showErrorSummary = false; + + formGroup = this.formBuilder.group({ + email: ["", [Validators.required, Validators.email]], + name: [""], + masterPassword: ["", [Validators.required, Validators.minLength(8)]], + confirmMasterPassword: [ + "", + [ + Validators.required, + Validators.minLength(8), + validateInputsMatch("masterPassword", this.i18nService.t("masterPassDoesntMatch")), + ], + ], + hint: [ + null, + [validateInputsDoesntMatch("masterPassword", this.i18nService.t("hintEqualsPassword"))], + ], + acceptPolicies: [false, [Validators.requiredTrue]], + }); protected successRoute = "login"; private masterPasswordStrengthTimeout: any; constructor( + protected formValidationErrorService: FormValidationErrorsService, + protected formBuilder: FormBuilder, protected authService: AuthService, protected router: Router, i18nService: I18nService, @@ -84,59 +109,38 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn } } - async submit() { - if (!this.acceptPolicies && this.showTerms) { + async submit(showToast = true) { + let email = this.formGroup.get("email")?.value; + let name = this.formGroup.get("name")?.value; + const masterPassword = this.formGroup.get("masterPassword")?.value; + const hint = this.formGroup.get("hint")?.value; + + this.formGroup.markAllAsTouched(); + this.showErrorSummary = true; + + if (this.formGroup.get("acceptPolicies").hasError("required")) { this.platformUtilsService.showToast( "error", this.i18nService.t("errorOccurred"), - this.i18nService.t("acceptPoliciesError") + this.i18nService.t("acceptPoliciesRequired") ); return; } - if (this.email == null || this.email === "") { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("emailRequired") - ); + //web + if (this.formGroup.invalid && !showToast) { return; } - if (this.email.indexOf("@") === -1) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("invalidEmail") - ); - return; - } - if (this.masterPassword == null || this.masterPassword === "") { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("masterPassRequired") - ); - return; - } - if (this.masterPassword.length < 8) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("masterPassLength") - ); - return; - } - if (this.masterPassword !== this.confirmMasterPassword) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("masterPassDoesntMatch") - ); + + //desktop, browser + if (this.formGroup.invalid && showToast) { + const errorText = this.getErrorToastMessage(); + this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), errorText); return; } const strengthResult = this.passwordGenerationService.passwordStrength( - this.masterPassword, + masterPassword, this.getPasswordStrengthUserInput() ); if (strengthResult != null && strengthResult.score < 3) { @@ -152,33 +156,19 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn } } - if (this.hint === this.masterPassword) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("hintEqualsPassword") - ); - return; - } - - this.name = this.name === "" ? null : this.name; - this.email = this.email.trim().toLowerCase(); + name = name === "" ? null : name; + email = email.trim().toLowerCase(); const kdf = DEFAULT_KDF_TYPE; const kdfIterations = DEFAULT_KDF_ITERATIONS; - const key = await this.cryptoService.makeKey( - this.masterPassword, - this.email, - kdf, - kdfIterations - ); + const key = await this.cryptoService.makeKey(masterPassword, email, kdf, kdfIterations); const encKey = await this.cryptoService.makeEncKey(key); - const hashedPassword = await this.cryptoService.hashPassword(this.masterPassword, key); + const hashedPassword = await this.cryptoService.hashPassword(masterPassword, key); const keys = await this.cryptoService.makeKeyPair(encKey[0]); const request = new RegisterRequest( - this.email, - this.name, + email, + name, hashedPassword, - this.hint, + hint, encKey[1].encryptedString, kdf, kdfIterations, @@ -204,24 +194,25 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn } } this.platformUtilsService.showToast("success", null, this.i18nService.t("newAccountCreated")); - this.router.navigate([this.successRoute], { queryParams: { email: this.email } }); + this.router.navigate([this.successRoute], { queryParams: { email: email } }); } catch (e) { this.logService.error(e); } } - togglePassword(confirmField: boolean) { + togglePassword() { this.showPassword = !this.showPassword; - document.getElementById(confirmField ? "masterPasswordRetype" : "masterPassword").focus(); } updatePasswordStrength() { + const masterPassword = this.formGroup.get("masterPassword")?.value; + if (this.masterPasswordStrengthTimeout != null) { clearTimeout(this.masterPasswordStrengthTimeout); } this.masterPasswordStrengthTimeout = setTimeout(() => { const strengthResult = this.passwordGenerationService.passwordStrength( - this.masterPassword, + masterPassword, this.getPasswordStrengthUserInput() ); this.masterPasswordScore = strengthResult == null ? null : strengthResult.score; @@ -230,19 +221,47 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn private getPasswordStrengthUserInput() { let userInput: string[] = []; - const atPosition = this.email.indexOf("@"); + const email = this.formGroup.get("email")?.value; + const name = this.formGroup.get("name").value; + const atPosition = email.indexOf("@"); if (atPosition > -1) { userInput = userInput.concat( - this.email + email .substr(0, atPosition) .trim() .toLowerCase() .split(/[^A-Za-z0-9]/) ); } - if (this.name != null && this.name !== "") { - userInput = userInput.concat(this.name.trim().toLowerCase().split(" ")); + if (name != null && name !== "") { + userInput = userInput.concat(name.trim().toLowerCase().split(" ")); } return userInput; } + + private getErrorToastMessage() { + const error: AllValidationErrors = this.formValidationErrorService + .getFormValidationErrors(this.formGroup.controls) + .shift(); + + if (error) { + switch (error.errorName) { + case "email": + return this.i18nService.t("invalidEmail"); + case "inputsDoesntMatchError": + return this.i18nService.t("masterPassDoesntMatch"); + case "inputsMatchError": + return this.i18nService.t("hintEqualsPassword"); + default: + return this.i18nService.t(this.errorTag(error)); + } + } + + return; + } + + private errorTag(error: AllValidationErrors): string { + const name = error.errorName.charAt(0).toUpperCase() + error.errorName.slice(1); + return `${error.controlName}${name}`; + } } diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 1314abf4dac..245fa58bf95 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -17,6 +17,7 @@ import { EventService as EventServiceAbstraction } from "@bitwarden/common/abstr import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service"; import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/fileUpload.service"; import { FolderService as FolderServiceAbstraction } from "@bitwarden/common/abstractions/folder.service"; +import { FormValidationErrorsService as FormValidationErrorsServiceAbstraction } from "@bitwarden/common/abstractions/formValidationErrors.service"; import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service"; import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/abstractions/keyConnector.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; @@ -58,6 +59,7 @@ import { EventService } from "@bitwarden/common/services/event.service"; import { ExportService } from "@bitwarden/common/services/export.service"; import { FileUploadService } from "@bitwarden/common/services/fileUpload.service"; import { FolderService } from "@bitwarden/common/services/folder.service"; +import { FormValidationErrorsService } from "@bitwarden/common/services/formValidationErrors.service"; import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service"; import { NotificationsService } from "@bitwarden/common/services/notifications.service"; import { OrganizationService } from "@bitwarden/common/services/organization.service"; @@ -444,6 +446,10 @@ export const LOG_MAC_FAILURES = new InjectionToken("LOG_MAC_FAILURES"); provide: AbstractThemingService, useClass: ThemingService, }, + { + provide: FormValidationErrorsServiceAbstraction, + useClass: FormValidationErrorsService, + }, ], }) export class JslibServicesModule {} diff --git a/libs/angular/src/validators/fieldsInputCheck.validator.ts b/libs/angular/src/validators/fieldsInputCheck.validator.ts new file mode 100644 index 00000000000..ac1b4d5a404 --- /dev/null +++ b/libs/angular/src/validators/fieldsInputCheck.validator.ts @@ -0,0 +1,37 @@ +import { AbstractControl, ValidatorFn } from "@angular/forms"; + +import { FormGroupControls } from "@bitwarden/common/abstractions/formValidationErrors.service"; + +//check to ensure two fields do not have the same value +export function validateInputsDoesntMatch(matchTo: string, errorMessage: string): ValidatorFn { + return (control: AbstractControl) => { + if (control.parent && control.parent.controls) { + return control?.value === (control?.parent?.controls as FormGroupControls)[matchTo].value + ? { + inputsMatchError: { + message: errorMessage, + }, + } + : null; + } + + return null; + }; +} + +//check to ensure two fields have the same value +export function validateInputsMatch(matchTo: string, errorMessage: string): ValidatorFn { + return (control: AbstractControl) => { + if (control.parent && control.parent.controls) { + return control?.value === (control?.parent?.controls as FormGroupControls)[matchTo].value + ? null + : { + inputsDoesntMatchError: { + message: errorMessage, + }, + }; + } + + return null; + }; +} diff --git a/libs/common/src/abstractions/formValidationErrors.service.ts b/libs/common/src/abstractions/formValidationErrors.service.ts new file mode 100644 index 00000000000..08a12443a0c --- /dev/null +++ b/libs/common/src/abstractions/formValidationErrors.service.ts @@ -0,0 +1,13 @@ +import { AbstractControl } from "@angular/forms"; +export interface AllValidationErrors { + controlName: string; + errorName: string; +} + +export interface FormGroupControls { + [key: string]: AbstractControl; +} + +export abstract class FormValidationErrorsService { + getFormValidationErrors: (controls: FormGroupControls) => AllValidationErrors[]; +} diff --git a/libs/common/src/services/formValidationErrors.service.ts b/libs/common/src/services/formValidationErrors.service.ts new file mode 100644 index 00000000000..c5ce5377eb8 --- /dev/null +++ b/libs/common/src/services/formValidationErrors.service.ts @@ -0,0 +1,31 @@ +import { FormGroup, ValidationErrors } from "@angular/forms"; + +import { + FormGroupControls, + FormValidationErrorsService as FormValidationErrorsAbstraction, + AllValidationErrors, +} from "../abstractions/formValidationErrors.service"; + +export class FormValidationErrorsService implements FormValidationErrorsAbstraction { + getFormValidationErrors(controls: FormGroupControls): AllValidationErrors[] { + let errors: AllValidationErrors[] = []; + Object.keys(controls).forEach((key) => { + const control = controls[key]; + if (control instanceof FormGroup) { + errors = errors.concat(this.getFormValidationErrors(control.controls)); + } + + const controlErrors: ValidationErrors = controls[key].errors; + if (controlErrors !== null) { + Object.keys(controlErrors).forEach((keyError) => { + errors.push({ + controlName: key, + errorName: keyError, + }); + }); + } + }); + + return errors; + } +} diff --git a/libs/components/src/form-field/error.component.ts b/libs/components/src/form-field/error.component.ts index 26c1eec78f5..5cf95545e2a 100644 --- a/libs/components/src/form-field/error.component.ts +++ b/libs/components/src/form-field/error.component.ts @@ -26,6 +26,8 @@ export class BitErrorComponent { return this.i18nService.t("inputRequired"); case "email": return this.i18nService.t("inputEmail"); + case "minlength": + return this.i18nService.t("inputMinLength", this.error[1]?.requiredLength); default: // Attempt to show a custom error message. if (this.error[1]?.message) { From c8ead3de653d75f604c6a27a6d1496302a0cb56e Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Tue, 5 Jul 2022 23:03:00 +0200 Subject: [PATCH 09/86] Resolve CLI release pipeline not including build artifacts (#3040) --- .github/workflows/release-cli.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml index 3b4f8e9a90c..63a04406e51 100644 --- a/.github/workflows/release-cli.yml +++ b/.github/workflows/release-cli.yml @@ -206,7 +206,7 @@ jobs: uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8 with: workflow: build-cli.yml - path: apps/cli + path: apps/cli/build workflow_conclusion: success branch: ${{ github.ref_name }} artifacts: bitwarden-cli-${{ env._PKG_VERSION }}-npm-build.zip From 2f290e406d5bb917c828a34f20e798f1caf56a3d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 5 Jul 2022 14:43:54 -0700 Subject: [PATCH 10/86] Bumped cli version to 2022.6.1 (#3041) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- apps/cli/package-lock.json | 4 ++-- apps/cli/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/cli/package-lock.json b/apps/cli/package-lock.json index 9e6a3071763..304863e339a 100644 --- a/apps/cli/package-lock.json +++ b/apps/cli/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bitwarden/cli", - "version": "2022.6.0", + "version": "2022.6.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@bitwarden/cli", - "version": "2022.6.0", + "version": "2022.6.1", "license": "GPL-3.0-only", "dependencies": { "@koa/multer": "^3.0.0", diff --git a/apps/cli/package.json b/apps/cli/package.json index a41d8d5ca7e..1ad27031097 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,7 +1,7 @@ { "name": "@bitwarden/cli", "description": "A secure and free password manager for all of your devices.", - "version": "2022.6.0", + "version": "2022.6.1", "keywords": [ "bitwarden", "password", From 2ecce7215ff73abfbfb230ae93bd6685d6f53f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Tom=C3=A9?= <108268980+r-tome@users.noreply.github.com> Date: Wed, 6 Jul 2022 09:48:42 +0100 Subject: [PATCH 11/86] Changed the wording of the Bitwarden account deletion text. (#3035) --- apps/web/src/locales/en/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 9d54a00450c..c9ffaf9b01f 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -1085,7 +1085,7 @@ "message": "Account Deleted" }, "accountDeletedDesc": { - "message": "Your account has been closed and all associated data has been deleted." + "message": "Your Bitwarden account and vault data were permanently deleted." }, "myAccount": { "message": "My Account" From 4dd149e9122e030b33fd5f9854e609247859d04c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ch=C4=99ci=C5=84ski?= Date: Wed, 6 Jul 2022 10:50:59 +0200 Subject: [PATCH 12/86] Fix download URL on choco update script (#3029) --- apps/desktop/scripts/choco-update.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/scripts/choco-update.ps1 b/apps/desktop/scripts/choco-update.ps1 index 72677357aaa..24c0edf9526 100644 --- a/apps/desktop/scripts/choco-update.ps1 +++ b/apps/desktop/scripts/choco-update.ps1 @@ -19,7 +19,7 @@ if(Test-Path -Path $distChocoDir) { Copy-Item -Path $chocoDir -Destination $distChocoDir –Recurse $exe = $distChocoDir + "\Bitwarden-Installer-" + $version + ".exe"; -$uri = "https://github.com/bitwarden/desktop/releases/download/v" + $version + "/Bitwarden-Installer-" + $version + ".exe"; +$uri = "https://github.com/bitwarden/clients/releases/download/desktop-v" + $version + "/Bitwarden-Installer-" + $version + ".exe"; [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Invoke-RestMethod -Uri $uri -OutFile $exe From 12615c203fcc4783b6045a4a87038e92e0ccc9e8 Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Wed, 6 Jul 2022 15:19:58 -0400 Subject: [PATCH 13/86] [PS-1051] Fix/add master pass hash to all org reset key requests (#3049) * clarify master password reset calls * Add master password hash to master password change requests --- .../components/organization-options.component.ts | 1 + apps/web/src/app/settings/change-password.component.ts | 5 +++-- libs/angular/src/components/set-password.component.ts | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/web/src/app/modules/vault-filter/components/organization-options.component.ts b/apps/web/src/app/modules/vault-filter/components/organization-options.component.ts index 919e39f2acf..fd2cd437e20 100644 --- a/apps/web/src/app/modules/vault-filter/components/organization-options.component.ts +++ b/apps/web/src/app/modules/vault-filter/components/organization-options.component.ts @@ -120,6 +120,7 @@ export class OrganizationOptionsComponent { }, }); } else { + // Remove reset password const request = new OrganizationUserResetPasswordEnrollmentRequest(); request.masterPasswordHash = "ignored"; request.resetPasswordKey = null; diff --git a/apps/web/src/app/settings/change-password.component.ts b/apps/web/src/app/settings/change-password.component.ts index 9b7e541c6a3..9e4fde680be 100644 --- a/apps/web/src/app/settings/change-password.component.ts +++ b/apps/web/src/app/settings/change-password.component.ts @@ -224,7 +224,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { await this.updateEmergencyAccesses(encKey[0]); - await this.updateAllResetPasswordKeys(encKey[0]); + await this.updateAllResetPasswordKeys(encKey[0], masterPasswordHash); } private async updateEmergencyAccesses(encKey: SymmetricCryptoKey) { @@ -252,7 +252,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { } } - private async updateAllResetPasswordKeys(encKey: SymmetricCryptoKey) { + private async updateAllResetPasswordKeys(encKey: SymmetricCryptoKey, masterPasswordHash: string) { const orgs = await this.organizationService.getAll(); for (const org of orgs) { @@ -270,6 +270,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { // Create/Execute request const request = new OrganizationUserResetPasswordEnrollmentRequest(); + request.masterPasswordHash = masterPasswordHash; request.resetPasswordKey = encryptedKey.encryptedString; await this.apiService.putOrganizationUserResetPasswordEnrollment(org.id, org.userId, request); diff --git a/libs/angular/src/components/set-password.component.ts b/libs/angular/src/components/set-password.component.ts index 9ae12b9ebb6..3db85a65475 100644 --- a/libs/angular/src/components/set-password.component.ts +++ b/libs/angular/src/components/set-password.component.ts @@ -128,6 +128,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent { ); const resetRequest = new OrganizationUserResetPasswordEnrollmentRequest(); + resetRequest.masterPasswordHash = masterPasswordHash; resetRequest.resetPasswordKey = encryptedKey.encryptedString; return this.apiService.putOrganizationUserResetPasswordEnrollment( From 340beb1b8720482a97f687b4d5065efe8e57e03c Mon Sep 17 00:00:00 2001 From: Joseph Flinn <58369717+joseph-flinn@users.noreply.github.com> Date: Wed, 6 Jul 2022 15:44:03 -0700 Subject: [PATCH 14/86] Manual Web Version Bump 2022.6.1 (#3052) --- apps/web/package.json | 2 +- package-lock.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 33032c9a57d..52492d800dd 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/web-vault", - "version": "2022.6.0", + "version": "2022.6.1", "scripts": { "build:oss": "webpack", "build:bit": "webpack -c ../../bitwarden_license/bit-web/webpack.config.js", diff --git a/package-lock.json b/package-lock.json index da511d2ed33..3325a4292e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -227,7 +227,7 @@ }, "apps/web": { "name": "@bitwarden/web-vault", - "version": "2022.6.0" + "version": "2022.6.1" }, "libs/angular": { "name": "@bitwarden/angular", From a65964cd97cb10aa2182f6ab8397c78d72f2c009 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 7 Jul 2022 07:27:49 -0700 Subject: [PATCH 15/86] Bumped browser version to 2022.6.1 (#3060) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- apps/browser/src/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/browser/src/manifest.json b/apps/browser/src/manifest.json index 0054762b049..9e1299cf0b3 100644 --- a/apps/browser/src/manifest.json +++ b/apps/browser/src/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_extName__", "short_name": "__MSG_appName__", - "version": "2022.6.0", + "version": "2022.6.1", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", From 97598f5ba467e84bb5106175552b07d5a4a23eb7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 7 Jul 2022 07:28:16 -0700 Subject: [PATCH 16/86] Bumped cli version to 2022.6.2 (#3061) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- apps/cli/package-lock.json | 4 ++-- apps/cli/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/cli/package-lock.json b/apps/cli/package-lock.json index 304863e339a..133ba88a2c9 100644 --- a/apps/cli/package-lock.json +++ b/apps/cli/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bitwarden/cli", - "version": "2022.6.1", + "version": "2022.6.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@bitwarden/cli", - "version": "2022.6.1", + "version": "2022.6.2", "license": "GPL-3.0-only", "dependencies": { "@koa/multer": "^3.0.0", diff --git a/apps/cli/package.json b/apps/cli/package.json index 1ad27031097..f4c7b669539 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,7 +1,7 @@ { "name": "@bitwarden/cli", "description": "A secure and free password manager for all of your devices.", - "version": "2022.6.1", + "version": "2022.6.2", "keywords": [ "bitwarden", "password", From 847d972b0e8e5130f6500a9c9aeade0073f93973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Tom=C3=A9?= <108268980+r-tome@users.noreply.github.com> Date: Thu, 7 Jul 2022 17:22:37 +0100 Subject: [PATCH 17/86] Added warning when Vault timeout is set to "Never" (#3037) --- .../src/app/accounts/settings.component.ts | 19 +++++++++++++++++++ apps/desktop/src/locales/en/messages.json | 3 +++ 2 files changed, 22 insertions(+) diff --git a/apps/desktop/src/app/accounts/settings.component.ts b/apps/desktop/src/app/accounts/settings.component.ts index d8ef021155c..2a02746788c 100644 --- a/apps/desktop/src/app/accounts/settings.component.ts +++ b/apps/desktop/src/app/accounts/settings.component.ts @@ -68,6 +68,8 @@ export class SettingsComponent implements OnInit { currentUserEmail: string; + previousVaultTimeout: number = null; + constructor( private i18nService: I18nService, private platformUtilsService: PlatformUtilsService, @@ -173,6 +175,7 @@ export class SettingsComponent implements OnInit { // Security this.vaultTimeout.setValue(await this.stateService.getVaultTimeout()); this.vaultTimeoutAction = await this.stateService.getVaultTimeoutAction(); + this.previousVaultTimeout = this.vaultTimeout.value; this.vaultTimeout.valueChanges.pipe(debounceTime(500)).subscribe(() => { this.saveVaultTimeoutOptions(); }); @@ -195,6 +198,20 @@ export class SettingsComponent implements OnInit { } async saveVaultTimeoutOptions() { + if (this.vaultTimeout.value == null) { + const confirmed = await this.platformUtilsService.showDialog( + this.i18nService.t("neverLockWarning"), + "", + this.i18nService.t("yes"), + this.i18nService.t("cancel"), + "warning" + ); + if (!confirmed) { + this.vaultTimeout.setValue(this.previousVaultTimeout); + return; + } + } + if (this.vaultTimeoutAction === "logOut") { const confirmed = await this.platformUtilsService.showDialog( this.i18nService.t("vaultTimeoutLogOutConfirmation"), @@ -223,6 +240,8 @@ export class SettingsComponent implements OnInit { return; } + this.previousVaultTimeout = this.vaultTimeout.value; + await this.vaultTimeoutService.setVaultTimeoutOptions( this.vaultTimeout.value, this.vaultTimeoutAction diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index 23fbbbb77a2..94c44b53eb1 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -1963,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } From 75cf617a508f010ee0525e16e67901afea5384fe Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 8 Jul 2022 08:30:38 +0200 Subject: [PATCH 18/86] Autosync the updated translations (#3067) Co-authored-by: github-actions <> --- apps/browser/src/_locales/ar/messages.json | 9 +- apps/browser/src/_locales/az/messages.json | 9 +- apps/browser/src/_locales/be/messages.json | 15 +- apps/browser/src/_locales/bg/messages.json | 11 +- apps/browser/src/_locales/bn/messages.json | 15 +- apps/browser/src/_locales/bs/messages.json | 9 +- apps/browser/src/_locales/ca/messages.json | 21 +- apps/browser/src/_locales/cs/messages.json | 21 +- apps/browser/src/_locales/da/messages.json | 15 +- apps/browser/src/_locales/de/messages.json | 11 +- apps/browser/src/_locales/el/messages.json | 15 +- apps/browser/src/_locales/en_GB/messages.json | 11 +- apps/browser/src/_locales/en_IN/messages.json | 9 +- apps/browser/src/_locales/es/messages.json | 45 +- apps/browser/src/_locales/et/messages.json | 9 +- apps/browser/src/_locales/eu/messages.json | 331 +++++++------- apps/browser/src/_locales/fa/messages.json | 13 +- apps/browser/src/_locales/fi/messages.json | 19 +- apps/browser/src/_locales/fil/messages.json | 9 +- apps/browser/src/_locales/fr/messages.json | 15 +- apps/browser/src/_locales/he/messages.json | 15 +- apps/browser/src/_locales/hi/messages.json | 15 +- apps/browser/src/_locales/hr/messages.json | 15 +- apps/browser/src/_locales/hu/messages.json | 13 +- apps/browser/src/_locales/id/messages.json | 15 +- apps/browser/src/_locales/it/messages.json | 15 +- apps/browser/src/_locales/ja/messages.json | 11 +- apps/browser/src/_locales/ka/messages.json | 9 +- apps/browser/src/_locales/km/messages.json | 9 +- apps/browser/src/_locales/kn/messages.json | 15 +- apps/browser/src/_locales/ko/messages.json | 15 +- apps/browser/src/_locales/lt/messages.json | 13 +- apps/browser/src/_locales/lv/messages.json | 15 +- apps/browser/src/_locales/ml/messages.json | 15 +- apps/browser/src/_locales/nb/messages.json | 15 +- apps/browser/src/_locales/nl/messages.json | 15 +- apps/browser/src/_locales/nn/messages.json | 9 +- apps/browser/src/_locales/pl/messages.json | 11 +- apps/browser/src/_locales/pt_BR/messages.json | 15 +- apps/browser/src/_locales/pt_PT/messages.json | 414 ++++++++++++------ apps/browser/src/_locales/ro/messages.json | 15 +- apps/browser/src/_locales/ru/messages.json | 11 +- apps/browser/src/_locales/si/messages.json | 15 +- apps/browser/src/_locales/sk/messages.json | 11 +- apps/browser/src/_locales/sl/messages.json | 13 +- apps/browser/src/_locales/sr/messages.json | 43 +- apps/browser/src/_locales/sv/messages.json | 15 +- apps/browser/src/_locales/th/messages.json | 13 +- apps/browser/src/_locales/tr/messages.json | 9 +- apps/browser/src/_locales/uk/messages.json | 25 +- apps/browser/src/_locales/vi/messages.json | 15 +- apps/browser/src/_locales/zh_CN/messages.json | 17 +- apps/browser/src/_locales/zh_TW/messages.json | 13 +- 53 files changed, 903 insertions(+), 593 deletions(-) diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index 63464b4de8f..baa4e0066c3 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index 670bda360e1..127cd675b17 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "Etibarsız e-poçt ünvanı." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Ana parol lazımdır." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Ana parolun yenidən yazılması lazımdır." + }, + "masterPasswordMinLength": { "message": "Ana parol ən azı 8 simvol uzunluğunda olmalıdır." }, "masterPassDoesntMatch": { @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "Bu qutunu işarələyərək aşağıdakılarla razılaşırsınız:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Xidmət Şərtləri və Gizlilik Siyasəti qəbul edilməyib." }, "termsOfService": { diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index 4c7613f8e34..63313f049fd 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Памылковы адрас электроннай пошты." }, - "masterPassRequired": { - "message": "Патрабуецца асноўны пароль." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Асноўны пароль павінен быць даўжынёй не менш за 8 сімвалаў." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Асноўныя паролі не супадаюць." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Ставіўшы гэты сцяжок вы пагаджаецеся з наступным:" }, - "acceptPoliciesError": { - "message": "Умовы выкарыстання і Палітыка прыватнасці не былі пацверджаны." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Умовы выкарыстання" diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index 5d3cb13a47a..dadb47849a9 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Недействителна електронна поща." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Главната парола е задължителна." }, - "masterPassLength": { - "message": "Главната парола трябва да съдържа поне 8 знака." + "confirmMasterPasswordRequired": { + "message": "Повторното въвеждане на главната парола е задължително." + }, + "masterPasswordMinLength": { + "message": "Главната парола трябва да е с дължина поне 8 знака." }, "masterPassDoesntMatch": { "message": "Главната парола и потвърждението ѝ не съвпадат." @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "Чрез тази отметка вие се съгласявате със следното:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Условията за използване и политиката за поверителност не бяха приети." }, "termsOfService": { diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json index 39330004f62..9369e1adf03 100644 --- a/apps/browser/src/_locales/bn/messages.json +++ b/apps/browser/src/_locales/bn/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "অকার্যকর ইমেইল ঠিকানা।" }, - "masterPassRequired": { - "message": "মূল পাসওয়ার্ড প্রয়োজন।" + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "মূল পাসওয়ার্ড কমপক্ষে ৮ অক্ষর দীর্ঘ হওয়া উচিত।" + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "মূল পাসওয়ার্ড নিশ্চিতকরণ মেলেনি।" @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "এই বাক্সটি টিক করে আপনি নিম্নলিখিতগুলিতে সম্মত হন:" }, - "acceptPoliciesError": { - "message": "পরিষেবার শর্তাদি এবং গোপনীয়তা নীতি স্বীকার করা হয়নি।" + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "সেবা পাবার শর্ত" diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json index 63464b4de8f..baa4e0066c3 100644 --- a/apps/browser/src/_locales/bs/messages.json +++ b/apps/browser/src/_locales/bs/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index 5e848178824..eb929a8a951 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "L'adreça de correu electrònic no és vàlida." }, - "masterPassRequired": { - "message": "La contrasenya mestra és obligatòria." + "masterPasswordRequired": { + "message": "Es requereix la contrasenya mestra." }, - "masterPassLength": { - "message": "La contrasenya mestra ha de contenir almenys 8 caràcters." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "La confirmació de la contrasenya mestra no coincideix." @@ -568,7 +571,7 @@ "description": "This is the folder for uncategorized items" }, "enableAddLoginNotification": { - "message": "Ask to add login" + "message": "Demana d'afegir els inicis de sessió" }, "addLoginNotificationDesc": { "message": "La \"Notificació per afegir inicis de sessió\" demana automàticament que guardeu els nous inicis de sessió a la vostra caixa forta quan inicieu la sessió per primera vegada." @@ -600,7 +603,7 @@ "message": "Guarda" }, "enableChangedPasswordNotification": { - "message": "Ask to update existing login" + "message": "Demana d'actualitzar els inicis de sessió existents" }, "changedPasswordNotificationDesc": { "message": "Ask to update a login's password when a change is detected on a website." @@ -1034,7 +1037,7 @@ "message": "Aquest navegador no pot processar sol·licituds U2F en aquesta finestra emergent. Voleu obrir l'emergent en una finestra nova per poder iniciar la sessió mitjançant U2F?" }, "enableFavicon": { - "message": "Show website icons" + "message": "Mostra les icones dels llocs web" }, "faviconDesc": { "message": "Show a recognizable image next to each login." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Si activeu aquesta casella, indiqueu que esteu d’acord amb el següent:" }, - "acceptPoliciesError": { - "message": "No s’han reconegut les condicions del servei i la declaració de privadesa." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Condicions del servei" diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json index e04da60e48f..c84e80f0534 100644 --- a/apps/browser/src/_locales/cs/messages.json +++ b/apps/browser/src/_locales/cs/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Neplatná e-mailová adresa." }, - "masterPassRequired": { - "message": "Hlavní heslo je povinné." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Hlavní heslo musí obsahovat alespoň 8 znaků." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Potvrzení hlavního hesla se neshoduje." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Zaškrtnutím tohoto políčka souhlasím s následujícím:" }, - "acceptPoliciesError": { - "message": "Podmínky použití a zásady ochrany osobních údajů nebyly odsouhlaseny." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Podmínky použití" @@ -1950,17 +1953,17 @@ "message": "Forwarded Email Alias" }, "forwardedEmailDesc": { - "message": "Generate an email alias with an external forwarding service." + "message": "Vygenerovat e-mailový alias pomocí externí služby pro přesměrování." }, "hostname": { "message": "Hostname", "description": "Part of a URL." }, "apiAccessToken": { - "message": "API Access Token" + "message": "Přístupový token" }, "apiKey": { - "message": "API Key" + "message": "API klíč" }, "ssoKeyConnectorError": { "message": "Key Connector error: make sure Key Connector is available and working correctly." diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index b9c9a167c5c..d41ee8a0909 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Ugyldig e-mailadresse." }, - "masterPassRequired": { - "message": "Hovedadgangskode er påkrævet." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Hovedadgangskoden skal være på mindst 8 tegn." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "De to adgangskoder matcher ikke." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Ved at markere dette felt accepterer du følgende:" }, - "acceptPoliciesError": { - "message": "Servicevilkår og fortrolighedspolitik er ikke blevet bekræftet." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Servicevilkår" diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index 5c0064aad37..e7f623e4e0d 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "Ungültige E-Mail Adresse." }, - "masterPassRequired": { - "message": "Das Master-Passwort wird benötigt." + "masterPasswordRequired": { + "message": "Das Master-Passwort ist erforderlich." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Erneute Eingabe des Master-Passworts ist erforderlich." + }, + "masterPasswordMinLength": { "message": "Das Master-Passwort muss mindestens 8 Zeichen lang sein." }, "masterPassDoesntMatch": { @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "Durch Anwählen dieses Kästchens erklären Sie sich mit folgendem einverstanden:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Die Nutzungsbedingungen und Datenschutzerklärung wurden nicht akzeptiert." }, "termsOfService": { diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index 2acec9fb149..518190098fc 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Μη έγκυρη διεύθυνση e-mail." }, - "masterPassRequired": { - "message": "Απαιτείται κύριος κωδικός πρόσβασης." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Ο κύριος κωδικός πρέπει να έχει μήκος τουλάχιστον 8 χαρακτήρες." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Η επιβεβαίωση κύριου κωδικού δεν ταιριάζει." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Επιλέγοντας αυτό το πλαίσιο, συμφωνείτε με τα εξής:" }, - "acceptPoliciesError": { - "message": "Οι Όροι Παροχής Υπηρεσιών και η Πολιτική Απορρήτου δεν έχουν αναγνωριστεί." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Όροι Χρήσης" diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json index f9f82616207..9bb199f224f 100644 --- a/apps/browser/src/_locales/en_GB/messages.json +++ b/apps/browser/src/_locales/en_GB/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { - "message": "Terms of service and privacy policy have not been acknowledged." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Terms of service" diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json index 6afd6fd2082..ec786608775 100644 --- a/apps/browser/src/_locales/en_IN/messages.json +++ b/apps/browser/src/_locales/en_IN/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index 4fb5cc81e8c..9024cd39219 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "Correo electrónico no válido." }, - "masterPassRequired": { - "message": "Contraseña maestra requerida." + "masterPasswordRequired": { + "message": "Se requiere una contraseña maestra." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Se requiere volver a teclear la contraseña maestra." + }, + "masterPasswordMinLength": { "message": "La contraseña maestra debe tener al menos 8 caracteres." }, "masterPassDoesntMatch": { @@ -568,22 +571,22 @@ "description": "This is the folder for uncategorized items" }, "enableAddLoginNotification": { - "message": "Ask to add login" + "message": "Pedir que se añada el inicio de sesión" }, "addLoginNotificationDesc": { "message": "La opción \"Notificación para añadir entradas\" pregunta automáticamente si quieres guardar nuevas entradas en tu caja fuerte cuando te identificas en un sitio web por primera vez." }, "showCardsCurrentTab": { - "message": "Show cards on Tab page" + "message": "Mostrar las tarjetas en la pestaña" }, "showCardsCurrentTabDesc": { - "message": "List card items on the Tab page for easy auto-fill." + "message": "Listar los elementos de tarjetas en la página para facilitar el auto-rellenado." }, "showIdentitiesCurrentTab": { - "message": "Show identities on Tab page" + "message": "Mostrar las identidades en la página" }, "showIdentitiesCurrentTabDesc": { - "message": "List identity items on the Tab page for easy auto-fill." + "message": "Listar los elementos de identidad en la página para facilitar el auto-rellenado." }, "clearClipboard": { "message": "Vaciar portapapeles", @@ -600,10 +603,10 @@ "message": "Sí, guardar ahora" }, "enableChangedPasswordNotification": { - "message": "Ask to update existing login" + "message": "Solicitar la actualización de los datos de iniciode sesión existentes" }, "changedPasswordNotificationDesc": { - "message": "Ask to update a login's password when a change is detected on a website." + "message": "Solicitar la actualización de los datos de iniciode sesión existentes cuuando se detecte un cambio en un sitio web." }, "notificationChangeDesc": { "message": "¿Desea actualizar esta contraseña en Bitwarden?" @@ -612,10 +615,10 @@ "message": "Actualizado" }, "enableContextMenuItem": { - "message": "Show context menu options" + "message": "Mostrar las opciones de menú contextuales" }, "contextMenuItemDesc": { - "message": "Use a secondary click to access password generation and matching logins for the website. " + "message": "Haga clic con el botón secundario para acceder a la generación de contraseñas y a los inicios de sesión correspondientes al sitio web. " }, "defaultUriMatchDetection": { "message": "Detección por defecto de coincidencia de URI", @@ -807,13 +810,13 @@ "message": "Actualización completada" }, "enableAutoTotpCopy": { - "message": "Copy TOTP automatically" + "message": "Copiar TOTP automáticamente" }, "disableAutoTotpCopyDesc": { "message": "Si tu entrada tiene una clave de autenticación adjunta, el código de verificación TOTP es copiado automáticamente al portapapeles cuando autorellenas una entrada." }, "enableAutoBiometricsPrompt": { - "message": "Ask for biometrics on launch" + "message": "Pedir datos biométricos al ejecutar" }, "premiumRequired": { "message": "Premium requerido" @@ -1034,16 +1037,16 @@ "message": "Este navegador no puede procesar las peticiones U2F en esta ventana emergente. ¿Desea abrir esta ventana emergente en una nueva ventana para que pueda iniciar sesión usando U2F?" }, "enableFavicon": { - "message": "Show website icons" + "message": "Mostrar los iconos del sitio web" }, "faviconDesc": { - "message": "Show a recognizable image next to each login." + "message": "Mostrar una imagen reconocible junto a cada inicio de sesión." }, "enableBadgeCounter": { - "message": "Show badge counter" + "message": "Mostrar el contador numérico" }, "badgeCounterDesc": { - "message": "Indicate how many logins you have for the current web page." + "message": "Indique cuántos inicios de sesión tiene para la página web actual." }, "cardholderName": { "message": "Nombre en la tarjeta" @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Al seleccionar esta casilla, acepta lo siguiente:" }, - "acceptPoliciesError": { - "message": "Todavía no has aceptado los términos del servicio y la política de privacidad." + "acceptPoliciesRequired": { + "message": "No ha aceptado los términos del servicio y la política de privacidad." }, "termsOfService": { "message": "Términos y condiciones del servicio" @@ -1847,7 +1850,7 @@ } }, "vaultTimeoutTooLarge": { - "message": "Your vault timeout exceeds the restrictions set by your organization." + "message": "El tiempo de espera de tu caja fuerte excede las restricciones establecidas por tu organización." }, "vaultExportDisabled": { "message": "Exportación de caja fuerte desactivada" diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json index 9a14970b63a..73e86841cac 100644 --- a/apps/browser/src/_locales/et/messages.json +++ b/apps/browser/src/_locales/et/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "Vigane e-posti aadress." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Vajalik on ülemparooli sisestamine." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Vajalik on ülemparooli uuesti sisestamine." + }, + "masterPasswordMinLength": { "message": "Ülemparool peab olema vähemalt 8 tähemärgi pikkune." }, "masterPassDoesntMatch": { @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "Märkeruudu markeerimisel nõustud järgnevaga:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Kasutustingimuste ja Privaatsuspoliitikaga pole nõustutud." }, "termsOfService": { diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index c76ebdf6c2d..c9da1d80c4d 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Email helbide baliogabea" }, - "masterPassRequired": { - "message": "Pasahitz nagusia derrigorrezkoa da." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Pasahitz nagusiak gutxienez 8 karaktere izan behar ditu." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Pasahitz nagusiaren egiaztatzea ez dator bat." @@ -439,10 +442,10 @@ "message": "Mezu elektroniko bat bidali dizugu zure pasahitz nagusiaren pistarekin." }, "verificationCodeRequired": { - "message": "Egiaztapen-kodea behar da." + "message": "Egiaztatze-kodea behar da." }, "invalidVerificationCode": { - "message": "Egiaztapen-kodea ez da baliozkoa" + "message": "Egiaztatze-kodea ez da baliozkoa" }, "valueCopied": { "message": "$VALUE$ kopiatuta", @@ -488,7 +491,7 @@ "message": "Zure pasahitz nagusia alda dezakezu bitwarden.com webgunean. Orain joan nahi duzu webgunera?" }, "twoStepLoginConfirmation": { - "message": "Bi urratseko egiaztatzea dela eta, zure kontua seguruagoa da, beste aplikazio/gailu batekin saioa hastea eskatzen baitizu; adibidez, segurtasun kode, egiaztatze aplikazio, SMS, telefono dei edo posta elektroniko bidez. Bi urratseko egiaztatzea bitwarden.com webgunean aktibatu daiteke. Orain joan nahi duzu webgunera?" + "message": "Bi urratseko egiaztatzea dela eta, zure kontua seguruagoa da, beste aplikazio/gailu batekin saioa hastea eskatzen baitizu; adibidez, segurtasun kode, baimentze aplikazio, SMS, telefono dei edo posta elektroniko bidez. Bi urratseko egiaztatzea bitwarden.com webgunean aktibatu daiteke. Orain joan nahi duzu webgunera?" }, "editedFolder": { "message": "Karpeta editatuta" @@ -702,13 +705,13 @@ "message": "Gehiago ikasi" }, "authenticatorKeyTotp": { - "message": "Egiaztatze kodea (TOTP)" + "message": "Baimentze kodea (TOTP)" }, "verificationCodeTotp": { "message": "Egiaztatze kodea" }, "copyVerificationCode": { - "message": "Kopiatu egiaztatze kodea" + "message": "Kopiatu egiaztatze-kodea" }, "attachments": { "message": "Eranskinak" @@ -774,7 +777,7 @@ "message": "Pasahitzaren higienea, kontuaren egoera eta datu-bortxaketen txostenak, kutxa gotorra seguru mantentzeko." }, "ppremiumSignUpTotp": { - "message": "TOTP (2FA) egiaztatze kode sortzailea gotor kutxako erregistroetarako." + "message": "TOTP (2FA) egiaztatze-kode sortzailea gotor kutxako erregistroetarako." }, "ppremiumSignUpSupport": { "message": "Lehentasunezko bezeroarentzako arreta." @@ -786,16 +789,16 @@ "message": "Premium erosi" }, "premiumPurchaseAlert": { - "message": "You can purchase premium membership on the bitwarden.com web vault. Do you want to visit the website now?" + "message": "Zure premium bazkidetza bitwarden.com webguneko kutxa gotorrean ordaindu dezakezu. Orain bisitatu nahi duzu webgunea?" }, "premiumCurrentMember": { - "message": "You are a premium member!" + "message": "Premium bazkide zara!" }, "premiumCurrentMemberThanks": { - "message": "Thank you for supporting Bitwarden." + "message": "Eskerrik asko Bitwarden babesteagatik." }, "premiumPrice": { - "message": "All for just $PRICE$ /year!", + "message": "Dena, urtean $PRICE$gatik!", "placeholders": { "price": { "content": "$1", @@ -804,28 +807,28 @@ } }, "refreshComplete": { - "message": "Refresh complete" + "message": "Eguneratzea eginda" }, "enableAutoTotpCopy": { - "message": "Copy TOTP automatically" + "message": "Kopiatu TOTO automatikoki" }, "disableAutoTotpCopyDesc": { - "message": "Saio-hasiera batek egiaztatze kodea badu, TOTP egiaztatze kodea arbelean automatikoki kopiatuko da saio-hasiera bat auto-betetzean." + "message": "Saio-hasiera batek baimentze-kodea badu, TOTP egiaztatze-kodea arbelean automatikoki kopiatuko da saio-hasiera bat auto-betetzean." }, "enableAutoBiometricsPrompt": { - "message": "Ask for biometrics on launch" + "message": "Biometria eskatu saioa hastean" }, "premiumRequired": { - "message": "Premium Required" + "message": "Premium izatea beharrezkoa da" }, "premiumRequiredDesc": { - "message": "A premium membership is required to use this feature." + "message": "Premium bazkidetza beharrezkoa da ezaugarri hau erabiltzeko." }, "enterVerificationCodeApp": { - "message": "Enter the 6 digit verification code from your authenticator app." + "message": "Sartu zure baimentze-aplikazioaren 6 digituko egiaztatze-kodea." }, "enterVerificationCodeEmail": { - "message": "Enter the 6 digit verification code that was emailed to $EMAIL$.", + "message": "Sartu $EMAILA$-era bidalitako 6 digituko egiaztatze-kodea.", "placeholders": { "email": { "content": "$1", @@ -834,7 +837,7 @@ } }, "verificationCodeEmailSent": { - "message": "Verification email sent to $EMAIL$.", + "message": "Egiaztatze emaila $EMAIL$-era bidalia.", "placeholders": { "email": { "content": "$1", @@ -843,10 +846,10 @@ } }, "rememberMe": { - "message": "Remember me" + "message": "Gogora nazazu" }, "sendVerificationCodeEmailAgain": { - "message": "Send verification code email again" + "message": "Berbidali email bidezko egiaztatze-kodea." }, "useAnotherTwoStepMethod": { "message": "Erabili bi urratseko egiaztatzeko beste modu bat." @@ -858,13 +861,13 @@ "message": "Sartu zure segurtasun giltza ordenagailuaren USB portuan. Botoia badu, sakatu ezazu." }, "webAuthnNewTab": { - "message": "To start the WebAuthn 2FA verification. Click the button below to open a new tab and follow the instructions provided in the new tab." + "message": "WebAuthn 2FA egiaztatzea hasteko. Egin klik beheko botoian fitxa berria irekitzeko eta jarraitu fitxa berriko jarraibideei." }, "webAuthnNewTabOpen": { - "message": "Open new tab" + "message": "Ireki fitxa berria" }, "webAuthnAuthenticate": { - "message": "Authenticate WebAuthn" + "message": "WebAuthn baimendu" }, "loginUnavailable": { "message": "Ez dago eskuragarri saio-hasierarik" @@ -873,22 +876,22 @@ "message": "Kontu honek bi urratseko egiaztatzea du gaituta, baina konfiguratutako bi urratseko egiaztatzea ez da web-nabigatzaile honekin bateragarria." }, "noTwoStepProviders2": { - "message": "Please use a supported web browser (such as Chrome) and/or add additional providers that are better supported across web browsers (such as an authenticator app)." + "message": "Mesedez, erabili nabigatzaile bateragarri bat (adibidez, Chrome) eta/edo gehitu bateragarritasun obea duten nabigatzaile bidezko (baimentze-aplikazio gisa) baimentze modu gehigarriak." }, "twoStepOptions": { "message": "Bi urratseko egiaztatzearen aukerak" }, "recoveryCodeDesc": { - "message": "Lost access to all of your two-factor providers? Use your recovery code to disable all two-factor providers from your account." + "message": "Bi urratseko egiaztatzeko modu guztietarako sarbidea galdu duzu? Erabili zure berreskuratze-kodea zure kontuko bi urratseko egiaztatze hornitzaile guztiak desaktibatzeko." }, "recoveryCodeTitle": { - "message": "Recovery Code" + "message": "Berreskuratze-kodea" }, "authenticatorAppTitle": { - "message": "Authenticator App" + "message": "Baimentze aplikazioa" }, "authenticatorAppDesc": { - "message": "Use an authenticator app (such as Authy or Google Authenticator) to generate time-based verification codes.", + "message": "Erabili baimentze-aplikazio bat (adibidez, Authy edo Google Authenticator) denboran oinarritutako egiaztatze-kodeak sortzeko.", "description": "'Authy' and 'Google Authenticator' are product names and should not be translated." }, "yubiKeyTitle": { @@ -898,57 +901,57 @@ "message": "Erabili YubiKey zure kontuan sartzeko. YubiKey 4, 4 Nano, 4C eta NEO gailuekin dabil." }, "duoDesc": { - "message": "Verify with Duo Security using the Duo Mobile app, SMS, phone call, or U2F security key.", + "message": "Egiaztatu Duo Securityrekin Duo Mobile aplikazioa, SMS, telefono deia edo U2F segurtasun-gakoa erabiliz.", "description": "'Duo Security' and 'Duo Mobile' are product names and should not be translated." }, "duoOrganizationDesc": { - "message": "Verify with Duo Security for your organization using the Duo Mobile app, SMS, phone call, or U2F security key.", + "message": "Egiaztatu zure erakunderako Duo Securityrekin Duo Mobile aplikazioa, SMS, telefono deia edo U2F segurtasun-gakoa erabiliz.", "description": "'Duo Security' and 'Duo Mobile' are product names and should not be translated." }, "webAuthnTitle": { "message": "FIDO2 WebAuthn" }, "webAuthnDesc": { - "message": "Use any WebAuthn enabled security key to access your account." + "message": "Erabili gaitutako edozein WebAuthn segurtasun kode zure kontura sartzeko" }, "emailTitle": { - "message": "Email" + "message": "Emaila" }, "emailDesc": { - "message": "Verification codes will be emailed to you." + "message": "Egiaztatze-kodeak email bidez bidaliko dira." }, "selfHostedEnvironment": { - "message": "Self-hosted Environment" + "message": "Ostatze ingurune propioa" }, "selfHostedEnvironmentFooter": { - "message": "Specify the base URL of your on-premises hosted Bitwarden installation." + "message": "Bitwarden instalatzeko, zehaztu ostatze propioaren oinarrizko URL-a." }, "customEnvironment": { - "message": "Custom Environment" + "message": "Ingurune pertsonalizatua" }, "customEnvironmentFooter": { - "message": "For advanced users. You can specify the base URL of each service independently." + "message": "Erabiltzaile aurreratuentzat. Zerbitzu bakoitzarentzako oinarrizko URL-a zehaztu dezakezu independienteki." }, "baseUrl": { - "message": "Server URL" + "message": "Zerbitzariaren URL-a" }, "apiUrl": { - "message": "API Server URL" + "message": "API zerbitzariaren URL-a" }, "webVaultUrl": { - "message": "Web Vault Server URL" + "message": "Web kutxa gotorreko zerbitzariaren URL-a" }, "identityUrl": { - "message": "Identity Server URL" + "message": "Identitate zerbitzariaren URL-a" }, "notificationsUrl": { - "message": "Notifications Server URL" + "message": "Jakinarazpenen zerbitzariaren URL-a" }, "iconsUrl": { - "message": "Icons Server URL" + "message": "Ikonoen zerbitzariaren URL-a" }, "environmentSaved": { - "message": "The environment URLs have been saved." + "message": "Inguruneko URL-ak gorde dira." }, "enableAutoFillOnPageLoad": { "message": "Auto-bete orrialdea kargatzean" @@ -957,7 +960,7 @@ "message": "Saio-hasierako formulario bat detektatzen bada, auto-bete webgunea kargatzen denean." }, "experimentalFeature": { - "message": "This is currently an experimental feature. Use at your own risk." + "message": "Hau ezaugarri esperimental bat da. Zure ardurapean erabili." }, "defaultAutoFillOnPageLoad": { "message": "Saio-hasierako elementuetarako lehenetsitako auto-betetzearen konfigurazioa" @@ -969,7 +972,7 @@ "message": "Auto-bete orrialdea kargatzean (ezarpenetan gaituta badago)" }, "autoFillOnPageLoadUseDefault": { - "message": "Use default setting" + "message": "Erabili ezarpen lehenetsiak" }, "autoFillOnPageLoadYes": { "message": "Auto-bete orrialdea kargatzean" @@ -978,207 +981,207 @@ "message": "Ez auto-bete orrialdea kargatzean" }, "commandOpenPopup": { - "message": "Open vault popup" + "message": "Leiho gainjarrian ireki kutxa gotorra" }, "commandOpenSidebar": { - "message": "Open vault in sidebar" + "message": "Alboko barran ireki kutxa gotorra" }, "commandAutofillDesc": { "message": "Uneko webgunerako erabilitako azken saio-hastea auto-bete" }, "commandGeneratePasswordDesc": { - "message": "Generate and copy a new random password to the clipboard" + "message": "Zorizko pasahitz berria sortu eta kopiatu arbelean" }, "commandLockVaultDesc": { - "message": "Lock the vault" + "message": "Blokeatu kutxa gotorra" }, "privateModeWarning": { - "message": "Private mode support is experimental and some features are limited." + "message": "Modu pribatuko euskarria esperimentala da eta ezaugarri batzuk mugatuak dira." }, "customFields": { - "message": "Custom Fields" + "message": "Eremu pertsonalizatuak" }, "copyValue": { - "message": "Copy Value" + "message": "Kopiatu balioa" }, "value": { - "message": "Value" + "message": "Balioa" }, "newCustomField": { - "message": "New Custom Field" + "message": "Eremu pertsonalizatu berria" }, "dragToSort": { - "message": "Drag to sort" + "message": "Arrastatu txukuntzeko" }, "cfTypeText": { - "message": "Text" + "message": "Testua" }, "cfTypeHidden": { - "message": "Hidden" + "message": "Ezkutatua" }, "cfTypeBoolean": { - "message": "Boolean" + "message": "Boolearra" }, "cfTypeLinked": { - "message": "Linked", + "message": "Lotuta", "description": "This describes a field that is 'linked' (tied) to another field." }, "linkedValue": { - "message": "Linked value", + "message": "Balioa lotuta", "description": "This describes a value that is 'linked' (tied) to another value." }, "popup2faCloseMessage": { - "message": "Clicking outside the popup window to check your email for your verification code will cause this popup to close. Do you want to open this popup in a new window so that it does not close?" + "message": "Leiho gainjarritik kanpora klik eginez gero, zure posta elektronikoa egiaztatzeko leiho gainjarria itxi egingo da. Leiho berri batean ireki nahi duzu leiho gainjarri hau itxi ez dadin?" }, "popupU2fCloseMessage": { - "message": "This browser cannot process U2F requests in this popup window. Do you want to open this popup in a new window so that you can log in using U2F?" + "message": "Nabigatzaile honek ezin ditu U2F eskaerak prozesatu leiho gainjarri honetan. Leiho berri batean ireki nahi duzu leiho gainjarri hau saioa U2F erabiliz hasi ahal izateko?" }, "enableFavicon": { - "message": "Show website icons" + "message": "Erakutsi webguneko ikonoak" }, "faviconDesc": { "message": "Erakutsi irudi bat saio-hasiera bakoitzaren ondoan." }, "enableBadgeCounter": { - "message": "Show badge counter" + "message": "Erakutsi txartelen kontagailua" }, "badgeCounterDesc": { "message": "Adierazi zenbat saio-hasiera dituzun uneko webgunerako." }, "cardholderName": { - "message": "Cardholder Name" + "message": "Txartelaren titularraren izena" }, "number": { - "message": "Number" + "message": "Zenbakia" }, "brand": { - "message": "Brand" + "message": "Marka" }, "expirationMonth": { - "message": "Expiration Month" + "message": "Iraungitze hilabetea" }, "expirationYear": { - "message": "Expiration Year" + "message": "Iraungitze urtea" }, "expiration": { - "message": "Expiration" + "message": "Iraungitze data" }, "january": { - "message": "January" + "message": "Urtarrila" }, "february": { - "message": "February" + "message": "Otsaila" }, "march": { - "message": "March" + "message": "Martxoa" }, "april": { - "message": "April" + "message": "Apirila" }, "may": { - "message": "May" + "message": "Maiatza" }, "june": { - "message": "June" + "message": "Ekaina" }, "july": { - "message": "July" + "message": "Uztaila" }, "august": { - "message": "August" + "message": "Abuztua" }, "september": { - "message": "September" + "message": "Iraila" }, "october": { - "message": "October" + "message": "Urria" }, "november": { - "message": "November" + "message": "Azaroa" }, "december": { - "message": "December" + "message": "Abendua" }, "securityCode": { - "message": "Security Code" + "message": "Segurtasun kodea" }, "ex": { - "message": "ex." + "message": "adib." }, "title": { - "message": "Title" + "message": "Titulua" }, "mr": { - "message": "Mr" + "message": "Jn." }, "mrs": { - "message": "Mrs" + "message": "And." }, "ms": { - "message": "Ms" + "message": "And." }, "dr": { - "message": "Dr" + "message": "Jn." }, "firstName": { - "message": "First Name" + "message": "Izena" }, "middleName": { - "message": "Middle Name" + "message": "Bigarren izena" }, "lastName": { - "message": "Last Name" + "message": "Abizena" }, "fullName": { - "message": "Full Name" + "message": "Izen osoa" }, "identityName": { - "message": "Identity Name" + "message": "Nortasun izena" }, "company": { - "message": "Company" + "message": "Enpresa" }, "ssn": { - "message": "Social Security Number" + "message": "Segurtasun sozialaren zenbakia" }, "passportNumber": { - "message": "Passport Number" + "message": "Pasaporte zenbakia" }, "licenseNumber": { - "message": "License Number" + "message": "Lizentzia zenbakia" }, "email": { - "message": "Email" + "message": "Emaila" }, "phone": { - "message": "Phone" + "message": "Telefonoa" }, "address": { - "message": "Address" + "message": "Helbidea" }, "address1": { - "message": "Address 1" + "message": "1go helbidea" }, "address2": { - "message": "Address 2" + "message": "2. helbidea" }, "address3": { - "message": "Address 3" + "message": "3. helbidea" }, "cityTown": { - "message": "City / Town" + "message": "Hiria / Herria" }, "stateProvince": { - "message": "State / Province" + "message": "Estatua / Probintzia" }, "zipPostalCode": { - "message": "Zip / Postal Code" + "message": "Posta kodea" }, "country": { - "message": "Country" + "message": "Herrialdea" }, "type": { - "message": "Type" + "message": "Mota" }, "typeLogin": { "message": "Saio-hasiera" @@ -1187,53 +1190,53 @@ "message": "Saio-hasierak" }, "typeSecureNote": { - "message": "Secure Note" + "message": "Ohar segurua" }, "typeCard": { - "message": "Card" + "message": "Txartela" }, "typeIdentity": { - "message": "Identity" + "message": "Nortasuna" }, "passwordHistory": { - "message": "Password History" + "message": "Pasahitz historiala" }, "back": { - "message": "Back" + "message": "Itzuli" }, "collections": { - "message": "Collections" + "message": "Bildumak" }, "favorites": { - "message": "Favorites" + "message": "Gogokoak" }, "popOutNewWindow": { - "message": "Pop out to a new window" + "message": "Ireki leiho berrian" }, "refresh": { - "message": "Refresh" + "message": "Freskatu" }, "cards": { - "message": "Cards" + "message": "Txartelak" }, "identities": { - "message": "Identities" + "message": "Nortasunak" }, "logins": { "message": "Saio-hasierak" }, "secureNotes": { - "message": "Secure Notes" + "message": "Ohar seguruak" }, "clear": { - "message": "Clear", + "message": "Ezabatu", "description": "To clear something out. example: To clear browser history." }, "checkPassword": { - "message": "Check if password has been exposed." + "message": "Egiaztatu pasahitza konprometituta dagoen." }, "passwordExposed": { - "message": "This password has been exposed $VALUE$ time(s) in data breaches. You should change it.", + "message": "Pasahitz hau $VALUE$ aldiz datu-iragazketetan aurkitu da. Aldatu egin beharko zenuke.", "placeholders": { "value": { "content": "$1", @@ -1242,28 +1245,28 @@ } }, "passwordSafe": { - "message": "This password was not found in any known data breaches. It should be safe to use." + "message": "Pasahitz hau ez da inongo datu-filtrazio ezagunetan aurkitu. Erabiltzea segurua izan beharko luke." }, "baseDomain": { - "message": "Base domain", + "message": "Oinarrizko domeinua", "description": "Domain name. Ex. website.com" }, "domainName": { - "message": "Domain name", + "message": "Domeinu izena", "description": "Domain name. Ex. website.com" }, "host": { - "message": "Host", + "message": "Ostalaria", "description": "A URL's host value. For example, the host of https://sub.domain.com:443 is 'sub.domain.com:443'." }, "exact": { - "message": "Exact" + "message": "Zehatza" }, "startsWith": { - "message": "Starts with" + "message": "Hasi honekin" }, "regEx": { - "message": "Regular expression", + "message": "Expresio erregularra", "description": "A programming term, also known as 'RegEx'." }, "matchDetection": { @@ -1275,82 +1278,82 @@ "description": "Default URI match detection for auto-fill." }, "toggleOptions": { - "message": "Toggle Options" + "message": "Txandaketa aukerak" }, "toggleCurrentUris": { - "message": "Toggle Current URIs", + "message": "Uneko URI-ak txandakatu", "description": "Toggle the display of the URIs of the currently open tabs in the browser." }, "currentUri": { - "message": "Current URI", + "message": "Uneko URI-a", "description": "The URI of one of the current open tabs in the browser." }, "organization": { - "message": "Organization", + "message": "Erakundea", "description": "An entity of multiple related people (ex. a team or business organization)." }, "types": { - "message": "Types" + "message": "Motak" }, "allItems": { - "message": "All Items" + "message": "Elementu guztiak" }, "noPasswordsInList": { - "message": "There are no passwords to list." + "message": "Ez dago erakusteko pasahitzik." }, "remove": { - "message": "Remove" + "message": "Ezabatu" }, "default": { - "message": "Default" + "message": "Lehenetsia" }, "dateUpdated": { - "message": "Updated", + "message": "Eguneratua", "description": "ex. Date this item was updated" }, "datePasswordUpdated": { - "message": "Password Updated", + "message": "Pasahitza eguneratu da", "description": "ex. Date this password was updated" }, "neverLockWarning": { - "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." + "message": "Ziur zaude \"Inoiz ez\" aukera erabili nahi duzula? Zure blokeo aukerak \"Inoiz ez\" bezala konfiguratzeak kutxa gotorraren zifratze-gakoa gailuan gordetzen du. Aukera hau erabiltzen baduzu, gailua behar bezala babestuta duzula ziurtatu behar duzu." }, "noOrganizationsList": { - "message": "You do not belong to any organizations. Organizations allow you to securely share items with other users." + "message": "Zu ez zara inongo erakundekoa. Erakundeek elementuak beste erabiltzaile batzuekin modu seguruan partekatzeko aukera ematen dute." }, "noCollectionsInList": { - "message": "There are no collections to list." + "message": "Ez dago erakusteko bildumarik." }, "ownership": { - "message": "Ownership" + "message": "Jabetza" }, "whoOwnsThisItem": { - "message": "Who owns this item?" + "message": "Nork du elementu hau?" }, "strong": { - "message": "Strong", + "message": "Sendoa", "description": "ex. A strong password. Scale: Weak -> Good -> Strong" }, "good": { - "message": "Good", + "message": "Ona", "description": "ex. A good password. Scale: Weak -> Good -> Strong" }, "weak": { - "message": "Weak", + "message": "Biguna", "description": "ex. A weak password. Scale: Weak -> Good -> Strong" }, "weakMasterPassword": { - "message": "Weak Master Password" + "message": "Pasahitz nagusi ahula" }, "weakMasterPasswordDesc": { - "message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?" + "message": "Aukeratu duzun pasahitza ahula da. Pasahitz nagusi sendo bat (edo pasaesaldi bat) erabili beharko zenuke Bitwarden kontua behar bezala babesteko. Ziur zaude pasahitz nagusi hau erabili nahi duzula?" }, "pin": { - "message": "PIN", + "message": "PIN-a", "description": "PIN code. Ex. The short code (often numeric) that you use to unlock a device." }, "unlockWithPin": { - "message": "Unlock with PIN" + "message": "PIN-arekin desblokeatu" }, "setYourPinCode": { "message": "Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if you ever fully log out of the application." @@ -1418,7 +1421,7 @@ "message": "Restored Item" }, "vaultTimeoutLogOutConfirmation": { - "message": "Logging out will remove all access to your vault and requires online authentication after the timeout period. Are you sure you want to use this setting?" + "message": "Saioa ixteak kutxa gotorreko sarrera guztia kenduko du eta itxaronaldiaren ondoren lineako baimentzea eskatuko du. Ziur zaude hau egin nahi duzula?" }, "vaultTimeoutLogOutConfirmationTitle": { "message": "Timeout Action Confirmation" @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -1553,7 +1556,7 @@ "message": "Permission request error" }, "nativeMessaginPermissionSidebarDesc": { - "message": "This action cannot be done in the sidebar, please retry the action in the popup or popout." + "message": "Ekintza hau ezin da alboko barran egin. Saiatu berriro leiho gainjarrian edo leiho berri batean." }, "personalOwnershipSubmitError": { "message": "Due to an Enterprise Policy, you are restricted from saving items to your personal vault. Change the Ownership option to an organization and choose from available Collections." @@ -1886,7 +1889,7 @@ "message": "You have left the organization." }, "toggleCharacterCount": { - "message": "Toggle character count" + "message": "Karaktere kontaketak txandakatu" }, "sessionTimeout": { "message": "Your session has timed out. Please go back and try logging in again." diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index f244356988a..c4e92a0a131 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "آدرس ایمیل نامعتبر است." }, - "masterPassRequired": { - "message": "کلمه عبور اصلی ضروری است." + "masterPasswordRequired": { + "message": "گذرواژه اصلی ضروری است." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "تایپ مجدد گذرواژه اصلی نیاز است." + }, + "masterPasswordMinLength": { "message": "طول کلمه عبور اصلی باید حداقل ۸ کاراکتر باشد." }, "masterPassDoesntMatch": { @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "با علامت زدن این کادر با موارد زیر موافقت می کنید:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "شرایط خدمات و سیاست حفظ حریم خصوصی تأیید نشده است." }, "termsOfService": { @@ -1847,7 +1850,7 @@ } }, "vaultTimeoutTooLarge": { - "message": "Your vault timeout exceeds the restrictions set by your organization." + "message": "مهلت زمانی شما بیش از محدودیت های تعیین شده توسط سازمانتان است." }, "vaultExportDisabled": { "message": "صادرات گاوصندوق غیرفعال شده است" diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index 012a4f52b48..c05ec851ee2 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Virheellinen sähköpostiosoite." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Pääsalasana vaaditaan." }, - "masterPassLength": { - "message": "Pääsalasanan on oltava vähintään 8 merkkiä pitkä." + "confirmMasterPasswordRequired": { + "message": "Pääsalasanan uudelleensyöttö vaaditaan." + }, + "masterPasswordMinLength": { + "message": "Pääsalasanan tulee sisältää ainakin 8 merkkiä." }, "masterPassDoesntMatch": { "message": "Pääsalasanan vahvistus ei täsmää." @@ -455,7 +458,7 @@ } }, "autofillError": { - "message": "Valitun kohteen automaattinen täyttö ei onnistu tällä sivulla. Kopioi ja liitä tiedot sen sijaan itse." + "message": "Valitttua kohdetta ei voitu täyttää tälle sivulle automaattisesti. Kopioi ja liitä tiedot itse." }, "loggedOut": { "message": "Kirjauduttu ulos" @@ -1313,7 +1316,7 @@ "description": "ex. Date this password was updated" }, "neverLockWarning": { - "message": "Oletko varma, että haluat käyttää asetusta \"Ei koskaan\"? Tämä valinta tallentaa holvisi salausavaimen laitteellesi. Jos käytät asetusta, varmista että laitteesi on hyvin suojattu." + "message": "Haluatko varmasti käyttää asetusta \"Ei koskaan\"? Se tallentaa holvisi salausavaimen laitteellesi. Jos käytät asetusta, varmista että laite on suojattu hyvin." }, "noOrganizationsList": { "message": "Et kuulu mihinkään organisaatioon. Organisaatioiden avulla voit jakaa kohteita turvallisesti muiden käyttäjien kanssa." @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "Valitsemalla tämän ruudun hyväksyt seuraavat:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Käyttöehtoja ja tietosuojakäytäntöä ei ole vahvistettu." }, "termsOfService": { @@ -1514,7 +1517,7 @@ "message": "Bitwardenin työpöytäsovellus on käynnistettävä ennen kuin biometristä avausta voidaan käyttää." }, "errorEnableBiometricTitle": { - "message": "Biometrian käyttöönotto ei onnistu" + "message": "Biometriaa ei voitu ottaa käyttöön" }, "errorEnableBiometricDesc": { "message": "Työpöytäsovellus perui toiminnon" @@ -1856,7 +1859,7 @@ "message": "Yksi tai useampi organisaation käytäntö estää henkilökohtaisen holvisi viennin." }, "copyCustomFieldNameInvalidElement": { - "message": "Oikeaa lomakkeen elementtiä ei tunnistettu. Yritä sen sijaan HTML-koodin tarkastusta." + "message": "Oikeaa lomakkeen elementtiä ei voitu tunnistaa. Tutki sen sijaan HTML-koodia." }, "copyCustomFieldNameNotUnique": { "message": "Yksilöllistä tunnistetta ei löytynyt." diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json index 779da3b0875..8dc866b2082 100644 --- a/apps/browser/src/_locales/fil/messages.json +++ b/apps/browser/src/_locales/fil/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json index c45ca835d39..fafd9299135 100644 --- a/apps/browser/src/_locales/fr/messages.json +++ b/apps/browser/src/_locales/fr/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Adresse e-mail invalide." }, - "masterPassRequired": { - "message": "Le mot de passe maître est requis." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Le mot de passe maître doit au moins contenir 8 caractères." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "La confirmation du mot de passe maître ne correspond pas." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "En cochant cette case, vous acceptez les éléments suivants :" }, - "acceptPoliciesError": { - "message": "Les conditions d'utilisation et la politique de confidentialité n'ont pas été acceptées." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Conditions d'utilisation" diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json index 7449dc8a77d..f57010e5569 100644 --- a/apps/browser/src/_locales/he/messages.json +++ b/apps/browser/src/_locales/he/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "כתובת אימייל לא תקינה." }, - "masterPassRequired": { - "message": "יש להזין את הסיסמה הראשית." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "הסיסמה הראשית חייבת להיות לפחות באורך 8 תווים." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "שדה אימות סיסמה ראשית לא תואם." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "סימון תיבה זו מהווה את הסכמתך לתנאים הבאים:" }, - "acceptPoliciesError": { - "message": "תנאי השירות ומדיניות הפרטיות לא אושרו." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "תנאי השירות" diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json index 238d3c73232..295e2adad82 100644 --- a/apps/browser/src/_locales/hi/messages.json +++ b/apps/browser/src/_locales/hi/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "अमान्य ई-मेल |" }, - "masterPassRequired": { - "message": "मास्टर पासवर्ड की आवश्यकता है।" + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "मास्टर पासवर्ड कम से कम 8 अक्षर लंबे होने चाहिए।" + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "मास्टर पासवर्ड पुष्टि मेल नहीं खाती है।" @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "इस बॉक्स की जांच करके आप निम्नलिखित से सहमत हैं:" }, - "acceptPoliciesError": { - "message": "सेवा और गोपनीयता नीति की शर्तों को स्वीकार नहीं किया गया है ।" + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "सेवा की शर्तें" diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json index b9648605c26..40d45316301 100644 --- a/apps/browser/src/_locales/hr/messages.json +++ b/apps/browser/src/_locales/hr/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Neispravna adresa e-pošte." }, - "masterPassRequired": { - "message": "Potrebna je glavna lozinka." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Glavna lozinka mora imati najmanje 8 znakova." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Potvrda glavne lozinke se ne podudara." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Označavanjem ove kućice slažete se sa sljedećim:" }, - "acceptPoliciesError": { - "message": "Uvjeti korištenja i Pravila privatnosti nisu prihvaćeni." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Uvjeti korištenja" diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json index ac6940136af..3e15b3095fb 100644 --- a/apps/browser/src/_locales/hu/messages.json +++ b/apps/browser/src/_locales/hu/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Érvénytelen email cím." }, - "masterPassRequired": { - "message": "Mesterjelszó megadása kötelező." + "masterPasswordRequired": { + "message": "A mesterjelszó megadása kötelező." }, - "masterPassLength": { - "message": "Mesterjelszónak legalább 8 karakter hosszúnak kell lennie." + "confirmMasterPasswordRequired": { + "message": "A mesterjelszó ismételt megadása kötelező." + }, + "masterPasswordMinLength": { + "message": "A mesterjelszó legyen legalább 8 karakter hosszú." }, "masterPassDoesntMatch": { "message": "A megadott két jelszó nem egyezik meg." @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "A doboz bejelölésével elfogadjuk a következőket:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "A szolgáltatási feltételeket és az adatvédelmi irányelveket nem vették figyelembe." }, "termsOfService": { diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json index e8e338c1674..429117d8b5a 100644 --- a/apps/browser/src/_locales/id/messages.json +++ b/apps/browser/src/_locales/id/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Alamat email tidak valid." }, - "masterPassRequired": { - "message": "Sandi utama diperlukan." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Kata sandi utama sedikitnya harus 8 karakter." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Konfirmasi sandi utama tidak cocok." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Dengan mencentang kotak ini, Anda menyetujui yang berikut:" }, - "acceptPoliciesError": { - "message": "Persyaratan Layanan dan Kebijakan Privasi belum disetujui." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Persyaratan Layanan" diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index ab6da9e057d..b87de23921f 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Indirizzo email non valido." }, - "masterPassRequired": { - "message": "La password principale è obbligatoria." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "La password principale deve essere lunga almeno 8 caratteri." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "La conferma della password principale non corrisponde." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Selezionando la casella accetti quanto segue:" }, - "acceptPoliciesError": { - "message": "I termini di servizio e l'informativa sulla privacy non sono stati accettati." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Termini del servizio" diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index f61b3f6b5ef..fff327d59af 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "無効なEメールアドレスです。" }, - "masterPassRequired": { - "message": "マスターパスワードは必須です。" + "masterPasswordRequired": { + "message": "マスターパスワードが必要です。" }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "マスターパスワードの再入力が必要です。" + }, + "masterPasswordMinLength": { "message": "マスターパスワードは、少なくとも8文字以上で設定してください。" }, "masterPassDoesntMatch": { @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "以下に同意しチェックします:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "利用規約とプライバシーポリシーを確認してください。" }, "termsOfService": { diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json index d45e8468364..73b0a57d087 100644 --- a/apps/browser/src/_locales/ka/messages.json +++ b/apps/browser/src/_locales/ka/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "არასწორი ელექტრო ფოსტის მისამართი." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json index 63464b4de8f..baa4e0066c3 100644 --- a/apps/browser/src/_locales/km/messages.json +++ b/apps/browser/src/_locales/km/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json index cbf71f2f6cc..ac7a52292a4 100644 --- a/apps/browser/src/_locales/kn/messages.json +++ b/apps/browser/src/_locales/kn/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "ಅಮಾನ್ಯ ಇಮೇಲ್ ವಿಳಾಸ." }, - "masterPassRequired": { - "message": "ಮಾಸ್ಟರ್ ಪಾಸ್ವರ್ಡ್ ಅಗತ್ಯವಿದೆ." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "ಮಾಸ್ಟರ್ ಪಾಸ್‌ವರ್ಡ್ ಕನಿಷ್ಠ 8 ಅಕ್ಷರಗಳಷ್ಟು ಉದ್ದವಾಗಿರಬೇಕು." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "ಮಾಸ್ಟರ್ ಪಾಸ್‌ವರ್ಡ್ ದೃಢೀಕರಣವು ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "ಈ ಪೆಟ್ಟಿಗೆಯನ್ನು ಪರಿಶೀಲಿಸುವ ಮೂಲಕ ನೀವು ಈ ಕೆಳಗಿನವುಗಳನ್ನು ಒಪ್ಪುತ್ತೀರಿ:" }, - "acceptPoliciesError": { - "message": "ಸೇವಾ ನಿಯಮಗಳು ಮತ್ತು ಗೌಪ್ಯತೆ ನೀತಿಯನ್ನು ಅಂಗೀಕರಿಸಲಾಗಿಲ್ಲ." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "ಸೇವಾ ನಿಯಮಗಳು" diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index 6cf1a1331af..0225cf55cb1 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "잘못된 이메일 주소입니다." }, - "masterPassRequired": { - "message": "마스터 비밀번호는 반드시 입력해야 합니다." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "마스터 비밀번호는 최소 8자 이상이어야 합니다." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "마스터 비밀번호 확인과 마스터 비밀번호가 일치하지 않습니다." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "이 박스를 체크하면 다음에 동의하는 것으로 간주됩니다:" }, - "acceptPoliciesError": { - "message": "서비스 약관 및 개인 정보 보호 정책을 확인하지 않았습니다." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "서비스 약관" diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json index b488de31869..5a1a8c068da 100644 --- a/apps/browser/src/_locales/lt/messages.json +++ b/apps/browser/src/_locales/lt/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Klaidingas el. pašto adresas." }, - "masterPassRequired": { - "message": "Būtinas pagrindinis slaptažodis." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Pagrindinis slaptažodis turi būti bent 8 simbolių ilgio." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Pagrindinio slaptažodžio patvirtinimas nesutampa." @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index bbf814b33db..b2b99963a01 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Nederīga e-pasta adrese." }, - "masterPassRequired": { - "message": "Galvenā parole ir nepieciešama." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Galvenajai parolei ir jābūt vismaz 8 rakstzīmes garai." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Galvenās paroles apstiprinājums nesakrīt." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Atzīmējot šo rūtiņu, Tu piekrīti sekojošajam:" }, - "acceptPoliciesError": { - "message": "Nav pieņemti izmantošanas nosacījumi un privātuma politika." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Izmantošanas nosacījumi" diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json index 4829546df1f..4df220a001c 100644 --- a/apps/browser/src/_locales/ml/messages.json +++ b/apps/browser/src/_locales/ml/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "അസാധുവായ ഇമെയിൽ." }, - "masterPassRequired": { - "message": "പ്രാഥമിക പാസ്‌വേഡ് നിർബന്ധമാണ്‌." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "പ്രാഥമിക പാസ്‌വേഡിന് കുറഞ്ഞത് 8 പ്രതീകങ്ങളെങ്കിലും ദൈർഘ്യമുണ്ടായിരിക്കണം." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "പ്രാഥമിക പാസ്‌വേഡ് സ്ഥിരീകരണം പൊരുത്തപ്പെടുന്നില്ല." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "ഈ ബോക്സ് ചെക്കുചെയ്യുന്നതിലൂടെ നിങ്ങൾ ഇനിപ്പറയുന്നവ അംഗീകരിക്കുന്നു:" }, - "acceptPoliciesError": { - "message": "സേവന നിബന്ധനകളും സ്വകാര്യതാ നയവും അംഗീകരിച്ചിട്ടില്ല." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "സേവന നിബന്ധനകൾ" diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json index f2be7e9a821..a57ffcffb47 100644 --- a/apps/browser/src/_locales/nb/messages.json +++ b/apps/browser/src/_locales/nb/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Ugyldig E-postadresse." }, - "masterPassRequired": { - "message": "Superpassordet er påkrevd." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Superpassordet må være ≥8 tegn lang." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Superpassord-bekreftelsen er ikke samsvarende." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Ved å merke av denne boksen sier du deg enig i følgende:" }, - "acceptPoliciesError": { - "message": "Vilkårene for bruk og personvernerklæring er ikke akseptert." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Vilkår for bruk" diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json index cc9e53fb97f..039b183ad00 100644 --- a/apps/browser/src/_locales/nl/messages.json +++ b/apps/browser/src/_locales/nl/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Ongeldig e-mailadres." }, - "masterPassRequired": { - "message": "Hoofdwachtwoord is vereist." + "masterPasswordRequired": { + "message": "Hoofdwachtwoord vereist." }, - "masterPassLength": { - "message": "Hoofdwachtwoord moet minstens 8 tekens lang zijn." + "confirmMasterPasswordRequired": { + "message": "Type je hoofdwachtwoord opnieuw in." + }, + "masterPasswordMinLength": { + "message": "Hoofdwachtwoord moet minimaal 8 tekens lang zijn." }, "masterPassDoesntMatch": { "message": "De hoofdwachtwoorden komen niet overeen." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Door dit vakje aan te vinken, ga je akkoord met het volgende:" }, - "acceptPoliciesError": { - "message": "Algemene voorwaarden en privacybeleid zijn nog niet erkend." + "acceptPoliciesRequired": { + "message": "Je hebt de algemene voorwaarden en het privacybeleid nog niet erkend." }, "termsOfService": { "message": "Algemene voorwaarden" diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json index 63464b4de8f..baa4e0066c3 100644 --- a/apps/browser/src/_locales/nn/messages.json +++ b/apps/browser/src/_locales/nn/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index 893aee37c3f..86470ec1681 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "Adres e-mail jest nieprawidłowy." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Hasło główne jest wymagane." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Wymagane jest ponowne wpisanie hasła głównego." + }, + "masterPasswordMinLength": { "message": "Hasło główne musi zawierać co najmniej 8 znaków." }, "masterPassDoesntMatch": { @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Zaznaczając tę opcję, akceptujesz:" }, - "acceptPoliciesError": { - "message": "Nie zaakceptowałeś regulaminu i polityki prywatności." + "acceptPoliciesRequired": { + "message": "Warunki użytkowania i polityka prywatności nie zostały zaakceptowane." }, "termsOfService": { "message": "Regulamin" diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index d16802f3297..be6d0c6e76d 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Endereço de e-mail inválido." }, - "masterPassRequired": { - "message": "A senha mestra é obrigatória." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "A senha mestra deve ter pelo menos 8 caracteres." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "A confirmação da senha mestra não corresponde." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Ao marcar esta caixa, você concorda com o seguinte:" }, - "acceptPoliciesError": { - "message": "Os Termos de Serviço e a Política de Privacidade não foram reconhecidos." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Termos de Serviço" diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json index 407c1933a55..0eaf4d50a5f 100644 --- a/apps/browser/src/_locales/pt_PT/messages.json +++ b/apps/browser/src/_locales/pt_PT/messages.json @@ -52,9 +52,15 @@ "tab": { "message": "Separador" }, + "vault": { + "message": "Cofre" + }, "myVault": { "message": "Meu cofre" }, + "allVaults": { + "message": "Todos os Cofres" + }, "tools": { "message": "Ferramentas" }, @@ -89,16 +95,16 @@ "message": "Gerar palavra-passe (copiada)" }, "copyElementIdentifier": { - "message": "Copy Custom Field Name" + "message": "Copiar nome do campo personalizado" }, "noMatchingLogins": { "message": "Sem credencias correspondidas." }, - "vaultLocked": { - "message": "O cofre está bloqueado." + "unlockVaultMenu": { + "message": "Desbloqueie o seu cofre" }, - "vaultLoggedOut": { - "message": "Sessão terminada no cofre." + "loginToVaultMenu": { + "message": "Inicie sessão para abrir o seu cofre" }, "autoFillInfo": { "message": "Não existem credenciais disponíveis para auto-preencher para o separador de navegador atual." @@ -121,14 +127,26 @@ "continue": { "message": "Continuar" }, + "sendVerificationCode": { + "message": "Envie um código de verificação para o seu e-mail" + }, + "sendCode": { + "message": "Enviar o código" + }, + "codeSent": { + "message": "Código enviado" + }, "verificationCode": { "message": "Código de verificação" }, + "confirmIdentity": { + "message": "Confirme a sua identidade para continuar." + }, "account": { "message": "Conta" }, "changeMasterPassword": { - "message": "Alterar palavra-passe mestra" + "message": "Alterar Palavra-passe Mestra" }, "fingerprintPhrase": { "message": "Frase de impressão digital", @@ -139,10 +157,10 @@ "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "twoStepLogin": { - "message": "Início de sessão de dois passos" + "message": "Início de Sessão de Dois Passos" }, "logOut": { - "message": "Terminar sessão" + "message": "Terminar Sessão" }, "about": { "message": "Acerca" @@ -154,7 +172,7 @@ "message": "Guardar" }, "move": { - "message": "Move" + "message": "Mover" }, "addFolder": { "message": "Adicionar pasta" @@ -217,6 +235,18 @@ "length": { "message": "Comprimento" }, + "uppercase": { + "message": "Maiúsculas (A-Z)" + }, + "lowercase": { + "message": "Minúsculas (a-z)" + }, + "numbers": { + "message": "Números (0-9)" + }, + "specialCharacters": { + "message": "Caracteres Especiais (!@#$%^&*)" + }, "numWords": { "message": "Número de palavras" }, @@ -308,8 +338,8 @@ "browserNotSupportClipboard": { "message": "O seu navegador web não suporta cópia fácil da área de transferência. Em alternativa, copie manualmente." }, - "verifyMasterPassword": { - "message": "Verificar palavra-passe mestra" + "verifyIdentity": { + "message": "Verificar Identidade" }, "yourVaultIsLocked": { "message": "O seu cofre está bloqueado. Verifique a sua palavra-passe mestra para continuar." @@ -376,7 +406,7 @@ "message": "Quando o sistema está bloqueado" }, "onRestart": { - "message": "Quando reiniciar o navegador" + "message": "Ao reiniciar o sistema" }, "never": { "message": "Nunca" @@ -393,11 +423,14 @@ "invalidEmail": { "message": "Endereço de email inválido." }, - "masterPassRequired": { - "message": "A palavra-passe mestra é requerida." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "A palavra-passe mestra tem de ter pelo menos 8 caracteres." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "A confirmação da palavra-passe mestra não corresponde." @@ -411,6 +444,9 @@ "verificationCodeRequired": { "message": "O código de verificação é requerido." }, + "invalidVerificationCode": { + "message": "Código de verificação inválido" + }, "valueCopied": { "message": "$VALUE$ copiado(a)", "description": "Value has been copied to the clipboard.", @@ -515,6 +551,12 @@ "overwritePasswordConfirmation": { "message": "Tem a certeza de que pretende sobreescrever a palavra-passe atual?" }, + "overwriteUsername": { + "message": "Sobrescrever Nome de Utilizador" + }, + "overwriteUsernameConfirmation": { + "message": "Tem a certeza de que deseja sobrescrever o nome de utilizador atual?" + }, "searchFolder": { "message": "Pesquisar pasta" }, @@ -528,23 +570,23 @@ "message": "Nenhuma pasta", "description": "This is the folder for uncategorized items" }, - "disableAddLoginNotification": { - "message": "Desativar notificação de adicionar credencial" + "enableAddLoginNotification": { + "message": "Ask to add login" }, "addLoginNotificationDesc": { "message": "A \"notificação de adicionar credencial\" solicita-lhe automaticamente a guardar novas credenciais para o seu cofre quando inicia sessão nas mesmas pela primeira vez." }, - "dontShowCardsCurrentTab": { - "message": "Não mostrar cartões na página do separador" + "showCardsCurrentTab": { + "message": "Show cards on Tab page" }, - "dontShowCardsCurrentTabDesc": { - "message": "Os itens de cartões do seu cofre estão listados na página 'Separador atual' para acesso de auto-preenchimento fácil." + "showCardsCurrentTabDesc": { + "message": "List card items on the Tab page for easy auto-fill." }, - "dontShowIdentitiesCurrentTab": { - "message": "Não mostrar identidades na página do separador" + "showIdentitiesCurrentTab": { + "message": "Show identities on Tab page" }, - "dontShowIdentitiesCurrentTabDesc": { - "message": "Os itens de identidades do seu cofre estão listados na página 'Separador atual' para acesso de auto-preenchimento fácil." + "showIdentitiesCurrentTabDesc": { + "message": "List identity items on the Tab page for easy auto-fill." }, "clearClipboard": { "message": "Limpar área de transferência", @@ -560,14 +602,11 @@ "notificationAddSave": { "message": "Sim, guardar agora" }, - "notificationNeverSave": { - "message": "Nunca para este site" + "enableChangedPasswordNotification": { + "message": "Ask to update existing login" }, - "disableChangedPasswordNotification": { - "message": "Desativar notificação de palavra-passe alterada" - }, - "disableChangedPasswordNotificationDesc": { - "message": "A \"notificação de palavra-passe alterada\" solicita-lhe automaticamente para atualizar a palavra-passe de uma credencial no seu cofre quando deteta que a alterou num website." + "changedPasswordNotificationDesc": { + "message": "Ask to update a login's password when a change is detected on a website." }, "notificationChangeDesc": { "message": "Pretende atualizar esta palavra-passe no Bitwarden?" @@ -575,11 +614,11 @@ "notificationChangeSave": { "message": "Sim, atualizar agora" }, - "disableContextMenuItem": { - "message": "Desativar opções do menu de contexto" + "enableContextMenuItem": { + "message": "Show context menu options" }, - "disableContextMenuItemDesc": { - "message": "As opções do menu de contexto providenciam acesso rápido à geração de palavras-passe e credenciais para o website no seu separador atual." + "contextMenuItemDesc": { + "message": "Use a secondary click to access password generation and matching logins for the website. " }, "defaultUriMatchDetection": { "message": "Deteção de correspondência de URI predefinida", @@ -603,7 +642,7 @@ "description": "Light color" }, "solarizedDark": { - "message": "Solarized Dark", + "message": "Solarized escuro", "description": "'Solarized' is a noun and the name of a color scheme. It should not be translated." }, "exportVault": { @@ -617,16 +656,16 @@ "description": "WARNING (should stay in capitalized letters if the language permits)" }, "confirmVaultExport": { - "message": "Confirm Vault Export" + "message": "Confirmar exportação de cofre" }, "exportWarningDesc": { "message": "Esta exportação contém os seus dados do cofre num formato desencriptado. Não deve armazenar ou enviar o ficheiro exportado através de canais inseguros (como email). Apague-a imediatamente após a utilizar." }, "encExportKeyWarningDesc": { - "message": "This export encrypts your data using your account's encryption key. If you ever rotate your account's encryption key you should export again since you will not be able to decrypt this export file." + "message": "Esta exportação cifra os seus dados utilizando a chave de cifragem da sua conta. Se alguma vez mudar a chave de cifragem da sua conta, deve fazer a exportação novamente, já que não conseguirá decifrar este ficheiro de exportação." }, "encExportAccountWarningDesc": { - "message": "Account encryption keys are unique to each Bitwarden user account, so you can't import an encrypted export into a different account." + "message": "As chaves de encriptação de conta são únicas para cada conta de utilizador Bitwarden, pelo que não se pode importar uma exportação encriptada para uma conta diferente." }, "exportMasterPassword": { "message": "Introduza a sua palavra-passe mestra para exportar os dados do seu cofre." @@ -635,19 +674,19 @@ "message": "Partilhado" }, "learnOrg": { - "message": "Learn about Organizations" + "message": "Saiba mais sobre as Organizações" }, "learnOrgConfirmation": { - "message": "Bitwarden allows you to share your vault items with others by using an organization. Would you like to visit the bitwarden.com website to learn more?" + "message": "O Bitwarden permite que você compartilhe os itens do seu cofre com outras pessoas usando uma organização. Gostaria de visitar o site bitwarden.com para saber mais?" }, "moveToOrganization": { - "message": "Move to Organization" + "message": "Mudança para Organização" }, "share": { "message": "Partilhar" }, "movedItemToOrg": { - "message": "$ITEMNAME$ moved to $ORGNAME$", + "message": "$ITEMNAME$ movido para $ORGNAME$", "placeholders": { "itemname": { "content": "$1", @@ -660,7 +699,7 @@ } }, "moveToOrgDesc": { - "message": "Choose an organization that you wish to move this item to. Moving to an organization transfers ownership of the item to that organization. You will no longer be the direct owner of this item once it has been moved." + "message": "Escolha uma organização para a qual deseja mover este item. A mudança para uma organização transfere a propriedade do item para essa organização. Deixará de ser o proprietário directo deste item uma vez que tenha sido movido." }, "learnMore": { "message": "Saber mais" @@ -770,14 +809,14 @@ "refreshComplete": { "message": "Atualização completada" }, - "disableAutoTotpCopy": { - "message": "Desativar cópia automática de TOTP" + "enableAutoTotpCopy": { + "message": "Copy TOTP automatically" }, "disableAutoTotpCopyDesc": { - "message": "Se a sua credencial tem uma chave de autenticador anexada à mesma, o código de verificação TOTP é copiado automaticamente para a sua área de transferência quando quer que auto-preencha a credencial." + "message": "Se o seu início de sessão tem uma chave de autenticador anexada ao mesmo, o código de verificação TOTP é copiado automaticamente para a sua área de transferência quando quer que auto-preencha o início de sessão." }, - "disableAutoBiometricsPrompt": { - "message": "Do not prompt for biometrics on launch" + "enableAutoBiometricsPrompt": { + "message": "Ask for biometrics on launch" }, "premiumRequired": { "message": "Premium requerido" @@ -822,13 +861,13 @@ "message": "Introduza a sua chave de segurança na porta USB do seu computador. Se tiver um botão, toque no mesmo." }, "webAuthnNewTab": { - "message": "To start the WebAuthn 2FA verification. Click the button below to open a new tab and follow the instructions provided in the new tab." + "message": "Para iniciar a verificação WebAuthn 2FA. Clique no botão abaixo para abrir um novo separador e siga as instruções fornecidas no novo separador." }, "webAuthnNewTabOpen": { - "message": "Open new tab" + "message": "Abrir novo separador" }, "webAuthnAuthenticate": { - "message": "Authenticate WebAuthn" + "message": "Autenticar WebAuthn" }, "loginUnavailable": { "message": "Início de sessão indisponível" @@ -873,7 +912,7 @@ "message": "FIDO2 WebAuthn" }, "webAuthnDesc": { - "message": "Use any WebAuthn enabled security key to access your account." + "message": "Utilize qualquer chave de segurança ativada pela WebAuthn para aceder à sua conta." }, "emailTitle": { "message": "Email" @@ -918,28 +957,28 @@ "message": "Ativar auto-preenchimento no carregar da página" }, "enableAutoFillOnPageLoadDesc": { - "message": "Se um formulário de início de sessão for detetado, realizar automaticamente um auto-preenchimento quando a página web carregar." + "message": "Se um formulário de início de sessão foram detetado, realizar automaticamente um auto-preenchimento quando a página web carregar." }, "experimentalFeature": { "message": "Esta é atualmente uma funcionalidade experimental. Utilize por sua conta e risco." }, "defaultAutoFillOnPageLoad": { - "message": "Default autofill setting for login items" + "message": "Predefinição padrão de preenchimento automático para itens de login" }, "defaultAutoFillOnPageLoadDesc": { - "message": "After enabling Auto-fill on Page Load, you can enable or disable the feature for individual login items. This is the default setting for login items that are not separately configured." + "message": "Depois de activar o preenchimento automático no carregamento da página, pode activar ou desactivar a função de itens de início de sessão individuais. Esta é a configuração padrão para os itens de início de sessão que não estão configurados separadamente." }, "itemAutoFillOnPageLoad": { - "message": "Auto-fill on Page Load (if enabled in Options)" + "message": "Preenchimento automático no carregamento da página (se ativado em Opções)" }, "autoFillOnPageLoadUseDefault": { - "message": "Use default setting" + "message": "Usar padrão" }, "autoFillOnPageLoadYes": { - "message": "Auto-fill on page load" + "message": "Preenchimento automático na carga da página" }, "autoFillOnPageLoadNo": { - "message": "Do not auto-fill on page load" + "message": "Não preencher automaticamente no carregamento da página" }, "commandOpenPopup": { "message": "Abrir popup do cofre" @@ -956,8 +995,8 @@ "commandLockVaultDesc": { "message": "Bloquear o cofre" }, - "privateModeMessage": { - "message": "Infelizmente esta janela não está disponível no modo privado para este navegador." + "privateModeWarning": { + "message": "O suporte do modo privado é experimental e alguns recursos são limitados." }, "customFields": { "message": "Campos personalizados" @@ -983,23 +1022,31 @@ "cfTypeBoolean": { "message": "Booleano" }, + "cfTypeLinked": { + "message": "Ligado", + "description": "This describes a field that is 'linked' (tied) to another field." + }, + "linkedValue": { + "message": "Valor vinculado", + "description": "This describes a value that is 'linked' (tied) to another value." + }, "popup2faCloseMessage": { "message": "Clicar fora da janela popup para verificar o seu email pelo código de verificação irá causar com que este popup feche. Deseja abrir este popup numa nova janela para que este não se feche?" }, "popupU2fCloseMessage": { "message": "Este navegador não pode processar solicitações U2F nesta janela popup. Pretende abrir este popup numa nova janela para que inicie sessão utilizando U2F?" }, - "disableFavicon": { - "message": "Desativar ícones de websites" + "enableFavicon": { + "message": "Show website icons" }, - "disableFaviconDesc": { - "message": "Os ícones de websites providenciam uma imagem reconhecível ao lado de cada item de credencial no seu cofre." + "faviconDesc": { + "message": "Show a recognizable image next to each login." }, - "disableBadgeCounter": { - "message": "Disable Badge Counter" + "enableBadgeCounter": { + "message": "Show badge counter" }, - "disableBadgeCounterDesc": { - "message": "Badge counter indicates how many logins you have for the current page in your vault." + "badgeCounterDesc": { + "message": "Indicate how many logins you have for the current web page." }, "cardholderName": { "message": "Titular do cartão" @@ -1085,6 +1132,9 @@ "lastName": { "message": "Último nome" }, + "fullName": { + "message": "Nome Completo" + }, "identityName": { "message": "Nome de identidade" }, @@ -1198,7 +1248,12 @@ "message": "Esta palavra-passe não foi encontrada em nenhuma brecha de dados conhecida. Esta deve ser segura de utilizar." }, "baseDomain": { - "message": "Domínio base" + "message": "Domínio base", + "description": "Domain name. Ex. website.com" + }, + "domainName": { + "message": "Nome do Domínio", + "description": "Domain name. Ex. website.com" }, "host": { "message": "Servidor", @@ -1257,7 +1312,7 @@ "description": "ex. Date this item was updated" }, "datePasswordUpdated": { - "message": "Palavra passe atualizada", + "message": "Palavra-passe atualizada", "description": "ex. Date this password was updated" }, "neverLockWarning": { @@ -1309,20 +1364,14 @@ "invalidPin": { "message": "Código PIN inválido." }, - "verifyPin": { - "message": "Verificar PIN" - }, - "yourVaultIsLockedPinCode": { - "message": "O seu cofre está bloqueado. Verifique o seu PIN para continuar." - }, "unlockWithBiometrics": { - "message": "Unlock with biometrics" + "message": "Desbloquear com biométricos" }, "awaitDesktop": { - "message": "Awaiting confirmation from desktop" + "message": "A aguardar confirmação do seu computador" }, "awaitDesktopDesc": { - "message": "Please confirm using biometrics in the Bitwarden Desktop application to enable biometrics for browser." + "message": "Por favor, confirme o uso de dados biométricos na aplicação Bitwarden Desktop para habilitar os dados biométricos do navegador." }, "lockWithMasterPassOnRestart": { "message": "Bloquear com palavra-passe mestra quando reiniciar o navegador" @@ -1434,8 +1483,8 @@ "acceptPolicies": { "message": "Ao marcar esta caixa concorda com o seguinte:" }, - "acceptPoliciesError": { - "message": "Os Termos de Serviço e a Política de Privacidade não foram aceites." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Termos de serviço" @@ -1444,28 +1493,28 @@ "message": "Política de privacidade" }, "hintEqualsPassword": { - "message": "Your password hint cannot be the same as your password." + "message": "A dica da sua senha não pode ser igual à senha." }, "ok": { "message": "Ok" }, "desktopSyncVerificationTitle": { - "message": "Desktop sync verification" + "message": "Verificação de sincronização do ambiente de trabalho" }, "desktopIntegrationVerificationText": { - "message": "Please verify that the desktop application shows this fingerprint: " + "message": "Por favor, verifique se a aplicação no computador mostra esta impressão digital: " }, "desktopIntegrationDisabledTitle": { - "message": "Browser integration is not enabled" + "message": "Integração com o navegador não está ativada" }, "desktopIntegrationDisabledDesc": { - "message": "Browser integration is not enabled in the Bitwarden Desktop application. Please enable it in the settings within the desktop application." + "message": "A integração com o navegador não está habilitada no aplicativo Bitwarden Desktop. Por favor, habilite-o nas configurações da aplicação para computador." }, "startDesktopTitle": { - "message": "Start the Bitwarden Desktop application" + "message": "Iniciar a aplicação Bitwarden Desktop" }, "startDesktopDesc": { - "message": "The Bitwarden Desktop application needs to be started before this function can be used." + "message": "The Bitwarden Desktop application needs to be started before unlock with biometrics can be used." }, "errorEnableBiometricTitle": { "message": "Unable to enable biometrics" @@ -1516,7 +1565,7 @@ "message": "An organization policy is affecting your ownership options." }, "excludedDomains": { - "message": "Excluded Domains" + "message": "Excluded domains" }, "excludedDomainsDesc": { "message": "Bitwarden will not ask to save login details for these domains. You must refresh the page for changes to take effect." @@ -1531,15 +1580,15 @@ } }, "send": { - "message": "Send", + "message": "Envio", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "searchSends": { - "message": "Search Sends", + "message": "Pesquisar Envios", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "addSend": { - "message": "Add Send", + "message": "Adicionar Envio", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendTypeText": { @@ -1549,20 +1598,21 @@ "message": "Ficheiro" }, "allSends": { - "message": "All Sends", + "message": "Todos os Envios", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "maxAccessCountReached": { - "message": "Max access count reached" + "message": "Número de acessos máximo atingido", + "description": "This text will be displayed after a Send has been accessed the maximum amount of times." }, "expired": { - "message": "Expired" + "message": "Expirado" }, "pendingDeletion": { - "message": "Pending deletion" + "message": "Remoção pendente" }, "passwordProtected": { - "message": "Password protected" + "message": "Protegido por senha" }, "copySendLink": { "message": "Copiar Send link", @@ -1575,47 +1625,47 @@ "message": "Eliminar" }, "removedPassword": { - "message": "Palavra-passe removida" + "message": "Senha removida" }, "deletedSend": { - "message": "Deleted Send", + "message": "Envio eliminado", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendLink": { - "message": "Send link", + "message": "Link de Envio", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "disabled": { - "message": "Disabled" + "message": "Desabilitado" }, "removePasswordConfirmation": { - "message": "Are you sure you want to remove the password?" + "message": "Tem a certeza que pretende remover a senha?" }, "deleteSend": { - "message": "Delete Send", + "message": "Eliminar Envio", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "deleteSendConfirmation": { - "message": "Are you sure you want to delete this Send?", + "message": "Tem a certeza que pretende eliminar este Envio?", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editSend": { - "message": "Edit Send", + "message": "Editar Envio", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendTypeHeader": { - "message": "What type of Send is this?", + "message": "Que tipo de Envio é este?", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendNameDesc": { - "message": "A friendly name to describe this Send.", + "message": "Um nome amigável para descrever este Envio.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendFileDesc": { - "message": "The file you want to send." + "message": "O ficheiro que deseja enviar." }, "deletionDate": { - "message": "Deletion Date" + "message": "Data de eliminação" }, "deletionDateDesc": { "message": "The Send will be permanently deleted on the specified date and time.", @@ -1709,37 +1759,37 @@ "message": "In order to choose a file using Safari, pop out to a new window by clicking this banner." }, "sendFileCalloutHeader": { - "message": "Before you start" + "message": "Antes de começar" }, "sendFirefoxCustomDatePopoutMessage1": { - "message": "To use a calendar style date picker", + "message": "Para usar um seletor de data no estilo de calendário", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read '**To use a calendar style date picker ** click here to pop out your window.'" }, "sendFirefoxCustomDatePopoutMessage2": { - "message": "click here", + "message": "clique aqui", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'To use a calendar style date picker **click here** to pop out your window.'" }, "sendFirefoxCustomDatePopoutMessage3": { - "message": "to pop out your window.", + "message": "Para abrir em janela.", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'To use a calendar style date picker click here **to pop out your window.**'" }, "expirationDateIsInvalid": { - "message": "The expiration date provided is not valid." + "message": "A data de validade fornecida não é válida." }, "deletionDateIsInvalid": { - "message": "The deletion date provided is not valid." + "message": "A data de eliminação fornecida não é válida." }, "expirationDateAndTimeRequired": { - "message": "An expiration date and time are required." + "message": "Uma data de validade e uma hora são obrigatórias." }, "deletionDateAndTimeRequired": { - "message": "A deletion date and time are required." + "message": "Uma data de eliminação e uma hora são obrigatórias." }, "dateParsingError": { - "message": "There was an error saving your deletion and expiration dates." + "message": "Ocorreu um erro ao guardar a sua exclusão e datas de validade." }, "hideEmail": { - "message": "Hide my email address from recipients." + "message": "Ocultar o meu endereço de correio eletrónico dos destinatários." }, "sendOptionsPolicyInEffect": { "message": "One or more organization policies are affecting your Send options." @@ -1760,31 +1810,31 @@ "message": "You must verify your email to use this feature. You can verify your email in the web vault." }, "updatedMasterPassword": { - "message": "Updated Master Password" + "message": "Palavra-passe Mestra Atualizada" }, "updateMasterPassword": { - "message": "Update Master Password" + "message": "Atualizar Senha Mestra" }, "updateMasterPasswordWarning": { "message": "Your Master Password was recently changed by an administrator in your organization. In order to access the vault, you must update it now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour." }, "resetPasswordPolicyAutoEnroll": { - "message": "Automatic Enrollment" + "message": "Inscrição Automática" }, "resetPasswordAutoEnrollInviteWarning": { "message": "This organization has an enterprise policy that will automatically enroll you in password reset. Enrollment will allow organization administrators to change your master password." }, "selectFolder": { - "message": "Select folder..." + "message": "Seleccionar pasta..." }, "ssoCompleteRegistration": { "message": "In order to complete logging in with SSO, please set a master password to access and protect your vault." }, "hours": { - "message": "Hours" + "message": "Horas" }, "minutes": { - "message": "Minutes" + "message": "Minutos" }, "vaultTimeoutPolicyInEffect": { "message": "Your organization policies are affecting your vault timeout. Maximum allowed Vault Timeout is $HOURS$ hour(s) and $MINUTES$ minute(s)", @@ -1799,7 +1849,7 @@ } } }, - "vaultTimeoutToLarge": { + "vaultTimeoutTooLarge": { "message": "Your vault timeout exceeds the restrictions set by your organization." }, "vaultExportDisabled": { @@ -1813,5 +1863,109 @@ }, "copyCustomFieldNameNotUnique": { "message": "No unique identifier found." + }, + "convertOrganizationEncryptionDesc": { + "message": "$ORGANIZATION$ is using SSO with a self-hosted key server. A master password is no longer required to log in for members of this organization.", + "placeholders": { + "organization": { + "content": "$1", + "example": "My Org Name" + } + } + }, + "leaveOrganization": { + "message": "Deixar a Organização" + }, + "removeMasterPassword": { + "message": "Remover Senha Mestra" + }, + "removedMasterPassword": { + "message": "Senha mestra removida." + }, + "leaveOrganizationConfirmation": { + "message": "Tem a certeza de que pretende sair desta organização?" + }, + "leftOrganization": { + "message": "Saiu da organização." + }, + "toggleCharacterCount": { + "message": "Toggle character count" + }, + "sessionTimeout": { + "message": "A sua sessão expirou. Por favor, volte atrás e tente iniciar sessão novamente." + }, + "exportingPersonalVaultTitle": { + "message": "A Exportar Cofre Pessoal" + }, + "exportingPersonalVaultDescription": { + "message": "Apenas os itens do cofre pessoal associado ao $EMAIL$ serão exportados. Os itens do cofre da organização não serão incluídos.", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "error": { + "message": "Erro" + }, + "regenerateUsername": { + "message": "Regerar Nome de Utilizador" + }, + "generateUsername": { + "message": "Gerar Nome de Utilizador" + }, + "usernameType": { + "message": "Tipo de Nome de Utilizador" + }, + "plusAddressedEmail": { + "message": "Plus Addressed Email", + "description": "Username generator option that appends a random sub-address to the username. For example: address+subaddress@email.com" + }, + "plusAddressedEmailDesc": { + "message": "Use your email provider's sub-addressing capabilities." + }, + "catchallEmail": { + "message": "Catch-all Email" + }, + "catchallEmailDesc": { + "message": "Use your domain's configured catch-all inbox." + }, + "random": { + "message": "Aleatório" + }, + "randomWord": { + "message": "Palavra Aleatória" + }, + "websiteName": { + "message": "Nome do Site" + }, + "whatWouldYouLikeToGenerate": { + "message": "O que desejaria de gerar?" + }, + "passwordType": { + "message": "Tipo de Palavra-passe" + }, + "service": { + "message": "Serviço" + }, + "forwardedEmail": { + "message": "Forwarded Email Alias" + }, + "forwardedEmailDesc": { + "message": "Generate an email alias with an external forwarding service." + }, + "hostname": { + "message": "Hostname", + "description": "Part of a URL." + }, + "apiAccessToken": { + "message": "Token de acesso da API" + }, + "apiKey": { + "message": "Chave da API" + }, + "ssoKeyConnectorError": { + "message": "Key Connector error: make sure Key Connector is available and working correctly." } } diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json index e14e0703904..9c0e0e8d4ea 100644 --- a/apps/browser/src/_locales/ro/messages.json +++ b/apps/browser/src/_locales/ro/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Adresă de e-mail greșită." }, - "masterPassRequired": { - "message": "Este necesară parola principală." + "masterPasswordRequired": { + "message": "Este necesară o parolă principală." }, - "masterPassLength": { - "message": "Parola principală trebuie să conțină minimum 8 caractere." + "confirmMasterPasswordRequired": { + "message": "Este necesară rescrierea parolei principale." + }, + "masterPasswordMinLength": { + "message": "Parola principală trebuie să aibă cel puțin 8 caractere." }, "masterPassDoesntMatch": { "message": "Parola principală și confirmarea ei nu coincid!" @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Dacă bifați această casetă sunteți de acord cu următoarele:" }, - "acceptPoliciesError": { - "message": "Termenii de utilizare și Politica de confidențialitate nu au fost recunoscute." + "acceptPoliciesRequired": { + "message": "Termeni de utilizare și Politica de confidențialitate nu au fost recunoscute." }, "termsOfService": { "message": "Termeni de utilizare" diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json index dc66b5c423b..5c2bd8fc26b 100644 --- a/apps/browser/src/_locales/ru/messages.json +++ b/apps/browser/src/_locales/ru/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "Неверный адрес email." }, - "masterPassRequired": { - "message": "Необходимо ввести мастер-пароль." + "masterPasswordRequired": { + "message": "Требуется мастер-пароль." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Необходимо ввести мастер-пароль повторно." + }, + "masterPasswordMinLength": { "message": "Мастер-пароль должен содержать не менее 8 символов." }, "masterPassDoesntMatch": { @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "Отметив этот флажок, вы соглашаетесь со следующим:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Условия предоставления услуг и Политика конфиденциальности не были подтверждены." }, "termsOfService": { diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json index f4b24172ce8..aef94ceae34 100644 --- a/apps/browser/src/_locales/si/messages.json +++ b/apps/browser/src/_locales/si/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "වලංගු නොවන විද්යුත් තැපැල් ලිපිනය." }, - "masterPassRequired": { - "message": "ප්රධාන මුරපදය අවශ්ය වේ." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "ප්රධාන මුරපදය අවම වශයෙන් අක්ෂර 8 ක් දිගු විය යුතුය." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "ප්රධාන මුරපදය තහවුරු කිරීම නොගැලපේ." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "මෙම කොටුව පරීක්ෂා කිරීමෙන් ඔබ පහත සඳහන් දෑ වලට එකඟ වේ:" }, - "acceptPoliciesError": { - "message": "සේවා කොන්දේසි සහ රහස්යතා ප්රතිපත්තිය පිළිගෙන නොමැත." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "සේවා කොන්දේසි" diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json index 687c49f807b..9ff59758719 100644 --- a/apps/browser/src/_locales/sk/messages.json +++ b/apps/browser/src/_locales/sk/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Neplatná emailová adresa." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Hlavné heslo je povinné." }, - "masterPassLength": { - "message": "Hlavné heslo musí obsahovať aspoň 8 znakov." + "confirmMasterPasswordRequired": { + "message": "Vyžaduje sa opätovné zadanie hlavného hesla." + }, + "masterPasswordMinLength": { + "message": "Hlavné heslo musí mať aspoň 8 znakov." }, "masterPassDoesntMatch": { "message": "Potvrdenie hlavného hesla sa nezhoduje." @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "Označením tohto políčka súhlasíte s nasledovným:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Neboli akceptované Podmienky používania a zásady Ochrany osobných údajov." }, "termsOfService": { diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index de480a328f6..102671ff32e 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Neveljaven epoštni naslov." }, - "masterPassRequired": { - "message": "Glavno geslo je obvezno." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Glavno geslo mora biti dolgo najmanj 8 znakov." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Potrditev glavnega gesla se ne ujema." @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index 99b83d09af2..b0959c3579e 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Неисправан имејл." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Главна Лозинка је неопходна." }, - "masterPassLength": { - "message": "Главна Лозинка треба имати бар 8 знака." + "confirmMasterPasswordRequired": { + "message": "Поновно уписивање главне лозинке је неопходно." + }, + "masterPasswordMinLength": { + "message": "Главна лозинка мора да садржи барем 8 знакова." }, "masterPassDoesntMatch": { "message": "Потврђена Главна Лозинка се не подудара." @@ -568,22 +571,22 @@ "description": "This is the folder for uncategorized items" }, "enableAddLoginNotification": { - "message": "Ask to add login" + "message": "Питај пре додавања" }, "addLoginNotificationDesc": { "message": "„Нотификације Додај Лозинку“ аутоматски тражи да сачувате нове пријаве у сефу кад год се први пут пријавите на њих." }, "showCardsCurrentTab": { - "message": "Show cards on Tab page" + "message": "Прикажи кредитне картице на страници картице" }, "showCardsCurrentTabDesc": { - "message": "List card items on the Tab page for easy auto-fill." + "message": "Прикажи ставке кредитних картица на страници картице за лакше аутоматско допуњавање." }, "showIdentitiesCurrentTab": { - "message": "Show identities on Tab page" + "message": "Прикажи идентитете на страници" }, "showIdentitiesCurrentTabDesc": { - "message": "List identity items on the Tab page for easy auto-fill." + "message": "Прикажи ставке идентитета на страници за лакше аутоматско допуњавање." }, "clearClipboard": { "message": "Обриши привремену меморију", @@ -600,10 +603,10 @@ "message": "Сачувај" }, "enableChangedPasswordNotification": { - "message": "Ask to update existing login" + "message": "Питај за ажурирање постојеће пријаве" }, "changedPasswordNotificationDesc": { - "message": "Ask to update a login's password when a change is detected on a website." + "message": "Прикажи потврду за ажурирање тренутне лозинке за пријаву када се промена препозна на Web страници." }, "notificationChangeDesc": { "message": "Да ли желите да ажурирате ову лозинку за Bitwarden?" @@ -612,10 +615,10 @@ "message": "Ажурирај" }, "enableContextMenuItem": { - "message": "Show context menu options" + "message": "Прикажи контекстни мени" }, "contextMenuItemDesc": { - "message": "Use a secondary click to access password generation and matching logins for the website. " + "message": "Користите други клик за приступање генерисању лозинки и пријавама за тренутну web страницу. " }, "defaultUriMatchDetection": { "message": "Стандардно налажење УРЛ", @@ -807,13 +810,13 @@ "message": "Освежавање је завршено" }, "enableAutoTotpCopy": { - "message": "Copy TOTP automatically" + "message": "Аутоматски копирај једнократни код" }, "disableAutoTotpCopyDesc": { "message": "Ако је за вашу пријаву приложен аутентификациони кључ, једнократни код се аутоматски копира у вашој привременој меморији кад год ауто-попуните пријаву." }, "enableAutoBiometricsPrompt": { - "message": "Ask for biometrics on launch" + "message": "Захтевај биометрију при покретању" }, "premiumRequired": { "message": "Потребан Премијум" @@ -1034,16 +1037,16 @@ "message": "Овај прегледач не може да обрађује U2F захтеве у овом искачућем прозору. Да ли желите да отворите овај искачући прозор у новом прозору како бисте могли да се пријавите користећи U2F?" }, "enableFavicon": { - "message": "Show website icons" + "message": "Прикажи иконе сајтова" }, "faviconDesc": { - "message": "Show a recognizable image next to each login." + "message": "Прикажи препознатљиву слику поред сваке ставке за пријаву." }, "enableBadgeCounter": { - "message": "Show badge counter" + "message": "Прикажи бедж са бројачем" }, "badgeCounterDesc": { - "message": "Indicate how many logins you have for the current web page." + "message": "Означи број пријава које се могу користити на тренутној Web страници." }, "cardholderName": { "message": "Име Власника Картице" @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "Означавањем овог поља пристајете на следеће:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Услови услуге и Политика приватности нису прихваћени." }, "termsOfService": { @@ -1847,7 +1850,7 @@ } }, "vaultTimeoutTooLarge": { - "message": "Your vault timeout exceeds the restrictions set by your organization." + "message": "Време истека вашег сефа је премашило дозвољена ограничења од стране ваше организације." }, "vaultExportDisabled": { "message": "Извоз сефа онемогућен" diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index 8ad84e58e77..be3eaa5afb4 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Ogiltig e-postadress." }, - "masterPassRequired": { - "message": "Huvudlösenord krävs." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Huvudlösenordet måste vara minst 8 tecken långt." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Bekräftelsen för huvudlösenordet stämde ej." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Genom att markera denna ruta godkänner du följande:" }, - "acceptPoliciesError": { - "message": "Användarvillkoren och Integritetspolicyn har inte accepterats." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Användarvillkor" diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json index 814eac51b95..eabe6c688a7 100644 --- a/apps/browser/src/_locales/th/messages.json +++ b/apps/browser/src/_locales/th/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "ที่อยู่อีเมลไม่ถูกต้อง" }, - "masterPassRequired": { - "message": "ต้องระบุรหัสผ่านหลัก" + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "รหัสผ่านหลักต้องมีความยาวอย่างน้อย 8 อักขระ" + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Master password confirmation does not match." @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index c5d38c8cacd..5b5cdc71805 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "Geçersiz e-posta adresi." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Ana parola gereklidir." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Ana parolayı yeniden yazmalısınız." + }, + "masterPasswordMinLength": { "message": "Ana parola en az 8 karakter uzunluğunda olmalıdır." }, "masterPassDoesntMatch": { @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "Bu kutuyu işaretleyerek aşağıdakileri kabul etmiş olursunuz:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Hizmet Koşulları ve Gizlilik Politikası kabul edilmemiş." }, "termsOfService": { diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json index c976f2d3d80..2f6675f6ede 100644 --- a/apps/browser/src/_locales/uk/messages.json +++ b/apps/browser/src/_locales/uk/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Неправильна адреса е-пошти." }, - "masterPassRequired": { - "message": "Потрібен головний пароль." + "masterPasswordRequired": { + "message": "Необхідно ввести головний пароль." }, - "masterPassLength": { - "message": "Довжина головного пароля повинна бути не менше 8 символів." + "confirmMasterPasswordRequired": { + "message": "Необхідно повторно ввести головний пароль." + }, + "masterPasswordMinLength": { + "message": "Довжина головного пароля має бути принаймні 8 символів." }, "masterPassDoesntMatch": { "message": "Підтвердження головного пароля не збігається." @@ -594,7 +597,7 @@ "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "notificationAddDesc": { - "message": "Чи повинен Bitwarden зберегти цей пароль?" + "message": "Чи має Bitwarden зберегти цей пароль?" }, "notificationAddSave": { "message": "Зберегти" @@ -659,7 +662,7 @@ "message": "Експортовані дані вашого сховища знаходяться в незашифрованому вигляді. Вам не слід зберігати чи надсилати їх через незахищені канали (наприклад, е-поштою). Після використання негайно видаліть їх." }, "encExportKeyWarningDesc": { - "message": "Цей експорт шифрує ваші дані за допомогою ключа шифрування облікового запису. Якщо ви коли-небудь оновите ключ шифрування облікового запису, ви повинні виконати експорт знову, оскільки не зможете розшифрувати цей файл експорту." + "message": "Цей експорт шифрує ваші дані за допомогою ключа шифрування облікового запису. Якщо ви коли-небудь оновите ключ шифрування облікового запису, необхідно виконати експорт знову, оскільки не зможете розшифрувати цей файл експорту." }, "encExportAccountWarningDesc": { "message": "Ключі шифрування унікальні для кожного облікового запису користувача Bitwarden, тому ви не можете імпортувати зашифрований експорт до іншого облікового запису." @@ -1374,7 +1377,7 @@ "message": "Блокувати головним паролем при перезапуску браузера" }, "selectOneCollection": { - "message": "Ви повинні обрати принаймні одну збірку." + "message": "Необхідно вибрати принаймні одну збірку." }, "cloneItem": { "message": "Клонувати запис" @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Позначивши цей прапорець, ви погоджуєтеся з:" }, - "acceptPoliciesError": { - "message": "Умови користування та політика приватності не погоджені." + "acceptPoliciesRequired": { + "message": "Ви не погодилися з умовами користування та політикою приватності." }, "termsOfService": { "message": "Умови користування" @@ -1565,7 +1568,7 @@ "message": "Виключені домени" }, "excludedDomainsDesc": { - "message": "Bitwarden не запитуватиме про збереження даних входу для цих доменів. Ви повинні оновити сторінку для застосування змін." + "message": "Bitwarden не запитуватиме про збереження даних входу для цих доменів. Потрібно оновити сторінку для застосування змін." }, "excludedDomainsInvalidDomain": { "message": "$DOMAIN$ не є дійсним доменом", @@ -1813,7 +1816,7 @@ "message": "Оновити головний пароль" }, "updateMasterPasswordWarning": { - "message": "Ваш головний пароль нещодавно був змінений адміністратором організації. Щоб отримати доступ до сховища, ви повинні оновити його зараз. Продовживши, ви вийдете з поточного сеансу, після чого необхідно буде повторно виконати вхід. Сеанси на інших пристроях можуть залишатися активними протягом однієї години." + "message": "Ваш головний пароль нещодавно був змінений адміністратором організації. Щоб отримати доступ до сховища, вам необхідно оновити його зараз. Продовживши, ви вийдете з поточного сеансу, після чого потрібно буде повторно виконати вхід. Сеанси на інших пристроях можуть залишатися активними протягом однієї години." }, "resetPasswordPolicyAutoEnroll": { "message": "Автоматичне розгортання" diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json index 5878d809866..9954d954908 100644 --- a/apps/browser/src/_locales/vi/messages.json +++ b/apps/browser/src/_locales/vi/messages.json @@ -423,11 +423,14 @@ "invalidEmail": { "message": "Địa chỉ email không hợp lệ." }, - "masterPassRequired": { - "message": "Mật khẩu chủ là bắt buộc." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Mật khẩu chủ phải có ít nhất 8 kí tự." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Xác nhận mật khẩu chủ không khớp." @@ -1480,8 +1483,8 @@ "acceptPolicies": { "message": "Bạn đồng ý với những điều sau khi nhấn chọn ô này:" }, - "acceptPoliciesError": { - "message": "Điều khoản sử dụng và Chính sách quyền riêng tư chưa được đồng ý." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Điều khoản sử dụng" diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index f5c13b3adfc..800e861f80a 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "无效的电子邮件地址。" }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "必须填写主密码。" }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "必须填写确认主密码。" + }, + "masterPasswordMinLength": { "message": "主密码至少需要 8 个字符。" }, "masterPassDoesntMatch": { @@ -568,7 +571,7 @@ "description": "This is the folder for uncategorized items" }, "enableAddLoginNotification": { - "message": "要求添加登录" + "message": "询问添加登录" }, "addLoginNotificationDesc": { "message": "在密码库中找不到匹配项目时询问添加一个。" @@ -600,10 +603,10 @@ "message": "保存" }, "enableChangedPasswordNotification": { - "message": "要求更新现有的登录" + "message": "询问更新现有的登录" }, "changedPasswordNotificationDesc": { - "message": "在网站上检测到更改时要求更新登录密码。" + "message": "在网站上检测到更改时询问更新登录密码。" }, "notificationChangeDesc": { "message": "是否要在 Bitwarden 中更新此密码?" @@ -615,7 +618,7 @@ "message": "显示上下文菜单选项" }, "contextMenuItemDesc": { - "message": "使用辅助点击来访问网站的密码生成和匹配登录。" + "message": "使用辅助点击来访问密码生成和匹配网站登录。 " }, "defaultUriMatchDetection": { "message": "默认 URI 匹配检测", @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "选中此框表示您同意:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "尚未同意服务条款和隐私政策。" }, "termsOfService": { diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json index 384a62cda2c..d937b54aff4 100644 --- a/apps/browser/src/_locales/zh_TW/messages.json +++ b/apps/browser/src/_locales/zh_TW/messages.json @@ -423,10 +423,13 @@ "invalidEmail": { "message": "無效的電子郵件地址。" }, - "masterPassRequired": { - "message": "必須填入主密碼。" + "masterPasswordRequired": { + "message": "必須填寫主密碼。" }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "必須再次輸入主密碼。" + }, + "masterPasswordMinLength": { "message": "主密碼需要至少 8 個字元。" }, "masterPassDoesntMatch": { @@ -1356,7 +1359,7 @@ "message": "設定您用來解鎖 Bitwarden 的 PIN 碼。您的 PIN 設定將在您完全登出本應用程式時被重設。" }, "pinRequired": { - "message": "需要 PIN 碼。" + "message": "必須填入 PIN 碼。" }, "invalidPin": { "message": "無效的 PIN 碼。" @@ -1480,7 +1483,7 @@ "acceptPolicies": { "message": "若選取此方塊,代表您同意下列項目:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "尚未接受服務條款與隱私權政策。" }, "termsOfService": { From cc9a6e12f7eda0b31885b809fe3b8ea54ab016cd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 8 Jul 2022 08:34:46 +0200 Subject: [PATCH 19/86] Autosync the updated translations (#3068) Co-authored-by: github-actions <> --- apps/desktop/src/locales/af/messages.json | 28 +- apps/desktop/src/locales/ar/messages.json | 318 +++++++------- apps/desktop/src/locales/az/messages.json | 12 +- apps/desktop/src/locales/be/messages.json | 18 +- apps/desktop/src/locales/bg/messages.json | 14 +- apps/desktop/src/locales/bn/messages.json | 18 +- apps/desktop/src/locales/bs/messages.json | 16 +- apps/desktop/src/locales/ca/messages.json | 18 +- apps/desktop/src/locales/cs/messages.json | 18 +- apps/desktop/src/locales/da/messages.json | 18 +- apps/desktop/src/locales/de/messages.json | 14 +- apps/desktop/src/locales/el/messages.json | 18 +- apps/desktop/src/locales/en_GB/messages.json | 306 ++++++++++++-- apps/desktop/src/locales/en_IN/messages.json | 12 +- apps/desktop/src/locales/eo/messages.json | 12 +- apps/desktop/src/locales/es/messages.json | 64 +-- apps/desktop/src/locales/et/messages.json | 18 +- apps/desktop/src/locales/eu/messages.json | 16 +- apps/desktop/src/locales/fa/messages.json | 14 +- apps/desktop/src/locales/fi/messages.json | 14 +- apps/desktop/src/locales/fil/messages.json | 12 +- apps/desktop/src/locales/fr/messages.json | 18 +- apps/desktop/src/locales/he/messages.json | 18 +- apps/desktop/src/locales/hi/messages.json | 12 +- apps/desktop/src/locales/hr/messages.json | 18 +- apps/desktop/src/locales/hu/messages.json | 12 +- apps/desktop/src/locales/id/messages.json | 18 +- apps/desktop/src/locales/it/messages.json | 18 +- apps/desktop/src/locales/ja/messages.json | 14 +- apps/desktop/src/locales/ka/messages.json | 12 +- apps/desktop/src/locales/km/messages.json | 12 +- apps/desktop/src/locales/kn/messages.json | 18 +- apps/desktop/src/locales/ko/messages.json | 18 +- apps/desktop/src/locales/lv/messages.json | 18 +- apps/desktop/src/locales/me/messages.json | 18 +- apps/desktop/src/locales/ml/messages.json | 18 +- apps/desktop/src/locales/nb/messages.json | 18 +- apps/desktop/src/locales/nl/messages.json | 16 +- apps/desktop/src/locales/nn/messages.json | 12 +- apps/desktop/src/locales/pl/messages.json | 14 +- apps/desktop/src/locales/pt_BR/messages.json | 18 +- apps/desktop/src/locales/pt_PT/messages.json | 410 +++++++++++++++---- apps/desktop/src/locales/ro/messages.json | 16 +- apps/desktop/src/locales/ru/messages.json | 12 +- apps/desktop/src/locales/si/messages.json | 12 +- apps/desktop/src/locales/sk/messages.json | 14 +- apps/desktop/src/locales/sl/messages.json | 12 +- apps/desktop/src/locales/sr/messages.json | 18 +- apps/desktop/src/locales/sv/messages.json | 18 +- apps/desktop/src/locales/th/messages.json | 14 +- apps/desktop/src/locales/tr/messages.json | 12 +- apps/desktop/src/locales/uk/messages.json | 26 +- apps/desktop/src/locales/vi/messages.json | 16 +- apps/desktop/src/locales/zh_CN/messages.json | 396 ++++++++++++++---- apps/desktop/src/locales/zh_TW/messages.json | 16 +- 55 files changed, 1646 insertions(+), 644 deletions(-) diff --git a/apps/desktop/src/locales/af/messages.json b/apps/desktop/src/locales/af/messages.json index 028ca64d233..584ded79ced 100644 --- a/apps/desktop/src/locales/af/messages.json +++ b/apps/desktop/src/locales/af/messages.json @@ -233,13 +233,13 @@ "message": "Mnr." }, "mrs": { - "message": "Mev." + "message": "Mev" }, "ms": { - "message": "Mej." + "message": "Mej" }, "dr": { - "message": "Dr." + "message": "Dr" }, "expirationMonth": { "message": "Vervalmaand" @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Ongeldige e-posadres." }, - "masterPassRequired": { - "message": "Hoofwagwoord word benodig." + "masterPasswordRequired": { + "message": "Hoofwagwoord word vereis." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Hoofwagwoord moet weer intevoer word." + }, + "masterPasswordMinLength": { "message": "Hoofwagwoord moet ten minste 8 karakters lank wees." }, "masterPassDoesntMatch": { @@ -895,10 +898,10 @@ "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "enableFavicon": { - "message": "Show website icons" + "message": "Toon webwerfikone" }, "faviconDesc": { - "message": "Show a recognizable image next to each login." + "message": "Toon ’n herkenbare beeld langs elke aantekening." }, "enableMinToTray": { "message": "Minimaliseer na stelsellaai" @@ -1382,10 +1385,10 @@ "message": "ontgrendel u kluis" }, "autoPromptWindowsHello": { - "message": "Ask for Windows Hello on launch" + "message": "Vra vir Windows Hello by lansering" }, "autoPromptTouchId": { - "message": "Ask for Touch ID on launch" + "message": "Vra vir Touch ID by lansering" }, "lockWithMasterPassOnRestart": { "message": "Vergrendel by herbegin met hoofwagwoord" @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "Deur hierdie kassie af te merk stem u in tot die volgende:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Gebruiksvoorwaardes en privaatheidsbeleid is nie erken nie." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API-sleutel" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/ar/messages.json b/apps/desktop/src/locales/ar/messages.json index e245d887308..1cf617f9c56 100644 --- a/apps/desktop/src/locales/ar/messages.json +++ b/apps/desktop/src/locales/ar/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "عنوان البريد الإلكتروني غير صالح." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "كلمة المرور الرئيسية مطلوبة." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "مطلوب إعادة كتابة كلمة المرور الرئيسية." + }, + "masterPasswordMinLength": { "message": "يجب أن تكون كلمة المرور الرئيسية أكثر من 8 أحرف." }, "masterPassDoesntMatch": { @@ -895,10 +898,10 @@ "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "enableFavicon": { - "message": "Show website icons" + "message": "إظهار أيقونات الموقع" }, "faviconDesc": { - "message": "Show a recognizable image next to each login." + "message": "إظهار صورة قابلة للتعرف بجانب كل تسجيل دخول." }, "enableMinToTray": { "message": "تصغير إلى أيقونة شريط المهام" @@ -937,28 +940,28 @@ "message": "عندما يبدأ التطبيق لأول مرة، فقط إظهار أيقونة في شريط مهام النظام." }, "startToMenuBar": { - "message": "Start to menu bar" + "message": "البدء في شريط القائمة" }, "startToMenuBarDesc": { - "message": "When the application is first started, only show an icon in the menu bar." + "message": "عند بدء تشغيل التطبيق لأول مرة، فقط إظهار أيقونة في شريط القائمة." }, "openAtLogin": { - "message": "Start automatically on login" + "message": "بدء التشغيل تلقائياً عند تسجيل الدخول" }, "openAtLoginDesc": { - "message": "Start the Bitwarden desktop application automatically on login." + "message": "بدء تشغيل تطبيق سطح المكتب Bitwarden تلقائياً عند تسجيل الدخول." }, "alwaysShowDock": { - "message": "Always show in the Dock" + "message": "إظهار دائمًا في القائمة" }, "alwaysShowDockDesc": { - "message": "Show the Bitwarden icon in the Dock even when minimized to the menu bar." + "message": "إظهار أيقونة Bitwarden في القائمة حتى عند التصغير إلى شريط القائمة." }, "confirmTrayTitle": { - "message": "Confirm disable tray" + "message": "تأكيد تعطيل الشريط" }, "confirmTrayDesc": { - "message": "Disabling this setting will also disable all other tray related settings." + "message": "سيؤدي تعطيل هذا الإعداد أيضًا إلى تعطيل كافة الإعدادات الأخرى ذات الصلة بشريط النظام." }, "language": { "message": "اللّغة" @@ -1137,45 +1140,45 @@ "message": "إعادة تعيين التكبير/التصغير غلى الوضع الافتراضي" }, "toggleFullScreen": { - "message": "Toggle Full Screen" + "message": "تفعيل وضع ملء الشاشة" }, "reload": { - "message": "Reload" + "message": "إعادة تحميل" }, "toggleDevTools": { - "message": "Toggle Developer Tools" + "message": "تبديل إلى أدوات المطور" }, "minimize": { - "message": "Minimize", + "message": "تصغير", "description": "Minimize window" }, "zoom": { - "message": "Zoom" + "message": "تكبير" }, "bringAllToFront": { - "message": "Bring All to Front", + "message": "احضار الكل إلى الأمام", "description": "Bring all windows to front (foreground)" }, "aboutBitwarden": { - "message": "About Bitwarden" + "message": "حول Bitwarden" }, "services": { - "message": "Services" + "message": "الخدمات" }, "hideBitwarden": { - "message": "Hide Bitwarden" + "message": "إخفاء Bitwarden" }, "hideOthers": { - "message": "Hide Others" + "message": "إخفاء الآخرين" }, "showAll": { - "message": "Show All" + "message": "إظهار الكل" }, "quitBitwarden": { - "message": "Quit Bitwarden" + "message": "غلق Bitwarden" }, "valueCopied": { - "message": "$VALUE$ copied", + "message": "$VALUE$ تم نسخه", "description": "Value has been copied to the clipboard.", "placeholders": { "value": { @@ -1185,16 +1188,16 @@ } }, "help": { - "message": "Help" + "message": "المساعدة" }, "window": { - "message": "Window" + "message": "نافذة" }, "checkPassword": { - "message": "Check if password has been exposed." + "message": "تحقق مما إذا تم الكشف عن كلمة المرور." }, "passwordExposed": { - "message": "This password has been exposed $VALUE$ time(s) in data breaches. You should change it.", + "message": "تم الكشف عن كلمة المرور هذه $VALUE$ مرّة (ات) في خروقات البيانات. يجب عليك تغييرها.", "placeholders": { "value": { "content": "$1", @@ -1203,92 +1206,92 @@ } }, "passwordSafe": { - "message": "This password was not found in any known data breaches. It should be safe to use." + "message": "لم يتم العثور على كلمة المرور هذه في أي عمليات اختراق معروفة للبيانات. يجب أن تكون آمنة للاستخدام." }, "baseDomain": { - "message": "Base domain", + "message": "النطاق الأساسي", "description": "Domain name. Ex. website.com" }, "domainName": { - "message": "Domain Name", + "message": "اسم النطاق", "description": "Domain name. Ex. website.com" }, "host": { - "message": "Host", + "message": "المضيف", "description": "A URL's host value. For example, the host of https://sub.domain.com:443 is 'sub.domain.com:443'." }, "exact": { - "message": "Exact" + "message": "بالضبط" }, "startsWith": { - "message": "Starts with" + "message": "يبدأ بـ" }, "regEx": { - "message": "Regular expression", + "message": "التعبير الاعتيادي", "description": "A programming term, also known as 'RegEx'." }, "matchDetection": { - "message": "Match Detection", + "message": "كشف المطابقة", "description": "URI match detection for auto-fill." }, "defaultMatchDetection": { - "message": "Default match detection", + "message": "الكشف الافتراضي عن المطابقة", "description": "Default URI match detection for auto-fill." }, "toggleOptions": { - "message": "Toggle Options" + "message": "خيارات التبديل" }, "organization": { - "message": "Organization", + "message": "المؤسسة", "description": "An entity of multiple related people (ex. a team or business organization)." }, "default": { - "message": "Default" + "message": "الافتراضي" }, "exit": { - "message": "Exit" + "message": "الخروج" }, "showHide": { - "message": "Show / Hide", + "message": "عرض / اخفاء", "description": "Text for a button that toggles the visibility of the window. Shows the window when it is hidden or hides the window if it is currently open." }, "hideToTray": { - "message": "Hide to Tray" + "message": "إخفاء إلى الشريط" }, "alwaysOnTop": { - "message": "Always on Top", + "message": "دائما في الأعلى", "description": "Application window should always stay on top of other windows" }, "dateUpdated": { - "message": "Updated", + "message": "تم التحديث", "description": "ex. Date this item was updated" }, "datePasswordUpdated": { - "message": "Password Updated", + "message": "تم تحديث كلمة المرور", "description": "ex. Date this password was updated" }, "exportVault": { - "message": "Export Vault" + "message": "تصدير الخزنة" }, "fileFormat": { - "message": "File Format" + "message": "صيغة الملف" }, "hCaptchaUrl": { - "message": "hCaptcha Url", + "message": "رابط hCaptcha", "description": "hCaptcha is the name of a website, should not be translated" }, "loadAccessibilityCookie": { - "message": "Load Accessibility Cookie" + "message": "تحميل ملف تعريف الارتباط الخاص بإمكانية الوصول" }, "registerAccessibilityUser": { - "message": "Register as an accessibility user at", + "message": "تسجيل كمستخدم مع إمكانية الوصول في", "description": "ex. Register as an accessibility user at hcaptcha.com" }, "copyPasteLink": { - "message": "Copy and paste the link sent to your email below" + "message": "نسخ وصق الرابط المرسل إلى بريدك الإلكتروني أدناه" }, "enterhCaptchaUrl": { - "message": "Enter URL to load accessibility cookie for hCaptcha", + "message": "أدخل عنوان URL لتحميل ملف تعريف الارتباط للوصول إلى hCaptcha", "description": "hCaptcha is the name of a website, should not be translated" }, "hCaptchaUrlRequired": { @@ -1382,10 +1385,10 @@ "message": "فتح خزنتك" }, "autoPromptWindowsHello": { - "message": "Ask for Windows Hello on launch" + "message": "اسأل عن Windows Hello عند التشغيل" }, "autoPromptTouchId": { - "message": "Ask for Touch ID on launch" + "message": "اطلب معرف اللمس عند التشغيل" }, "lockWithMasterPassOnRestart": { "message": "قفل مع كلمة المرور الرئيسية عند إعادة تشغيل" @@ -1496,13 +1499,13 @@ "message": "كلمة المرور الرئيسية الجديدة" }, "confirmNewMasterPass": { - "message": "Confirm New Master Password" + "message": "تأكيد كلمة المرور الرئيسية الجديدة" }, "masterPasswordPolicyInEffect": { - "message": "One or more organization policies require your master password to meet the following requirements:" + "message": "1 - تتطلب سياسة واحدة أو أكثر من سياسات المؤسسة كلمة مرورك الرئيسية لتلبية المتطلبات التالية:" }, "policyInEffectMinComplexity": { - "message": "Minimum complexity score of $SCORE$", + "message": "الحد الأدنى لدرجة التعقيد $SCORE$", "placeholders": { "score": { "content": "$1", @@ -1511,7 +1514,7 @@ } }, "policyInEffectMinLength": { - "message": "Minimum length of $LENGTH$", + "message": "الحد الأدنى لطول $LENGTH$", "placeholders": { "length": { "content": "$1", @@ -1520,16 +1523,16 @@ } }, "policyInEffectUppercase": { - "message": "Contain one or more uppercase characters" + "message": "يحتوي على حرف كبير واحد أو أكثر" }, "policyInEffectLowercase": { - "message": "Contain one or more lowercase characters" + "message": "يحتوي على واحد أو أكثر من الأحرف الصغيرة" }, "policyInEffectNumbers": { - "message": "Contain one or more numbers" + "message": "يحتوي على رقم واحد أو أكثر" }, "policyInEffectSpecial": { - "message": "Contain one or more of the following special characters $CHARS$", + "message": "يحتوي على واحد أو أكثر من الأحرف الخاصة التالية $CHARS$", "placeholders": { "chars": { "content": "$1", @@ -1538,117 +1541,117 @@ } }, "masterPasswordPolicyRequirementsNotMet": { - "message": "Your new master password does not meet the policy requirements." + "message": "كلمة المرور الرئيسية الجديدة لا تفي بمتطلبات السياسة العامة." }, "acceptPolicies": { - "message": "By checking this box you agree to the following:" + "message": "من خلال تحديد هذا المربع فإنك توافق على ما يلي:" }, - "acceptPoliciesError": { - "message": "Terms of Service and Privacy Policy have not been acknowledged." + "acceptPoliciesRequired": { + "message": "لم يتم الاعتراف بشروط الخدمة وسياسة الخصوصية." }, "enableBrowserIntegration": { - "message": "Allow browser integration" + "message": "السماح بتكامل المتصفح" }, "enableBrowserIntegrationDesc": { - "message": "Browser integration is used for biometrics in browser." + "message": "يتم استخدام تكامل المتصفح للقياسات الحيوية في المتصفح." }, "browserIntegrationUnsupportedTitle": { - "message": "Browser integration not supported" + "message": "تكامل المتصفح غير مدعوم" }, "browserIntegrationMasOnlyDesc": { - "message": "Unfortunately browser integration is only supported in the Mac App Store version for now." + "message": "للأسف، لا يتم دعم تكامل المتصفح إلا في إصدار متجر تطبيقات ماك في الوقت الحالي." }, "browserIntegrationWindowsStoreDesc": { - "message": "Unfortunately browser integration is currently not supported in the Windows Store version." + "message": "للأسف، لا يتم دعم تكامل المتصفح في إصدار متجر ويندوز في الوقت الحالي." }, "browserIntegrationLinuxDesc": { - "message": "Unfortunately browser integration is currently not supported in the linux version." + "message": "للأسف، لا يتم دعم تكامل المتصفح في إصدار لينكس في الوقت الحالي." }, "enableBrowserIntegrationFingerprint": { - "message": "Require verification for browser integration" + "message": "يتطلب التحقق من تكامل المتصفح" }, "enableBrowserIntegrationFingerprintDesc": { - "message": "Add an additional layer of security by requiring fingerprint phrase confirmation when establishing a link between your desktop and browser. This requires user action and verification each time a connection is created." + "message": "أضف طبقة أمان إضافية عن طريق طلب تأكيد عبارة بصمة الإصبع عند إنشاء رابط بين سطح المكتب الخاص بك والمتصفح. هذا يتطلب إجراء المستخدم والتحقق في كل مرة يتم فيها إنشاء اتصال." }, "approve": { - "message": "Approve" + "message": "الموافقة" }, "verifyBrowserTitle": { - "message": "Verify browser connection" + "message": "التحقق من اتصال المتصفح" }, "verifyBrowserDesc": { - "message": "Please ensure the shown fingerprint is identical to the fingerprint showed in the browser extension." + "message": "الرجاء التأكد من أن البصمة المعروضة متطابقة مع البصمة المعروضة في ملحق المتصفح." }, "biometricsNotEnabledTitle": { - "message": "Biometrics not enabled" + "message": "القياسات الحيوية غير مفعلة" }, "biometricsNotEnabledDesc": { - "message": "Browser biometrics requires desktop biometrics to be enabled in the settings first." + "message": "القياسات الحيوية للمتصفح تتطلب القياسات الحيوية لسطح المكتب ليتم تمكينها في الإعدادات أولاً." }, "personalOwnershipSubmitError": { - "message": "Due to an Enterprise Policy, you are restricted from saving items to your personal vault. Change the Ownership option to an organization and choose from available Collections." + "message": "بسبب سياسة المؤسسة، يمنع عليك حفظ العناصر في خزانتك الشخصية. غيّر خيار الملكية إلى مؤسسة واختر من المجموعات المتاحة." }, "hintEqualsPassword": { - "message": "Your password hint cannot be the same as your password." + "message": "لا يمكن أن يكون تلميح كلمة المرور نفس كلمة المرور الخاصة بك." }, "personalOwnershipPolicyInEffect": { - "message": "An organization policy is affecting your ownership options." + "message": "تؤثر سياسة مؤسسة على خيارات الملكية الخاصة بك." }, "allSends": { - "message": "All Sends", + "message": "كل الإرسالات", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendTypeFile": { - "message": "File" + "message": "ملف" }, "sendTypeText": { - "message": "Text" + "message": "نص" }, "searchSends": { - "message": "Search Sends", + "message": "بحث عن الإرسالات", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editSend": { - "message": "Edit Send", + "message": "عدّل الإرسال", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "myVault": { - "message": "My Vault" + "message": "خزنتي" }, "text": { - "message": "Text" + "message": "نص" }, "deletionDate": { - "message": "Deletion Date" + "message": "تاريخ الحذف" }, "deletionDateDesc": { - "message": "The Send will be permanently deleted on the specified date and time.", + "message": "سيتم حذف الإرسال بشكل دائم في التاريخ والوقت المحددين.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "expirationDate": { - "message": "Expiration Date" + "message": "تاريخ انتهاء الصلاحية" }, "expirationDateDesc": { - "message": "If set, access to this Send will expire on the specified date and time.", + "message": "في حالة التعيين، ستنتهي صلاحية الوصول إلى هذا الإرسال في التاريخ والوقت المحددين.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "maxAccessCount": { - "message": "Maximum Access Count", + "message": "الحد الأقصى لعدد الوصول", "description": "This text will be displayed after a Send has been accessed the maximum amount of times." }, "maxAccessCountDesc": { - "message": "If set, users will no longer be able to access this Send once the maximum access count is reached.", + "message": "في حالة التعيين، لن يتمكن المستخدمون من الوصول إلى هذا الإرسال بمجرد الوصول إلى الحد الأقصى لعدد الوصول.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "currentAccessCount": { - "message": "Current Access Count" + "message": "العد الحالي للوصول" }, "disableSend": { - "message": "Disable this Send so that no one can access it.", + "message": "تعطيل هذا الإرسال بحيث لا يمكن لأحد الوصول إليه.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendPasswordDesc": { - "message": "Optionally require a password for users to access this Send.", + "message": "بشكل اختياري يتطلب كلمة مرور للمستخدمين للوصول إلى هذا الإرسال.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendNotesDesc": { @@ -1764,28 +1767,28 @@ "message": "إعادة توجيه كلمة المرور الرئيسية" }, "passwordConfirmation": { - "message": "Master password confirmation" + "message": "تأكيد كلمة المرور الرئيسية" }, "passwordConfirmationDesc": { - "message": "This action is protected. To continue, please re-enter your master password to verify your identity." + "message": "هذا الإجراء محمي. للاستمرار، يرجى إعادة إدخال كلمة المرور الرئيسية للتحقق من هويتك." }, "updatedMasterPassword": { - "message": "Updated Master Password" + "message": "كلمة المرور الرئيسية المحدثة" }, "updateMasterPassword": { - "message": "Update Master Password" + "message": "تحديث كلمة المرور الرئيسية" }, "updateMasterPasswordWarning": { - "message": "Your Master Password was recently changed by an administrator in your organization. In order to access the vault, you must update it now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour." + "message": "تم تغيير كلمة المرور الرئيسية الخاصة بك مؤخرًا من قبل مسؤول في مؤسستك. من أجل الوصول إلى الخزانة، يجب عليك تحديثها الآن. سيتم تسجيل خروجك من الجلسة الحالية، مما يتطلب منك تسجيل الدخول مرة أخرى. وقد تظل الجلسات النشطة على أجهزة أخرى نشطة لمدة تصل إلى ساعة واحدة." }, "hours": { - "message": "Hours" + "message": "ساعات" }, "minutes": { - "message": "Minutes" + "message": "دقائق" }, "vaultTimeoutPolicyInEffect": { - "message": "Your organization policies are affecting your vault timeout. Maximum allowed Vault Timeout is $HOURS$ hour(s) and $MINUTES$ minute(s)", + "message": "سياسات مؤسستك تؤثر على مهلة خزانتك. الحد الأقصى المسموح به لمهلة الخزنة هو $HOURS$ ساعة و $MINUTES$ دقيقة", "placeholders": { "hours": { "content": "$1", @@ -1798,31 +1801,31 @@ } }, "vaultTimeoutTooLarge": { - "message": "Your vault timeout exceeds the restrictions set by your organization." + "message": "مهلة خزنتك تتجاوز القيود التي تضعها مؤسستك." }, "resetPasswordPolicyAutoEnroll": { - "message": "Automatic Enrollment" + "message": "التسجيل التلقائي" }, "resetPasswordAutoEnrollInviteWarning": { - "message": "This organization has an enterprise policy that will automatically enroll you in password reset. Enrollment will allow organization administrators to change your master password." + "message": "هذه المؤسسة لديها سياسة الشركة التي ستقوم تلقائياً بتسجيلك في إعادة تعيين كلمة المرور. التسجيل سيسمح لمسؤولي المؤسسة بتغيير كلمة المرور الرئيسية الخاصة بك." }, "vaultExportDisabled": { - "message": "Vault Export Disabled" + "message": "تصدير الخزنة معطل" }, "personalVaultExportPolicyInEffect": { - "message": "One or more organization policies prevents you from exporting your personal vault." + "message": "واحدة أو أكثر من سياسات المؤسسة تمنعك من تصدير خزانتك الشخصية." }, "addAccount": { - "message": "Add Account" + "message": "إضافة حساب" }, "removeMasterPassword": { - "message": "Remove Master Password" + "message": "إزالة كلمة المرور الرئيسية" }, "removedMasterPassword": { - "message": "Master password removed." + "message": "تمت إزالة كلمة المرور الرئيسية." }, "convertOrganizationEncryptionDesc": { - "message": "$ORGANIZATION$ is using SSO with a self-hosted key server. A master password is no longer required to log in for members of this organization.", + "message": "يستخدم $ORGANIZATION$ SSO مع خادم مفتاح الاستضافة الذاتية. لم تعد هناك حاجة إلى كلمة مرور رئيسية لتسجيل الدخول لأعضاء هذه المؤسسة.", "placeholders": { "organization": { "content": "$1", @@ -1831,34 +1834,34 @@ } }, "leaveOrganization": { - "message": "Leave Organization" + "message": "مغادرة المؤسسة" }, "leaveOrganizationConfirmation": { - "message": "Are you sure you want to leave this organization?" + "message": "هل أنت متأكد من أنك تريد مغادرة هذه المؤسسة؟" }, "leftOrganization": { - "message": "You have left the organization." + "message": "لقد غادرت المؤسسة." }, "ssoKeyConnectorError": { - "message": "Key Connector error: make sure Key Connector is available and working correctly." + "message": "خطأ في موصل المفتاح: تأكد من أن موصل المفتاح متاح ويعمل بشكل صحيح." }, "lockAllVaults": { - "message": "Lock All Vaults" + "message": "قفل جميع الخزنات" }, "accountLimitReached": { - "message": "No more than 5 accounts may be logged in at the same time." + "message": "لا يمكن تسجيل دخول أكثر من 5 حسابات في نفس الوقت." }, "accountPreferences": { - "message": "Preferences" + "message": "التفضيلات" }, "appPreferences": { - "message": "App Settings (All Accounts)" + "message": "إعدادات التطبيق (جميع الحسابات)" }, "accountSwitcherLimitReached": { - "message": "Account limit reached. Log out of an account to add another." + "message": "تم الوصول إلى الحد الأقصى للحساب. تسجيل الخروج من حساب لإضافة حساب آخر." }, "settingsTitle": { - "message": "App settings for $EMAIL$", + "message": "إعدادات التطبيق لـ $EMAIL$", "placeholders": { "email": { "content": "$1", @@ -1867,19 +1870,19 @@ } }, "switchAccount": { - "message": "Switch Account" + "message": "تبديل الحساب" }, "options": { - "message": "Options" + "message": "الخيارات" }, "sessionTimeout": { - "message": "Your session has timed out. Please go back and try logging in again." + "message": "انتهت مهلة جلستك. يرجى العودة ومحاولة تسجيل الدخول مرة أخرى." }, "exportingPersonalVaultTitle": { - "message": "Exporting Personal Vault" + "message": "تصدير الخزنة الشخصية" }, "exportingPersonalVaultDescription": { - "message": "Only the personal vault items associated with $EMAIL$ will be exported. Organization vault items will not be included.", + "message": "سيتم تصدير فقط عناصر الخزنة الشخصية المرتبطة بـ $EMAIL$. لن يتم إدراج عناصر خزنة المؤسسة.", "placeholders": { "email": { "content": "$1", @@ -1888,77 +1891,80 @@ } }, "locked": { - "message": "Locked" + "message": "مقفل" }, "unlocked": { - "message": "Unlocked" + "message": "غير مقفل" }, "generator": { - "message": "Generator" + "message": "المولّد" }, "whatWouldYouLikeToGenerate": { - "message": "What would you like to generate?" + "message": "ما الذي ترغب في توليده؟" }, "passwordType": { - "message": "Password Type" + "message": "نوع كلمة المرور" }, "regenerateUsername": { - "message": "Regenerate Username" + "message": "إعادة إنشاء اسم المستخدم" }, "generateUsername": { - "message": "Generate Username" + "message": "إنشاء اسم المستخدم" }, "usernameType": { - "message": "Username Type" + "message": "نوع اسم المستخدم" }, "plusAddressedEmail": { - "message": "Plus Addressed Email", + "message": "بريد إلكتروني موجه اكثر", "description": "Username generator option that appends a random sub-address to the username. For example: address+subaddress@email.com" }, "plusAddressedEmailDesc": { - "message": "Use your email provider's sub-addressing capabilities." + "message": "استخدم قدرات العنوان الفرعي لموفر البريد الإلكتروني الخاص بك." }, "catchallEmail": { - "message": "Catch-all Email" + "message": "تجميع كل البريد" }, "catchallEmailDesc": { - "message": "Use your domain's configured catch-all inbox." + "message": "استخدم علبة البريد الإلكتروني الشاملة التي تم تكوينها في نطاقك." }, "random": { - "message": "Random" + "message": "عشوائي" }, "randomWord": { - "message": "Random Word" + "message": "كلمات عشوائية" }, "websiteName": { - "message": "Website Name" + "message": "اسم الموقع" }, "service": { - "message": "Service" + "message": "الخدمة" }, "allVaults": { - "message": "All Vaults" + "message": "جميع الخزنات" }, "searchOrganization": { - "message": "Search Organization" + "message": "البحث عن مؤسسة" }, "searchMyVault": { - "message": "Search My Vault" + "message": "البحث عن خزانتي" }, "forwardedEmail": { - "message": "Forwarded Email Alias" + "message": "إعادة توجيه الاسم المستعار للبريد الإلكتروني" }, "forwardedEmailDesc": { - "message": "Generate an email alias with an external forwarding service." + "message": "إنشاء بريد إلكتروني مستعار مع خدمة إعادة توجيه خارجية." }, "hostname": { - "message": "Hostname", + "message": "اسم المضيف", "description": "Part of a URL." }, "apiAccessToken": { - "message": "API Access Token" + "message": "رمز الوصول" }, "apiKey": { - "message": "API Key" + "message": "مفتاح API" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/az/messages.json b/apps/desktop/src/locales/az/messages.json index 6ac7b1c8653..df87416cd20 100644 --- a/apps/desktop/src/locales/az/messages.json +++ b/apps/desktop/src/locales/az/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Etibarsız e-poçt ünvanı." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Ana parol lazımdır." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Ana parolun yenidən yazılması lazımdır." + }, + "masterPasswordMinLength": { "message": "Ana parol ən azı 8 simvol uzunluğunda olmalıdır." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "Bu qutunu işarələyərək aşağıdakılarla razılaşırsınız:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Xidmət Şərtləri və Gizlilik Siyasəti qəbul edilməyib." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API açar" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/be/messages.json b/apps/desktop/src/locales/be/messages.json index 845b8f81b9b..c30d25afa6f 100644 --- a/apps/desktop/src/locales/be/messages.json +++ b/apps/desktop/src/locales/be/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Памылковы адрас электроннай пошты." }, - "masterPassRequired": { - "message": "Патрабуецца асноўны пароль." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Асноўны пароль павінен быць даўжынёй не менш за 8 сімвалаў." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Асноўныя паролі не супадаюць." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Ставячы гэты сцяжок вы пагаджаецеся з наступным:" }, - "acceptPoliciesError": { - "message": "Умовы выкарыстання і Палітыка прыватнасці не былі пацверджаны." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Allow browser integration" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/bg/messages.json b/apps/desktop/src/locales/bg/messages.json index 5af7fa5dbb7..5f9ec73956f 100644 --- a/apps/desktop/src/locales/bg/messages.json +++ b/apps/desktop/src/locales/bg/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Грешен адрес на е-поща." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Главната парола е задължителна." }, - "masterPassLength": { - "message": "Главната парола трябва да съдържа поне 8 знака." + "confirmMasterPasswordRequired": { + "message": "Повторното въвеждане на главната парола е задължително." + }, + "masterPasswordMinLength": { + "message": "Главната парола трябва да е с дължина поне 8 знака." }, "masterPassDoesntMatch": { "message": "Главната парола и потвърждението ѝ не съвпадат." @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "Чрез тази отметка вие се съгласявате със следното:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Условията за използване и политиката за поверителност не бяха приети." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "Ключ за API" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/bn/messages.json b/apps/desktop/src/locales/bn/messages.json index 43762b66b56..a5dad3ce3ab 100644 --- a/apps/desktop/src/locales/bn/messages.json +++ b/apps/desktop/src/locales/bn/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "অকার্যকর ইমেইল ঠিকানা।" }, - "masterPassRequired": { - "message": "মূল পাসওয়ার্ড প্রয়োজন।" + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "মূল পাসওয়ার্ড কমপক্ষে ৮ অক্ষর দীর্ঘ হওয়া উচিত।" + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "মূল পাসওয়ার্ড নিশ্চিতকরণ মেলেনি।" @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "এই বাক্সটি টিক করে আপনি নিম্নলিখিতগুলিতে সম্মত হন:" }, - "acceptPoliciesError": { - "message": "পরিষেবার শর্তাদি এবং গোপনীয়তা নীতি স্বীকার করা হয়নি।" + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Allow browser integration" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/bs/messages.json b/apps/desktop/src/locales/bs/messages.json index b3bf8961c56..6dbb224f184 100644 --- a/apps/desktop/src/locales/bs/messages.json +++ b/apps/desktop/src/locales/bs/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Neispravna email adresa." }, - "masterPassRequired": { - "message": "Potrebna je glavna lozinka." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Glavna lozinka mora imati najmanje 8 znakova." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Potvrda glavne lozinke se ne podudara." @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/ca/messages.json b/apps/desktop/src/locales/ca/messages.json index d9e00929eb7..8df75ca3d6c 100644 --- a/apps/desktop/src/locales/ca/messages.json +++ b/apps/desktop/src/locales/ca/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "L’adreça electrònica no és vàlida." }, - "masterPassRequired": { - "message": "La contrasenya és obligatòria." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "La contrasenya ha de contenir almenys 8 caràcters." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "La confirmació de la contrasenya mestra no coincideix." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Si activeu aquesta casella, indiqueu que esteu d’acord amb el següent:" }, - "acceptPoliciesError": { - "message": "No s’han reconegut les condicions del servei i la declaració de privadesa." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Habilita la integració amb el navegador" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "Clau de l'API" + }, + "neverLockWarning": { + "message": "Esteu segur que voleu utilitzar l'opció \"Mai\"? En configurar les opcions de bloqueig a \"Mai\" s'emmagatzema la clau de xifratge de la vostra caixa forta al vostre dispositiu. Si utilitzeu aquesta opció, heu d'assegurar-vos que conserveu el dispositiu degudament protegit." } } diff --git a/apps/desktop/src/locales/cs/messages.json b/apps/desktop/src/locales/cs/messages.json index e02509d5029..251f8a90fc7 100644 --- a/apps/desktop/src/locales/cs/messages.json +++ b/apps/desktop/src/locales/cs/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Neplatná e-mailová adresa." }, - "masterPassRequired": { - "message": "Hlavní heslo je povinné." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Hlavní heslo musí obsahovat alespoň 8 znaků." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Potvrzení hlavního hesla se neshoduje." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Zaškrtnutím tohoto políčka souhlasím s následujícím:" }, - "acceptPoliciesError": { - "message": "Podmínky služby a zásady ochrany osobních údajů nebyly uznány." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Povolit integraci prohlížeče" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/da/messages.json b/apps/desktop/src/locales/da/messages.json index cbf2b163a13..0daca31da28 100644 --- a/apps/desktop/src/locales/da/messages.json +++ b/apps/desktop/src/locales/da/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Ugyldig e-mailadresse." }, - "masterPassRequired": { - "message": "Hovedadgangskode er påkrævet." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Hovedadgangskoden skal være på mindst 8 tegn." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "De to adgangskoder matcher ikke." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Ved at markere dette felt accepterer du følgende:" }, - "acceptPoliciesError": { - "message": "Servicevilkår og fortrolighedspolitik er ikke blevet bekræftet." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Tillad browserintegration" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API-nøgle" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/de/messages.json b/apps/desktop/src/locales/de/messages.json index 3643edda8e3..0c785b7b395 100644 --- a/apps/desktop/src/locales/de/messages.json +++ b/apps/desktop/src/locales/de/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Ungültige E-Mail-Adresse." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Das Master-Passwort ist erforderlich." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Erneute Eingabe des Master-Passworts ist erforderlich." + }, + "masterPasswordMinLength": { "message": "Das Master-Passwort muss mindestens 8 Zeichen lang sein." }, "masterPassDoesntMatch": { @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Durch Anwählen dieses Kästchens erklärst du dich mit folgendem einverstanden:" }, - "acceptPoliciesError": { - "message": "Die Nutzungsbedingungen und die Datenschutzerklärung wurden nicht akzeptiert." + "acceptPoliciesRequired": { + "message": "Die Nutzungsbedingungen und Datenschutzerklärung wurden nicht akzeptiert." }, "enableBrowserIntegration": { "message": "Browser-Integration aktivieren" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API-Schlüssel" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/el/messages.json b/apps/desktop/src/locales/el/messages.json index 82b8a386f14..ad6b38280ce 100644 --- a/apps/desktop/src/locales/el/messages.json +++ b/apps/desktop/src/locales/el/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Μη έγκυρη διεύθυνση e-mail." }, - "masterPassRequired": { - "message": "Απαιτείται κύριος κωδικός πρόσβασης." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Ο κύριος κωδικός πρέπει να έχει μήκος τουλάχιστον 8 χαρακτήρες." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Η επιβεβαίωση κύριου κωδικού δεν ταιριάζει." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Επιλέγοντας αυτό το πλαίσιο, συμφωνείτε με τα εξής:" }, - "acceptPoliciesError": { - "message": "Οι Όροι Παροχής Υπηρεσιών και η Πολιτική Απορρήτου δεν έχουν αναγνωριστεί." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Ενεργοποίηση ενσωμάτωσης περιηγητή" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "Kλειδί API" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/en_GB/messages.json b/apps/desktop/src/locales/en_GB/messages.json index ae918f7eb18..997855bdf8f 100644 --- a/apps/desktop/src/locales/en_GB/messages.json +++ b/apps/desktop/src/locales/en_GB/messages.json @@ -268,6 +268,9 @@ "lastName": { "message": "Last name" }, + "fullName": { + "message": "Full Name" + }, "address1": { "message": "Address 1" }, @@ -328,6 +331,14 @@ "cfTypeBoolean": { "message": "Boolean" }, + "cfTypeLinked": { + "message": "Linked", + "description": "This describes a field that is 'linked' (related) to another field." + }, + "linkedValue": { + "message": "Linked value", + "description": "This describes a value that is 'linked' (related) to another value." + }, "remove": { "message": "Remove" }, @@ -358,6 +369,12 @@ "overwritePasswordConfirmation": { "message": "Are you sure you want to overwrite the current password?" }, + "overwriteUsername": { + "message": "Overwrite Username" + }, + "overwriteUsernameConfirmation": { + "message": "Are you sure you want to overwrite the current username?" + }, "noneFolder": { "message": "No folder", "description": "This is the folder for uncategorized items" @@ -383,6 +400,18 @@ "length": { "message": "Length" }, + "uppercase": { + "message": "Uppercase (A-Z)" + }, + "lowercase": { + "message": "Lowercase (a-z)" + }, + "numbers": { + "message": "Numbers (0-9)" + }, + "specialCharacters": { + "message": "Special Characters (!@#$%^&*)" + }, "numWords": { "message": "Number of words" }, @@ -446,9 +475,6 @@ "updateKey": { "message": "You cannot use this feature until you update your encryption key." }, - "options": { - "message": "Options" - }, "editedFolder": { "message": "Edited folder" }, @@ -506,10 +532,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -530,12 +559,27 @@ "noItemsInList": { "message": "There are no items to list." }, + "sendVerificationCode": { + "message": "Send a verification code to your email" + }, + "sendCode": { + "message": "Send Code" + }, + "codeSent": { + "message": "Code Sent" + }, "verificationCode": { "message": "Verification code" }, + "confirmIdentity": { + "message": "Confirm your identity to continue." + }, "verificationCodeRequired": { "message": "Verification code is required." }, + "invalidVerificationCode": { + "message": "Invalid verification code" + }, "continue": { "message": "Continue" }, @@ -707,17 +751,17 @@ "loading": { "message": "Loading..." }, - "lockNow": { - "message": "Lock now" + "lockVault": { + "message": "Lock Vault" }, "passwordGenerator": { "message": "Password generator" }, - "emailUs": { - "message": "Email us" + "contactUs": { + "message": "Contact Us" }, - "visitOurWebsite": { - "message": "Visit our website" + "getHelp": { + "message": "Get Help" }, "fileBugReport": { "message": "File a bug report" @@ -853,11 +897,11 @@ "message": "Automatically clear copied values from your clipboard.", "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, - "disableFavicon": { - "message": "Disable website icons" + "enableFavicon": { + "message": "Show website icons" }, - "disableFaviconDesc": { - "message": "Website icons provide a recognisable image next to each login item in your vault." + "faviconDesc": { + "message": "Show a recognisable image next to each login." }, "enableMinToTray": { "message": "Minimise to tray icon" @@ -1165,7 +1209,12 @@ "message": "This password was not found in any known data breaches. It should be safe to use." }, "baseDomain": { - "message": "Base domain" + "message": "Base domain", + "description": "Domain name. Ex. website.com" + }, + "domainName": { + "message": "Domain Name", + "description": "Domain name. Ex. website.com" }, "host": { "message": "Host", @@ -1227,6 +1276,40 @@ "fileFormat": { "message": "File format" }, + "hCaptchaUrl": { + "message": "hCaptcha URL", + "description": "hCaptcha is the name of a website, should not be translated" + }, + "loadAccessibilityCookie": { + "message": "Load Accessibility Cookie" + }, + "registerAccessibilityUser": { + "message": "Register as an accessibility user at", + "description": "ex. Register as an accessibility user at hcaptcha.com" + }, + "copyPasteLink": { + "message": "Copy and paste the link sent to your email below" + }, + "enterhCaptchaUrl": { + "message": "Enter URL to load accessibility cookie for hCaptcha", + "description": "hCaptcha is the name of a website, should not be translated" + }, + "hCaptchaUrlRequired": { + "message": "hCaptcha URL is required", + "description": "hCaptcha is the name of a website, should not be translated" + }, + "invalidUrl": { + "message": "Invalid URL" + }, + "done": { + "message": "Done" + }, + "accessibilityCookieSaved": { + "message": "Accessibility cookie saved!" + }, + "noAccessibilityCookieSaved": { + "message": "No accessibility cookie saved" + }, "warning": { "message": "WARNING", "description": "WARNING (should stay in capitalized letters if the language permits)" @@ -1243,9 +1326,6 @@ "encExportAccountWarningDesc": { "message": "Account encryption keys are unique to each Bitwarden user account, so you can't import an encrypted export into a different account." }, - "exportMasterPassword": { - "message": "Enter your master password to export your vault data." - }, "noOrganizationsList": { "message": "You do not belong to any organisations. Organisations allow you to share items securely with other users." }, @@ -1292,9 +1372,6 @@ "invalidPin": { "message": "Invalid PIN code." }, - "yourVaultIsLockedPinCode": { - "message": "Your vault is locked. Verify your PIN code to continue." - }, "unlockWithWindowsHello": { "message": "Unlock with Windows Hello" }, @@ -1307,11 +1384,11 @@ "touchIdConsentMessage": { "message": "unlock your vault" }, - "noAutoPromptWindowsHello": { - "message": "Do not prompt for Windows Hello on launch." + "autoPromptWindowsHello": { + "message": "Ask for Windows Hello on launch" }, - "noAutoPromptTouchId": { - "message": "Do not prompt for Touch ID on launch." + "autoPromptTouchId": { + "message": "Ask for Touch ID on launch" }, "lockWithMasterPassOnRestart": { "message": "Lock with master password on restart" @@ -1469,8 +1546,8 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { - "message": "Terms of service and privacy policy have not been acknowledged." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Enable browser integration" @@ -1478,18 +1555,18 @@ "enableBrowserIntegrationDesc": { "message": "Browser integration is used for biometrics in browser." }, - "browserIntegrationMasOnlyTitle": { + "browserIntegrationUnsupportedTitle": { "message": "Browser integration not supported" }, "browserIntegrationMasOnlyDesc": { "message": "Unfortunately browser integration is only supported in the Mac App Store version for now." }, - "browserIntegrationWindowsStoreTitle": { - "message": "Browser integration not supported" - }, "browserIntegrationWindowsStoreDesc": { "message": "Unfortunately browser integration is currently not supported in the Windows Store version." }, + "browserIntegrationLinuxDesc": { + "message": "Unfortunately browser integration is currently not supported in the Linux version." + }, "enableBrowserIntegrationFingerprint": { "message": "Require verification for browser integration" }, @@ -1559,7 +1636,8 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "maxAccessCount": { - "message": "Maximum Access Count" + "message": "Maximum Access Count", + "description": "This text will be displayed after a Send has been accessed the maximum amount of times." }, "maxAccessCountDesc": { "message": "If set, users will no longer be able to access this Send once the maximum access count is reached.", @@ -1701,7 +1779,7 @@ "message": "Update Master Password" }, "updateMasterPasswordWarning": { - "message": "Your Master Password was recently changed by an administrator in your organization. In order to access the vault, you must update it now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour." + "message": "Your Master Password was recently changed by an administrator in your organisation. In order to access the vault, you must update it now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour." }, "hours": { "message": "Hours" @@ -1710,7 +1788,7 @@ "message": "Minutes" }, "vaultTimeoutPolicyInEffect": { - "message": "Your organization policies are affecting your vault timeout. Maximum allowed Vault Timeout is $HOURS$ hour(s) and $MINUTES$ minute(s)", + "message": "Your organisation policies are affecting your vault timeout. Maximum allowed Vault Timeout is $HOURS$ hour(s) and $MINUTES$ minute(s)", "placeholders": { "hours": { "content": "$1", @@ -1723,18 +1801,170 @@ } }, "vaultTimeoutTooLarge": { - "message": "Your vault timeout exceeds the restrictions set by your organization." + "message": "Your vault timeout exceeds the restrictions set by your organisation." }, "resetPasswordPolicyAutoEnroll": { "message": "Automatic Enrollment" }, "resetPasswordAutoEnrollInviteWarning": { - "message": "This organization has an enterprise policy that will automatically enroll you in password reset. Enrollment will allow organization administrators to change your master password." + "message": "This organisation has an enterprise policy that will automatically enroll you in password reset. Enrollment will allow organisation administrators to change your master password." }, "vaultExportDisabled": { "message": "Vault Export Disabled" }, "personalVaultExportPolicyInEffect": { - "message": "One or more organization policies prevents you from exporting your personal vault." + "message": "One or more organisation policies prevents you from exporting your personal vault." + }, + "addAccount": { + "message": "Add Account" + }, + "removeMasterPassword": { + "message": "Remove Master Password" + }, + "removedMasterPassword": { + "message": "Master password removed." + }, + "convertOrganizationEncryptionDesc": { + "message": "$ORGANIZATION$ is using SSO with a self-hosted key server. A master password is no longer required to log in for members of this organisation.", + "placeholders": { + "organization": { + "content": "$1", + "example": "My Org Name" + } + } + }, + "leaveOrganization": { + "message": "Leave Organisation" + }, + "leaveOrganizationConfirmation": { + "message": "Are you sure you want to leave this organisation?" + }, + "leftOrganization": { + "message": "You have left the organisation." + }, + "ssoKeyConnectorError": { + "message": "Key Connector error: make sure Key Connector is available and working correctly." + }, + "lockAllVaults": { + "message": "Lock All Vaults" + }, + "accountLimitReached": { + "message": "No more than 5 accounts may be logged in at the same time." + }, + "accountPreferences": { + "message": "Preferences" + }, + "appPreferences": { + "message": "App Settings (All Accounts)" + }, + "accountSwitcherLimitReached": { + "message": "Account limit reached. Log out of an account to add another." + }, + "settingsTitle": { + "message": "App settings for $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "jdoe@example.com" + } + } + }, + "switchAccount": { + "message": "Switch Account" + }, + "options": { + "message": "Options" + }, + "sessionTimeout": { + "message": "Your session has timed out. Please go back and try logging in again." + }, + "exportingPersonalVaultTitle": { + "message": "Exporting Personal Vault" + }, + "exportingPersonalVaultDescription": { + "message": "Only the personal vault items associated with $EMAIL$ will be exported. Organisation vault items will not be included.", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "locked": { + "message": "Locked" + }, + "unlocked": { + "message": "Unlocked" + }, + "generator": { + "message": "Generator" + }, + "whatWouldYouLikeToGenerate": { + "message": "What would you like to generate?" + }, + "passwordType": { + "message": "Password Type" + }, + "regenerateUsername": { + "message": "Regenerate Username" + }, + "generateUsername": { + "message": "Generate Username" + }, + "usernameType": { + "message": "Username Type" + }, + "plusAddressedEmail": { + "message": "Plus Addressed Email", + "description": "Username generator option that appends a random sub-address to the username. For example: address+subaddress@email.com" + }, + "plusAddressedEmailDesc": { + "message": "Use your email provider's sub-addressing capabilities." + }, + "catchallEmail": { + "message": "Catch-all Email" + }, + "catchallEmailDesc": { + "message": "Use your domain's configured catch-all inbox." + }, + "random": { + "message": "Random" + }, + "randomWord": { + "message": "Random Word" + }, + "websiteName": { + "message": "Website Name" + }, + "service": { + "message": "Service" + }, + "allVaults": { + "message": "All Vaults" + }, + "searchOrganization": { + "message": "Search Organisation" + }, + "searchMyVault": { + "message": "Search My Vault" + }, + "forwardedEmail": { + "message": "Forwarded Email Alias" + }, + "forwardedEmailDesc": { + "message": "Generate an email alias with an external forwarding service." + }, + "hostname": { + "message": "Hostname", + "description": "Part of a URL." + }, + "apiAccessToken": { + "message": "API Access Token" + }, + "apiKey": { + "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/en_IN/messages.json b/apps/desktop/src/locales/en_IN/messages.json index ecaf8c8bd0a..c6780182423 100644 --- a/apps/desktop/src/locales/en_IN/messages.json +++ b/apps/desktop/src/locales/en_IN/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/eo/messages.json b/apps/desktop/src/locales/eo/messages.json index ff3c33a6a83..93a3d65f83a 100644 --- a/apps/desktop/src/locales/eo/messages.json +++ b/apps/desktop/src/locales/eo/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/es/messages.json b/apps/desktop/src/locales/es/messages.json index d6e8f935f3e..2f786312cdb 100644 --- a/apps/desktop/src/locales/es/messages.json +++ b/apps/desktop/src/locales/es/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Correo electrónico no válido." }, - "masterPassRequired": { - "message": "Contraseña maestra requerida." + "masterPasswordRequired": { + "message": "Se requiere una contraseña maestra." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Se requiere volver a teclear la contraseña maestra." + }, + "masterPasswordMinLength": { "message": "La contraseña maestra debe tener al menos 8 caracteres." }, "masterPassDoesntMatch": { @@ -895,10 +898,10 @@ "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "enableFavicon": { - "message": "Show website icons" + "message": "Mostrar iconos del sitio web" }, "faviconDesc": { - "message": "Show a recognizable image next to each login." + "message": "Mostrar una imagen reconocible junto a cada inicio de sesión." }, "enableMinToTray": { "message": "Minimizar a icono en la bandeja" @@ -1278,34 +1281,34 @@ "description": "hCaptcha is the name of a website, should not be translated" }, "loadAccessibilityCookie": { - "message": "Load Accessibility Cookie" + "message": "Cargar cookie de accesibilidad" }, "registerAccessibilityUser": { - "message": "Register as an accessibility user at", + "message": "Registrarse como usuario de accesibilidad en", "description": "ex. Register as an accessibility user at hcaptcha.com" }, "copyPasteLink": { - "message": "Copy and paste the link sent to your email below" + "message": "Copia y pega el enlace enviado a tu correo electrónico" }, "enterhCaptchaUrl": { - "message": "Enter URL to load accessibility cookie for hCaptcha", + "message": "Introduzca la URL para cargar la cookie de accesibilidad de hCaptcha", "description": "hCaptcha is the name of a website, should not be translated" }, "hCaptchaUrlRequired": { - "message": "hCaptcha Url is required", + "message": "hCaptcha Url es obligatorio", "description": "hCaptcha is the name of a website, should not be translated" }, "invalidUrl": { - "message": "Invalid Url" + "message": "Url inválida" }, "done": { - "message": "Done" + "message": "Hecho" }, "accessibilityCookieSaved": { - "message": "Accessibility cookie saved!" + "message": "¡Cookie de accesibilidad guardada!" }, "noAccessibilityCookieSaved": { - "message": "No accessibility cookie saved" + "message": "No hay ninguna cookie de accesibilidad guardada" }, "warning": { "message": "ADVERTENCIA", @@ -1382,10 +1385,10 @@ "message": "Verificar para Bitwarden." }, "autoPromptWindowsHello": { - "message": "Ask for Windows Hello on launch" + "message": "Solicicitar Windows Hello al iniciar" }, "autoPromptTouchId": { - "message": "Ask for Touch ID on launch" + "message": "Solicitar Touch ID al iniciar" }, "lockWithMasterPassOnRestart": { "message": "Bloquear con contraseña maestra al reiniciar" @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Al seleccionar esta casilla, acepto lo siguiente:" }, - "acceptPoliciesError": { - "message": "Todavía no has aceptado los términos del servicio y la política de privacidad." + "acceptPoliciesRequired": { + "message": "No ha aceptado los términos del servicio y la política de privacidad." }, "enableBrowserIntegration": { "message": "Habilitar integración con el navegador" @@ -1553,7 +1556,7 @@ "message": "La integración del navegador se usa para la biometría en el mismo." }, "browserIntegrationUnsupportedTitle": { - "message": "Browser integration not supported" + "message": "La integración con el navegador no está soportada" }, "browserIntegrationMasOnlyDesc": { "message": "Por desgracia la integración del navegador sólo está soportada por ahora en la versión de la Mac App Store." @@ -1562,7 +1565,7 @@ "message": "Por desgracia la integración del navegador sólo está soportada por ahora en la versión de Microsoft Store." }, "browserIntegrationLinuxDesc": { - "message": "Unfortunately browser integration is currently not supported in the linux version." + "message": "Por desgracia la integración con el navegador actualmente sólo está soportada en la versión de Microsoft Store." }, "enableBrowserIntegrationFingerprint": { "message": "Requiere verificación para la integración del navegador" @@ -1840,7 +1843,7 @@ "message": "Has abandonado la organización." }, "ssoKeyConnectorError": { - "message": "Key Connector error: make sure Key Connector is available and working correctly." + "message": "Error en el conector de claves: asegúrate de que el conector de claves está disponible y que funciona correctamente." }, "lockAllVaults": { "message": "Bloquear todas las cajas fuertes" @@ -1937,28 +1940,31 @@ "message": "Servicio" }, "allVaults": { - "message": "All Vaults" + "message": "Todas las cajas fuertes" }, "searchOrganization": { - "message": "Search Organization" + "message": "Buscar organizaciones" }, "searchMyVault": { - "message": "Search My Vault" + "message": "Buscar en mi caja fuerte" }, "forwardedEmail": { - "message": "Forwarded Email Alias" + "message": "Alias de correo" }, "forwardedEmailDesc": { - "message": "Generate an email alias with an external forwarding service." + "message": "Generar un alias de correo electrónico con un servicio de reenvío externo." }, "hostname": { - "message": "Hostname", + "message": "Nombre del host", "description": "Part of a URL." }, "apiAccessToken": { - "message": "API Access Token" + "message": "Token de acceso API" }, "apiKey": { - "message": "API Key" + "message": "Clave API" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/et/messages.json b/apps/desktop/src/locales/et/messages.json index bff1505562e..eceeea09330 100644 --- a/apps/desktop/src/locales/et/messages.json +++ b/apps/desktop/src/locales/et/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Vigane e-posti aadress." }, - "masterPassRequired": { - "message": "Vajalik on ülemparooli sisestamine." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Ülemparool peab olema vähemalt 8 tähemärgi pikkune." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Ülemparoolid ei ühti." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Märkeruudu markeerimisel nõustud järgnevaga:" }, - "acceptPoliciesError": { - "message": "Kasutustingimuste ja Privaatsuspoliitikaga pole nõustutud." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Lülita sisse brauseri integratsioon" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API võti" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/eu/messages.json b/apps/desktop/src/locales/eu/messages.json index 8ab1d61861d..90681f641ea 100644 --- a/apps/desktop/src/locales/eu/messages.json +++ b/apps/desktop/src/locales/eu/messages.json @@ -3,10 +3,10 @@ "message": "Bitwarden" }, "filters": { - "message": "Filters" + "message": "Iragazkiak" }, "allItems": { - "message": "All Items" + "message": "Elementu guztiak" }, "favorites": { "message": "Favorites" @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/fa/messages.json b/apps/desktop/src/locales/fa/messages.json index 0c281762e03..181ffb40d76 100644 --- a/apps/desktop/src/locales/fa/messages.json +++ b/apps/desktop/src/locales/fa/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "نشانی رایانامه نامعتبر است." }, - "masterPassRequired": { - "message": "کلمه عبور اصلی ضروری است." + "masterPasswordRequired": { + "message": "گذرواژه اصلی ضروری است." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "تایپ مجدد گذرواژه اصلی نیاز است." + }, + "masterPasswordMinLength": { "message": "طول کلمه عبور اصلی باید حداقل ۸ کاراکتر باشد." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "با علامت زدن این کادر با موارد زیر موافقت می کنید:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "شرایط خدمات و سیاست حفظ حریم خصوصی تأیید نشده است." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "کلید API" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/fi/messages.json b/apps/desktop/src/locales/fi/messages.json index cf147dd9384..620dec2e2b6 100644 --- a/apps/desktop/src/locales/fi/messages.json +++ b/apps/desktop/src/locales/fi/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Virheellinen sähköpostiosoite." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Pääsalasana vaaditaan." }, - "masterPassLength": { - "message": "Pääsalasanan on oltava vähintään 8 merkkiä pitkä." + "confirmMasterPasswordRequired": { + "message": "Pääsalasanan uudelleensyöttö vaaditaan." + }, + "masterPasswordMinLength": { + "message": "Pääsalasanan tulee sisältää ainakin 8 merkkiä." }, "masterPassDoesntMatch": { "message": "Pääsalasanan vahvistus ei täsmää." @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "Valitsemalla tämän ruudun hyväksyt seuraavat:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Käyttöehtoja ja tietosuojakäytäntöä ei ole vahvistettu." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API-avain" + }, + "neverLockWarning": { + "message": "Haluatko varmasti käyttää asetusta \"Ei koskaan\"? Se tallentaa holvisi salausavaimen laitteellesi. Jos käytät asetusta, varmista, että laite on suojattu hyvin." } } diff --git a/apps/desktop/src/locales/fil/messages.json b/apps/desktop/src/locales/fil/messages.json index 8ab1d61861d..87757b9b522 100644 --- a/apps/desktop/src/locales/fil/messages.json +++ b/apps/desktop/src/locales/fil/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/fr/messages.json b/apps/desktop/src/locales/fr/messages.json index c0f4d38eb02..b8f62673cad 100644 --- a/apps/desktop/src/locales/fr/messages.json +++ b/apps/desktop/src/locales/fr/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Adresse e-mail invalide." }, - "masterPassRequired": { - "message": "Le mot de passe maître est requis." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Le mot de passe maître doit au moins contenir 8 caractères." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "La confirmation du mot de passe maître ne correspond pas." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "En cochant cette case, vous acceptez les éléments suivants :" }, - "acceptPoliciesError": { - "message": "Les conditions d'utilisation et la politique de confidentialité n'ont pas été acceptées." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Activer l'intégration avec le navigateur" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "Clé d'IPA" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/he/messages.json b/apps/desktop/src/locales/he/messages.json index b41c046326b..dab46237dc5 100644 --- a/apps/desktop/src/locales/he/messages.json +++ b/apps/desktop/src/locales/he/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "כתובת אימייל לא תקינה." }, - "masterPassRequired": { - "message": "יש להזין את הסיסמה הראשית." + "masterPasswordRequired": { + "message": "הסיסמה הראשית נדרשת." }, - "masterPassLength": { - "message": "הסיסמה הראשית חייבת להיות לפחות באורך 8 תווים." + "confirmMasterPasswordRequired": { + "message": "נדרשת חזרה על הסיסמה הראשית." + }, + "masterPasswordMinLength": { + "message": "הסיסמה הראשית חייבת להכיל לפחות אורך של 8 תווים." }, "masterPassDoesntMatch": { "message": "אימות סיסמה ראשית אינו תואם." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "סימון תיבה זו מהווה את הסכמתך לתנאים הבאים:" }, - "acceptPoliciesError": { - "message": "לא הסכמת לתנאי השירות ומדיניות הפרטיות." + "acceptPoliciesRequired": { + "message": "תנאי השירות ומדיניות הפרטיות לא אושרו." }, "enableBrowserIntegration": { "message": "אפשר אינטגרציה עם הדפדפן" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/hi/messages.json b/apps/desktop/src/locales/hi/messages.json index 1ce89805165..6d17a6ae9a7 100644 --- a/apps/desktop/src/locales/hi/messages.json +++ b/apps/desktop/src/locales/hi/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/hr/messages.json b/apps/desktop/src/locales/hr/messages.json index e6fdd959eda..d7d312be382 100644 --- a/apps/desktop/src/locales/hr/messages.json +++ b/apps/desktop/src/locales/hr/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Nevažeća adresa e-pošte." }, - "masterPassRequired": { - "message": "Potrebna je glavna lozinka." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Glavna lozinka mora imati najmanje 8 znakova." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Potvrda glavne lozinke se ne podudara." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Označavanjem ove kućice slažete se sa sljedećim:" }, - "acceptPoliciesError": { - "message": "Uvjeti korištenja i Pravila privatnosti nisu prihvaćeni." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Uključi integraciju s web preglednikom" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API ključ" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/hu/messages.json b/apps/desktop/src/locales/hu/messages.json index bf9b0bd3130..137b60bcb1b 100644 --- a/apps/desktop/src/locales/hu/messages.json +++ b/apps/desktop/src/locales/hu/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Az email cím érvénytelen." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "A mesterjelszó megadása kötelező." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "A mesterjelszó ismételt megadása kötelező." + }, + "masterPasswordMinLength": { "message": "A mesterjelszó legyen legalább 8 karakter hosszú." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "A kapcsoló bekapcsolásával egyetértünk a következőkkel:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "A szolgáltatási feltételeket és az adatvédelmi irányelveket nem vették figyelembe." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API kulcs" + }, + "neverLockWarning": { + "message": "Biztosan szeretnénk használni a \"Soha\" opciót? A zárolási opciók \"Soha\" értékre állítása a széf titkosítási kulcsát az eszközön tárolja. Ennek az opciónak a használatakor célszerű az eszköz megfelelő védettségét biztosítani." } } diff --git a/apps/desktop/src/locales/id/messages.json b/apps/desktop/src/locales/id/messages.json index fb2ead1100c..2e318f865bf 100644 --- a/apps/desktop/src/locales/id/messages.json +++ b/apps/desktop/src/locales/id/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Alamat email tidak valid." }, - "masterPassRequired": { - "message": "Sandi utama diperlukan." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Kata sandi utama sedikitnya harus 8 karakter." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Konfirmasi sandi utama tidak cocok." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Dengan mencentang kotak ini, anda menyetujui yang berikut:" }, - "acceptPoliciesError": { - "message": "Persyaratan Layanan dan Kebijakan Privasi belum diakui." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Aktifkan integrasi browser" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/it/messages.json b/apps/desktop/src/locales/it/messages.json index e94a6faff06..3befecfdbd3 100644 --- a/apps/desktop/src/locales/it/messages.json +++ b/apps/desktop/src/locales/it/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "L'indirizzo email non è valido." }, - "masterPassRequired": { - "message": "La password principale è obbligatoria." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "La password principale deve avere almeno 8 caratteri." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "La conferma della password principale non corrisponde." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Marcando la casella accetti quanto segue:" }, - "acceptPoliciesError": { - "message": "I termini di servizio e l'informativa sulla privacy non sono stati accettati." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Abilita l'integrazione con il browser" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "Chiave API" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/ja/messages.json b/apps/desktop/src/locales/ja/messages.json index 6cf07bcb88e..cb2ca0fd51e 100644 --- a/apps/desktop/src/locales/ja/messages.json +++ b/apps/desktop/src/locales/ja/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "無効なメールアドレスです。" }, - "masterPassRequired": { - "message": "マスターパスワードは必須です。" + "masterPasswordRequired": { + "message": "マスターパスワードが必要です。" }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "マスターパスワードの再入力が必要です。" + }, + "masterPasswordMinLength": { "message": "マスターパスワードは、少なくとも8文字以上で設定してください。" }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "以下に同意しチェックします:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "利用規約とプライバシーポリシーを確認してください。" }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API キー" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/ka/messages.json b/apps/desktop/src/locales/ka/messages.json index 8ab1d61861d..87757b9b522 100644 --- a/apps/desktop/src/locales/ka/messages.json +++ b/apps/desktop/src/locales/ka/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/km/messages.json b/apps/desktop/src/locales/km/messages.json index 8ab1d61861d..87757b9b522 100644 --- a/apps/desktop/src/locales/km/messages.json +++ b/apps/desktop/src/locales/km/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/kn/messages.json b/apps/desktop/src/locales/kn/messages.json index 746a59f29e6..65fe54da6e9 100644 --- a/apps/desktop/src/locales/kn/messages.json +++ b/apps/desktop/src/locales/kn/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "ಅಮಾನ್ಯ ಇಮೇಲ್ ವಿಳಾಸ." }, - "masterPassRequired": { - "message": "ಮಾಸ್ಟರ್ ಪಾಸ್ವರ್ಡ್ ಅಗತ್ಯವಿದೆ." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "ಮಾಸ್ಟರ್ ಪಾಸ್‌ವರ್ಡ್ ಕನಿಷ್ಠ 8 ಅಕ್ಷರಗಳಷ್ಟು ಉದ್ದವಾಗಿರಬೇಕು." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "ಮಾಸ್ಟರ್ ಪಾಸ್‌ವರ್ಡ್ ದೃಢೀಕರಣವು ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "ಈ ಪೆಟ್ಟಿಗೆಯನ್ನು ಪರಿಶೀಲಿಸುವ ಮೂಲಕ ನೀವು ಈ ಕೆಳಗಿನವುಗಳನ್ನು ಒಪ್ಪುತ್ತೀರಿ:" }, - "acceptPoliciesError": { - "message": "ಸೇವಾ ನಿಯಮಗಳು ಮತ್ತು ಗೌಪ್ಯತೆ ನೀತಿಯನ್ನು ಅಂಗೀಕರಿಸಲಾಗಿಲ್ಲ." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "ಬ್ರೌಸರ್ ಏಕೀಕರಣವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/ko/messages.json b/apps/desktop/src/locales/ko/messages.json index 54b411719b0..cadf428a4cd 100644 --- a/apps/desktop/src/locales/ko/messages.json +++ b/apps/desktop/src/locales/ko/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "잘못된 이메일 주소입니다." }, - "masterPassRequired": { - "message": "마스터 비밀번호는 반드시 입력해야 합니다." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "마스터 비밀번호는 최소 8자 이상이어야 합니다." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "마스터 비밀번호 확인과 마스터 비밀번호가 일치하지 않습니다." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "이 박스를 체크하면 다음에 동의하는 것으로 간주됩니다:" }, - "acceptPoliciesError": { - "message": "서비스 약관 및 개인 정보 보호 정책을 확인하지 않았습니다." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "브라우저와 연결 활성화" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API 키" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/lv/messages.json b/apps/desktop/src/locales/lv/messages.json index 22e0d207d2e..1ad255768cc 100644 --- a/apps/desktop/src/locales/lv/messages.json +++ b/apps/desktop/src/locales/lv/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Nederīga e-pasta adrese." }, - "masterPassRequired": { - "message": "Ir jānorāda galvenā parole." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Galvenajai parolei ir jābūt vismaz 8 rakstzīmes garai." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Galvenās paroles apstiprinājums nesakrīt." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Atzīmējot šo rūtiņu, Tu piekrīti sekojošajam:" }, - "acceptPoliciesError": { - "message": "Nav pieņemti izmantošanas nosacījumi un privātuma politika." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Iespējot pārlūka saistīšanu" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API atslēga" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/me/messages.json b/apps/desktop/src/locales/me/messages.json index 609bdb1e103..5015346a933 100644 --- a/apps/desktop/src/locales/me/messages.json +++ b/apps/desktop/src/locales/me/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Nepravilna email adresa." }, - "masterPassRequired": { - "message": "Potrebna je glavna lozinka." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Glavna lozinka mora imati najmanje 8 karaktera." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Potvrda glavne lozinke ne odgovara." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Označavanjem ovog polja pristajete na sledeće:" }, - "acceptPoliciesError": { - "message": "Uslovi usluge i Politika privatnosti nisu prihvaćeni." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Allow browser integration" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/ml/messages.json b/apps/desktop/src/locales/ml/messages.json index 636afbe2502..2a519f2c577 100644 --- a/apps/desktop/src/locales/ml/messages.json +++ b/apps/desktop/src/locales/ml/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "അസാധുവായ ഇമെയിൽ." }, - "masterPassRequired": { - "message": "പ്രാഥമിക പാസ്‌വേഡ് നിർബന്ധമാണ്‌." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "പ്രാഥമിക പാസ്‌വേഡിന് കുറഞ്ഞത് 8 പ്രതീകങ്ങളെങ്കിലും ദൈർഘ്യമുണ്ടായിരിക്കണം." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "പ്രാഥമിക പാസ്‌വേഡ് സ്ഥിരീകരണം പൊരുത്തപ്പെടുന്നില്ല." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "ഈ ബോക്സ് ചെക്കുചെയ്യുന്നതിലൂടെ നിങ്ങൾ ഇനിപ്പറയുന്നവ അംഗീകരിക്കുന്നു:" }, - "acceptPoliciesError": { - "message": "സേവന നിബന്ധനകളും സ്വകാര്യതാ നയവും അംഗീകരിച്ചിട്ടില്ല." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Allow browser integration" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/nb/messages.json b/apps/desktop/src/locales/nb/messages.json index 5f3be62910b..1c049ce8fce 100644 --- a/apps/desktop/src/locales/nb/messages.json +++ b/apps/desktop/src/locales/nb/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Ugyldig E-postadresse." }, - "masterPassRequired": { - "message": "Superpassordet er påkrevd." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Superpassordet må være ≥8 tegn lang." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Superpassord-bekreftelsen er ikke samsvarende." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Ved å huke av i denne boksen sier du deg enig i følgende:" }, - "acceptPoliciesError": { - "message": "Bruksvilkårene og personvernerklæring er ikke godkjent." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Aktiver nettleserintegrasjon" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API-nøkkel" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/nl/messages.json b/apps/desktop/src/locales/nl/messages.json index 63772ecb07c..d80251cf4fc 100644 --- a/apps/desktop/src/locales/nl/messages.json +++ b/apps/desktop/src/locales/nl/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Ongeldig e-mailadres." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Hoofdwachtwoord vereist." }, - "masterPassLength": { - "message": "Het hoofdwachtwoord moet minimaal 8 tekens lang zijn." + "confirmMasterPasswordRequired": { + "message": "Type je hoofdwachtwoord opnieuw in." + }, + "masterPasswordMinLength": { + "message": "Hoofdwachtwoord moet minimaal 8 tekens lang zijn." }, "masterPassDoesntMatch": { "message": "De hoofdwachtwoorden komen niet overeen." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Door dit vakje aan te vinken, ga je akkoord met het volgende:" }, - "acceptPoliciesError": { - "message": "Algemene voorwaarden en privacybeleid zijn nog niet erkend." + "acceptPoliciesRequired": { + "message": "Je hebt de algemene voorwaarden en het privacybeleid nog niet erkend." }, "enableBrowserIntegration": { "message": "Browserintegratie inschakelen" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Weet je zeker dat je de optie \"Nooit\" wilt gebruiken? De vergrendelingsoptie \"Nooit\" bewaart de sleutel van je kluis op je apparaat. Als je deze optie gebruikt, moet je ervoor zorgen dat je je apparaat naar behoren beschermt." } } diff --git a/apps/desktop/src/locales/nn/messages.json b/apps/desktop/src/locales/nn/messages.json index 50b1f546ff2..bacbbb9a9bc 100644 --- a/apps/desktop/src/locales/nn/messages.json +++ b/apps/desktop/src/locales/nn/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/pl/messages.json b/apps/desktop/src/locales/pl/messages.json index ec79db55d8a..45e6ecbddea 100644 --- a/apps/desktop/src/locales/pl/messages.json +++ b/apps/desktop/src/locales/pl/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Adres e-mail jest nieprawidłowy." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Hasło główne jest wymagane." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Wymagane jest ponowne wpisanie hasła głównego." + }, + "masterPasswordMinLength": { "message": "Hasło główne musi zawierać co najmniej 8 znaków." }, "masterPassDoesntMatch": { @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Zaznaczając tę opcję, akceptujesz:" }, - "acceptPoliciesError": { - "message": "Nie zaakceptowałeś regulaminu i polityki prywatności." + "acceptPoliciesRequired": { + "message": "Warunki użytkowania i polityka prywatności nie zostały zaakceptowane." }, "enableBrowserIntegration": { "message": "Włącz połączenie z przeglądarką" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "Klucz interfejsu API" + }, + "neverLockWarning": { + "message": "Czy na pewno chcesz użyć opcji „Nigdy”? Ustawienie opcji blokady na „Nigdy” powoduje zapisanie klucza szyfrowania sejfu na urządzeniu. Jeśli korzystasz z tej opcji, upewnij się, że urządzenie jest odpowiednio chronione." } } diff --git a/apps/desktop/src/locales/pt_BR/messages.json b/apps/desktop/src/locales/pt_BR/messages.json index 586e1e2998c..85a9c8db348 100644 --- a/apps/desktop/src/locales/pt_BR/messages.json +++ b/apps/desktop/src/locales/pt_BR/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Endereço de e-mail inválido." }, - "masterPassRequired": { - "message": "A senha mestra é obrigatória." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "A senha mestra deve ter pelo menos 8 caracteres." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "A confirmação da senha mestra não corresponde." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Ao marcar esta caixa, você concorda com o seguinte:" }, - "acceptPoliciesError": { - "message": "Os Termos de Serviço e a Política de Privacidade não foram reconhecidos." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Ativar integração com o navegador" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/pt_PT/messages.json b/apps/desktop/src/locales/pt_PT/messages.json index 346685749b7..e3b235d5265 100644 --- a/apps/desktop/src/locales/pt_PT/messages.json +++ b/apps/desktop/src/locales/pt_PT/messages.json @@ -268,6 +268,9 @@ "lastName": { "message": "Último nome" }, + "fullName": { + "message": "Nome Completo" + }, "address1": { "message": "Endereço 1" }, @@ -328,6 +331,14 @@ "cfTypeBoolean": { "message": "Booleano" }, + "cfTypeLinked": { + "message": "Linked", + "description": "This describes a field that is 'linked' (related) to another field." + }, + "linkedValue": { + "message": "Linked value", + "description": "This describes a value that is 'linked' (related) to another value." + }, "remove": { "message": "Remover" }, @@ -350,7 +361,7 @@ "message": "Eliminar anexo" }, "deleteItemConfirmation": { - "message": "Tem a certeza de que pretende eliminar este item?" + "message": "Tem a certeza de que pretende eliminar?" }, "deletedItem": { "message": "Item enviado para o lixo" @@ -358,6 +369,12 @@ "overwritePasswordConfirmation": { "message": "Tem a certeza de que pretende sobreescrever a palavra-passe atual?" }, + "overwriteUsername": { + "message": "Overwrite Username" + }, + "overwriteUsernameConfirmation": { + "message": "Are you sure you want to overwrite the current username?" + }, "noneFolder": { "message": "Nenhuma pasta", "description": "This is the folder for uncategorized items" @@ -383,6 +400,18 @@ "length": { "message": "Comprimento" }, + "uppercase": { + "message": "Maiúsculas (A-Z)" + }, + "lowercase": { + "message": "Minúsculas (a-z)" + }, + "numbers": { + "message": "Números (0-9)" + }, + "specialCharacters": { + "message": "Caracteres Especiais (!@#$%^&*)" + }, "numWords": { "message": "Número de palavras" }, @@ -446,9 +475,6 @@ "updateKey": { "message": "Não pode utilizar esta funcionalidade até atualizar a sua chave de encriptação." }, - "options": { - "message": "Opções" - }, "editedFolder": { "message": "Pasta editada" }, @@ -506,11 +532,14 @@ "invalidEmail": { "message": "Endereço de email inválido." }, - "masterPassRequired": { - "message": "A palavra-passe mestra é requerida." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "A palavra-passe mestra tem de ter pelo menos 8 caracteres." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "A confirmação da palavra-passe mestra não corresponde." @@ -530,12 +559,27 @@ "noItemsInList": { "message": "Não existem itens para listar." }, + "sendVerificationCode": { + "message": "Envie um código de verificação para o seu e-mail" + }, + "sendCode": { + "message": "Enviar o código" + }, + "codeSent": { + "message": "Código enviado" + }, "verificationCode": { "message": "Código de verificação" }, + "confirmIdentity": { + "message": "Confirme a sua identidade para continuar." + }, "verificationCodeRequired": { "message": "O código de verificação é requerido." }, + "invalidVerificationCode": { + "message": "Código de verificação inválido" + }, "continue": { "message": "Continuar" }, @@ -606,7 +650,7 @@ "message": "FIDO2 WebAuthn" }, "webAuthnDesc": { - "message": "Use any WebAuthn enabled security key to access your account." + "message": "Utilize qualquer chave de segurança ativada pela WebAuthn para aceder à sua conta." }, "emailTitle": { "message": "Email" @@ -707,17 +751,17 @@ "loading": { "message": "A carregar..." }, - "lockNow": { - "message": "Bloquear agora" + "lockVault": { + "message": "Bloquear Cofre" }, "passwordGenerator": { "message": "Gerador de palavras-passe" }, - "emailUs": { - "message": "Enviar-nos um email" + "contactUs": { + "message": "Contacte-nos" }, - "visitOurWebsite": { - "message": "Visitar o nosso website" + "getHelp": { + "message": "Obter Ajuda" }, "fileBugReport": { "message": "Submeter um relatório de bug" @@ -853,11 +897,11 @@ "message": "Limpar automaticamente valores copiados da sua área de transferência.", "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, - "disableFavicon": { - "message": "Desativar ícones de websites" + "enableFavicon": { + "message": "Show website icons" }, - "disableFaviconDesc": { - "message": "Os ícones de websites providenciam uma imagem reconhecível ao lado de cada item de credencial no seu cofre." + "faviconDesc": { + "message": "Show a recognizable image next to each login." }, "enableMinToTray": { "message": "Minimizar para ícone de bandeja" @@ -866,10 +910,10 @@ "message": "Ao minimizar a janela, mostrar um ícone na bandeja do sistema em alternativa." }, "enableMinToMenuBar": { - "message": "Minimize to menu bar" + "message": "Minimizar para a barra do menu" }, "enableMinToMenuBarDesc": { - "message": "When minimizing the window, show an icon in the menu bar instead." + "message": "Ao minimizar a janela, mostrar em alternativa um ícone na barra do menu." }, "enableCloseToTray": { "message": "Fechar para ícone de bandeja" @@ -878,10 +922,10 @@ "message": "Ao fechar a janela, mostrar um ícone na bandeja do sistema em alternativa." }, "enableCloseToMenuBar": { - "message": "Close to menu bar" + "message": "Próximo da barra do menu" }, "enableCloseToMenuBarDesc": { - "message": "When closing the window, show an icon in the menu bar instead." + "message": "Ao fechar a janela, mostrar em alternativa um ícone na barra do menu." }, "enableTray": { "message": "Ativar ícone de bandeja" @@ -905,7 +949,7 @@ "message": "Start automatically on login" }, "openAtLoginDesc": { - "message": "Start the Bitwarden Desktop application automatically on login." + "message": "Start the Bitwarden desktop application automatically on login." }, "alwaysShowDock": { "message": "Always show in the Dock" @@ -1165,7 +1209,12 @@ "message": "Esta palavra-passe não foi encontrada em nenhuma brecha de dados conhecida. Esta deve ser segura de utilizar." }, "baseDomain": { - "message": "Domínio base" + "message": "Domínio base", + "description": "Domain name. Ex. website.com" + }, + "domainName": { + "message": "Domain Name", + "description": "Domain name. Ex. website.com" }, "host": { "message": "Servidor", @@ -1218,7 +1267,7 @@ "description": "ex. Date this item was updated" }, "datePasswordUpdated": { - "message": "Palavra passe atualizada", + "message": "Palavra-passe atualizada", "description": "ex. Date this password was updated" }, "exportVault": { @@ -1227,6 +1276,40 @@ "fileFormat": { "message": "Formato do ficheiro" }, + "hCaptchaUrl": { + "message": "hCaptcha Url", + "description": "hCaptcha is the name of a website, should not be translated" + }, + "loadAccessibilityCookie": { + "message": "Load Accessibility Cookie" + }, + "registerAccessibilityUser": { + "message": "Register as an accessibility user at", + "description": "ex. Register as an accessibility user at hcaptcha.com" + }, + "copyPasteLink": { + "message": "Copy and paste the link sent to your email below" + }, + "enterhCaptchaUrl": { + "message": "Enter URL to load accessibility cookie for hCaptcha", + "description": "hCaptcha is the name of a website, should not be translated" + }, + "hCaptchaUrlRequired": { + "message": "hCaptcha Url is required", + "description": "hCaptcha is the name of a website, should not be translated" + }, + "invalidUrl": { + "message": "Invalid Url" + }, + "done": { + "message": "Done" + }, + "accessibilityCookieSaved": { + "message": "Accessibility cookie saved!" + }, + "noAccessibilityCookieSaved": { + "message": "No accessibility cookie saved" + }, "warning": { "message": "AVISO", "description": "WARNING (should stay in capitalized letters if the language permits)" @@ -1243,9 +1326,6 @@ "encExportAccountWarningDesc": { "message": "Account encryption keys are unique to each Bitwarden user account, so you can't import an encrypted export into a different account." }, - "exportMasterPassword": { - "message": "Introduza a sua palavra-passe mestra para exportar os dados do seu cofre." - }, "noOrganizationsList": { "message": "Você não pertence a nenhuma organização. Organizações permitem-lhe partilhar itens em segurança com outros utilizadores." }, @@ -1292,9 +1372,6 @@ "invalidPin": { "message": "Código PIN inválido." }, - "yourVaultIsLockedPinCode": { - "message": "O seu cofre está bloqueado. Verifique o seu PIN para continuar." - }, "unlockWithWindowsHello": { "message": "Desbloquear com Windows Hello" }, @@ -1307,11 +1384,11 @@ "touchIdConsentMessage": { "message": "Verificar para Bitwarden." }, - "noAutoPromptWindowsHello": { - "message": "Do not prompt for Windows Hello on launch." + "autoPromptWindowsHello": { + "message": "Ask for Windows Hello on launch" }, - "noAutoPromptTouchId": { - "message": "Do not prompt for Touch ID on launch." + "autoPromptTouchId": { + "message": "Ask for Touch ID on launch" }, "lockWithMasterPassOnRestart": { "message": "Bloquear com palavra-passe mestra ao reiniciar" @@ -1469,32 +1546,32 @@ "acceptPolicies": { "message": "Ao marcar esta caixa concorda com o seguinte:" }, - "acceptPoliciesError": { - "message": "Os Termos de Serviço e a Política de Privacidade não foram aceites." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { - "message": "Enable browser integration" + "message": "Allow browser integration" }, "enableBrowserIntegrationDesc": { "message": "Browser integration is used for biometrics in browser." }, - "browserIntegrationMasOnlyTitle": { - "message": "Browser integration not supported" + "browserIntegrationUnsupportedTitle": { + "message": "Integração com o navegador não suportada" }, "browserIntegrationMasOnlyDesc": { "message": "Unfortunately browser integration is only supported in the Mac App Store version for now." }, - "browserIntegrationWindowsStoreTitle": { - "message": "Browser integration not supported" - }, "browserIntegrationWindowsStoreDesc": { "message": "Unfortunately browser integration is currently not supported in the Windows Store version." }, + "browserIntegrationLinuxDesc": { + "message": "Infelizmente, a integração com o navegador não é, atualmente, suportada para a versão linux." + }, "enableBrowserIntegrationFingerprint": { "message": "Require verification for browser integration" }, "enableBrowserIntegrationFingerprintDesc": { - "message": "Enable an additional layer of security by requiring fingerprint phrase validation when establishing a link between your desktop and browser. When enabled, this requires user intervention and verification each time a connection is established." + "message": "Add an additional layer of security by requiring fingerprint phrase confirmation when establishing a link between your desktop and browser. This requires user action and verification each time a connection is created." }, "approve": { "message": "Approve" @@ -1521,45 +1598,46 @@ "message": "An organization policy is affecting your ownership options." }, "allSends": { - "message": "All Sends", + "message": "Tudo o que foi enviado", "description": "'Sends' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendTypeFile": { - "message": "File" + "message": "Ficheiro" }, "sendTypeText": { - "message": "Text" + "message": "Texto" }, "searchSends": { - "message": "Search Sends", + "message": "Pesquisar 'Sends'", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editSend": { - "message": "Edit Send", + "message": "Editar Envio", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "myVault": { - "message": "My Vault" + "message": "O meu Cofre" }, "text": { - "message": "Text" + "message": "Texto" }, "deletionDate": { - "message": "Deletion Date" + "message": "Data da eliminação" }, "deletionDateDesc": { "message": "The Send will be permanently deleted on the specified date and time.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "expirationDate": { - "message": "Expiration Date" + "message": "Data de Expiração" }, "expirationDateDesc": { "message": "If set, access to this Send will expire on the specified date and time.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "maxAccessCount": { - "message": "Maximum Access Count" + "message": "Maximum Access Count", + "description": "This text will be displayed after a Send has been accessed the maximum amount of times." }, "maxAccessCountDesc": { "message": "If set, users will no longer be able to access this Send once the maximum access count is reached.", @@ -1581,11 +1659,11 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendLink": { - "message": "Send link", + "message": "Enviar ligação", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendLinkLabel": { - "message": "Send Link", + "message": "Enviar Ligação", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "textHiddenByDefault": { @@ -1605,24 +1683,24 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "newPassword": { - "message": "New Password" + "message": "Nova palavra-passe" }, "whatTypeOfSend": { - "message": "What type of Send is this?", + "message": "Qual será o tipo de envio?", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "createSend": { - "message": "Create Send", + "message": "Criar envio", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendTextDesc": { - "message": "The text you want to send." + "message": "O que deseja enviar." }, "sendFileDesc": { - "message": "The file you want to send." + "message": "O ficheiro que deseja enviar." }, "days": { - "message": "$DAYS$ days", + "message": "$DAYS$ Dias", "placeholders": { "days": { "content": "$1", @@ -1631,83 +1709,83 @@ } }, "oneDay": { - "message": "1 day" + "message": "1 dia" }, "custom": { - "message": "Custom" + "message": "Personalizado" }, "deleteSendConfirmation": { - "message": "Are you sure you want to delete this Send?", + "message": "Tem a certeza que quer eliminar?", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "copySendLinkToClipboard": { - "message": "Copy Send link to clipboard", + "message": "Copiar link para a área de transferências", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "copySendLinkOnSave": { - "message": "Copy the link to share this Send to my clipboard upon save." + "message": "Copie o link para o partilhar para a área de transferências ao guardar." }, "sendDisabled": { - "message": "Send disabled", + "message": "Envio desativado", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendDisabledWarning": { - "message": "Due to an enterprise policy, you are only able to delete an existing Send.", + "message": "Devido a uma política corporativa, apenas é possível eliminar um envio já existente.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "copyLink": { - "message": "Copy link" + "message": "Copiar link" }, "disabled": { - "message": "Disabled" + "message": "Desativado" }, "maxAccessCountReached": { "message": "Max access count reached" }, "expired": { - "message": "Expired" + "message": "Expirou" }, "pendingDeletion": { - "message": "Pending deletion" + "message": "Data pendente" }, "webAuthnAuthenticate": { - "message": "Authenticate WebAuthn" + "message": "Autenticar WebAuthn" }, "hideEmail": { - "message": "Hide my email address from recipients." + "message": "Ocultar meu endereço de e-mail aos destinatários." }, "sendOptionsPolicyInEffect": { - "message": "One or more organization policies are affecting your Send options." + "message": "Uma ou mais políticas da organização estão a afetar as suas opções de envio." }, "emailVerificationRequired": { - "message": "Email Verification Required" + "message": "Verificação de Email Necessária" }, "emailVerificationRequiredDesc": { - "message": "You must verify your email to use this feature." + "message": "É necessário verificar o seu e-mail para usar esta funcionalidade." }, "passwordPrompt": { - "message": "Master password re-prompt" + "message": "Redefinir palavra-passe mestra" }, "passwordConfirmation": { - "message": "Master password confirmation" + "message": "Confirmação da palavra-passe mestra" }, "passwordConfirmationDesc": { - "message": "This action is protected. To continue, please re-enter your master password to verify your identity." + "message": "Esta ação está protegida. Para continuar, por favor reinsira a sua palavra-passe mestra para verificarmos a sua identidade." }, "updatedMasterPassword": { - "message": "Updated Master Password" + "message": "Palavra-passe Mestra Atualizada" }, "updateMasterPassword": { - "message": "Update Master Password" + "message": "Atualizar palavra-passe mestra" }, "updateMasterPasswordWarning": { "message": "Your Master Password was recently changed by an administrator in your organization. In order to access the vault, you must update it now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour." }, "hours": { - "message": "Hours" + "message": "Horas" }, "minutes": { - "message": "Minutes" + "message": "Minutos" }, "vaultTimeoutPolicyInEffect": { "message": "Your organization policies are affecting your vault timeout. Maximum allowed Vault Timeout is $HOURS$ hour(s) and $MINUTES$ minute(s)", @@ -1723,18 +1801,170 @@ } }, "vaultTimeoutTooLarge": { - "message": "Your vault timeout exceeds the restrictions set by your organization." + "message": "O tempo limite do seu cofre excede as restrições definidas pela sua organização." }, "resetPasswordPolicyAutoEnroll": { - "message": "Automatic Enrollment" + "message": "Registo automático" }, "resetPasswordAutoEnrollInviteWarning": { "message": "This organization has an enterprise policy that will automatically enroll you in password reset. Enrollment will allow organization administrators to change your master password." }, "vaultExportDisabled": { - "message": "Vault Export Disabled" + "message": "Exportação de cofre inválida" }, "personalVaultExportPolicyInEffect": { - "message": "One or more organization policies prevents you from exporting your personal vault." + "message": "Uma ou mais políticas da organização impedem que exporte o seu cofre pessoal." + }, + "addAccount": { + "message": "Adicionar Conta" + }, + "removeMasterPassword": { + "message": "Remover palavra-passe mestra" + }, + "removedMasterPassword": { + "message": "Palavra-passe mestra removida." + }, + "convertOrganizationEncryptionDesc": { + "message": "$ORGANIZATION$ is using SSO with a self-hosted key server. A master password is no longer required to log in for members of this organization.", + "placeholders": { + "organization": { + "content": "$1", + "example": "My Org Name" + } + } + }, + "leaveOrganization": { + "message": "Deixar a organização" + }, + "leaveOrganizationConfirmation": { + "message": "Tem a certeza que quer deixar a organização?" + }, + "leftOrganization": { + "message": "Saiu da organização." + }, + "ssoKeyConnectorError": { + "message": "Key Connector error: make sure Key Connector is available and working correctly." + }, + "lockAllVaults": { + "message": "Bloquear Todos os Cofres" + }, + "accountLimitReached": { + "message": "Não é possível iniciar sessão com mais de 5 contas ao mesmo tempo." + }, + "accountPreferences": { + "message": "Preferências" + }, + "appPreferences": { + "message": "Definições da Aplicação (Todas as Contas)" + }, + "accountSwitcherLimitReached": { + "message": "Limite de contas atingido. Termine a sessão de uma das contas para adicionar outra." + }, + "settingsTitle": { + "message": "Definições da aplicação para $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "jdoe@example.com" + } + } + }, + "switchAccount": { + "message": "Mudar de Conta" + }, + "options": { + "message": "Opções" + }, + "sessionTimeout": { + "message": "A sua sessão expirou. Por favor, volte atrás e tente iniciar sessão novamente." + }, + "exportingPersonalVaultTitle": { + "message": "A Exportar Cofre Pessoal" + }, + "exportingPersonalVaultDescription": { + "message": "Apenas os itens do cofre pessoal associado ao $EMAIL$ serão exportados. Os itens do cofre da organização não serão incluídos.", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "locked": { + "message": "Bloqueado" + }, + "unlocked": { + "message": "Desbloqueado" + }, + "generator": { + "message": "Generator" + }, + "whatWouldYouLikeToGenerate": { + "message": "What would you like to generate?" + }, + "passwordType": { + "message": "Password Type" + }, + "regenerateUsername": { + "message": "Regenerate Username" + }, + "generateUsername": { + "message": "Generate Username" + }, + "usernameType": { + "message": "Username Type" + }, + "plusAddressedEmail": { + "message": "Plus Addressed Email", + "description": "Username generator option that appends a random sub-address to the username. For example: address+subaddress@email.com" + }, + "plusAddressedEmailDesc": { + "message": "Use your email provider's sub-addressing capabilities." + }, + "catchallEmail": { + "message": "Catch-all Email" + }, + "catchallEmailDesc": { + "message": "Use your domain's configured catch-all inbox." + }, + "random": { + "message": "Random" + }, + "randomWord": { + "message": "Random Word" + }, + "websiteName": { + "message": "Website Name" + }, + "service": { + "message": "Service" + }, + "allVaults": { + "message": "Todos os Cofres" + }, + "searchOrganization": { + "message": "Procurar Organização" + }, + "searchMyVault": { + "message": "Procurar no meu Cofre" + }, + "forwardedEmail": { + "message": "Forwarded Email Alias" + }, + "forwardedEmailDesc": { + "message": "Generate an email alias with an external forwarding service." + }, + "hostname": { + "message": "Hostname", + "description": "Part of a URL." + }, + "apiAccessToken": { + "message": "API Access Token" + }, + "apiKey": { + "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/ro/messages.json b/apps/desktop/src/locales/ro/messages.json index e03051713a9..131044f8474 100644 --- a/apps/desktop/src/locales/ro/messages.json +++ b/apps/desktop/src/locales/ro/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Adresă de e-mail greșită." }, - "masterPassRequired": { - "message": "Este parola principală este necesară." + "masterPasswordRequired": { + "message": "Este necesară o parolă principală." }, - "masterPassLength": { - "message": "Parola principală trebuie să conțină minimum 8 caractere." + "confirmMasterPasswordRequired": { + "message": "Este necesară rescrierea parolei principale." + }, + "masterPasswordMinLength": { + "message": "Parola principală trebuie să aibă cel puțin 8 caractere." }, "masterPassDoesntMatch": { "message": "Parola principală și confirmarea ei nu coincid!" @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "Dacă bifați această casetă sunteți de acord cu următoarele:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Termeni de utilizare și Politica de confidențialitate nu au fost recunoscute." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "Cheie API" + }, + "neverLockWarning": { + "message": "Sunteți sigur că doriți să folosiți opțiunea „Niciodată”? Setarea opțiunilor de blocare la „Niciodată” stochează cheia de criptare a seifului pe dispozitivul dumneavoastră. Dacă utilizați această opțiune, trebuie să vă asigurați că vă păstrați dispozitivul protejat corespunzător." } } diff --git a/apps/desktop/src/locales/ru/messages.json b/apps/desktop/src/locales/ru/messages.json index 9ccca295e3c..6e3d9eb6b2b 100644 --- a/apps/desktop/src/locales/ru/messages.json +++ b/apps/desktop/src/locales/ru/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Неверный адрес email." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Требуется мастер-пароль." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Необходимо повторно ввести мастер-пароль." + }, + "masterPasswordMinLength": { "message": "Мастер-пароль должен содержать не менее 8 символов." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "Отметив этот флажок, вы соглашаетесь со следующим:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Условия предоставления услуг и Политика конфиденциальности не были подтверждены." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "Ключ API" + }, + "neverLockWarning": { + "message": "Вы действительно хотите отключить блокировку хранилища? В этом случае ключ шифрования вашего хранилища будет сохранен на вашем устройстве. Отключая блокировку, вы должны убедиться, что ваше устройство надежно защищено." } } diff --git a/apps/desktop/src/locales/si/messages.json b/apps/desktop/src/locales/si/messages.json index 16df6d15ab5..69b08405f6b 100644 --- a/apps/desktop/src/locales/si/messages.json +++ b/apps/desktop/src/locales/si/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "වලංගු නොවන වි-තැපැල් ලිපිනයකි." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/sk/messages.json b/apps/desktop/src/locales/sk/messages.json index 5fe922b407c..ca76b592737 100644 --- a/apps/desktop/src/locales/sk/messages.json +++ b/apps/desktop/src/locales/sk/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Neplatná emailová adresa." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Hlavné heslo je povinné." }, - "masterPassLength": { - "message": "Hlavné heslo musí obsahovať aspoň 8 znakov." + "confirmMasterPasswordRequired": { + "message": "Vyžaduje sa opätovné zadanie hlavného hesla." + }, + "masterPasswordMinLength": { + "message": "Hlavné heslo musí mať aspoň 8 znakov." }, "masterPassDoesntMatch": { "message": "Potvrdenie hlavného hesla sa nezhoduje." @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "Označením tohto políčka súhlasíte s nasledovným:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Neboli akceptované Podmienky používania a zásady Ochrany osobných údajov." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API kľúč" + }, + "neverLockWarning": { + "message": "Ste si istí, že chcete použiť možnosť \"Nikdy\"? Táto predvoľba ukladá šifrovací kľúč od trezora priamo na zariadení. Ak použijete túto možnosť, mali by ste svoje zariadenie náležite zabezpečiť." } } diff --git a/apps/desktop/src/locales/sl/messages.json b/apps/desktop/src/locales/sl/messages.json index 8c3264668a1..d3d9a84f9ce 100644 --- a/apps/desktop/src/locales/sl/messages.json +++ b/apps/desktop/src/locales/sl/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Neveljaven epoštni naslov." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/sr/messages.json b/apps/desktop/src/locales/sr/messages.json index 8d6eff428fc..7f9711d8d4e 100644 --- a/apps/desktop/src/locales/sr/messages.json +++ b/apps/desktop/src/locales/sr/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Неисправан имејл." }, - "masterPassRequired": { - "message": "Главна Лозинка је неопходна." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Главна Лозинка треба имати бар 8 знака." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Потврђена Главна Лозинка се не подудара." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Означавањем овог поља пристајете на следеће:" }, - "acceptPoliciesError": { - "message": "Услови услуге и Политика приватности нису прихваћени." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Укључи интеграцију са претраживачем" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "АПИ Кључ" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/sv/messages.json b/apps/desktop/src/locales/sv/messages.json index 9cbca248569..d6444fb9740 100644 --- a/apps/desktop/src/locales/sv/messages.json +++ b/apps/desktop/src/locales/sv/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Ogiltig e-postadress." }, - "masterPassRequired": { - "message": "Huvudlösenord krävs." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Huvudlösenordet måste vara minst 8 tecken långt." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Huvudlösenorden stämmer inte överens." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Genom att markera denna ruta godkänner du följande:" }, - "acceptPoliciesError": { - "message": "Användarvillkoren och Integritetspolicyn har inte accepterats." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { "message": "Aktivera webbläsarintegration" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API-nyckel" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/th/messages.json b/apps/desktop/src/locales/th/messages.json index 4807cc0dde4..c938879608c 100644 --- a/apps/desktop/src/locales/th/messages.json +++ b/apps/desktop/src/locales/th/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "ที่อยู่อีเมลไม่ถูกต้อง" }, - "masterPassRequired": { - "message": "จำเป็นต้องมีรหัสผ่านหลัก" + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API Key" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/tr/messages.json b/apps/desktop/src/locales/tr/messages.json index d269529e5d3..bd38b0f5607 100644 --- a/apps/desktop/src/locales/tr/messages.json +++ b/apps/desktop/src/locales/tr/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "Geçersiz e-posta adresi." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Ana parola gereklidir." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Ana parolayı yeniden yazmalısınız." + }, + "masterPasswordMinLength": { "message": "Ana parola en az 8 karakter uzunluğunda olmalıdır." }, "masterPassDoesntMatch": { @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "Bu kutuyu işaretleyerek aşağıdakileri kabul etmiş olursunuz:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Hizmet Koşulları ve Gizlilik Politikası kabul edilmemiş." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API anahtarı" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/uk/messages.json b/apps/desktop/src/locales/uk/messages.json index cd1665e48f7..fe93cae6947 100644 --- a/apps/desktop/src/locales/uk/messages.json +++ b/apps/desktop/src/locales/uk/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Неправильна адреса е-пошти." }, - "masterPassRequired": { - "message": "Потрібен головний пароль." + "masterPasswordRequired": { + "message": "Необхідно ввести головний пароль." }, - "masterPassLength": { - "message": "Довжина головного пароля повинна бути не менше 8 символів." + "confirmMasterPasswordRequired": { + "message": "Необхідно повторно ввести головний пароль." + }, + "masterPasswordMinLength": { + "message": "Довжина головного пароля має бути принаймні 8 символів." }, "masterPassDoesntMatch": { "message": "Підтвердження головного пароля не збігається." @@ -1000,7 +1003,7 @@ "message": "Перезапустити для оновлення" }, "restartToUpdateDesc": { - "message": "Версія $VERSION_NUM$ готова до встановлення. Для завершення встановлення ви повинні перезапустити програму. Хочете зробити це зараз?", + "message": "Версія $VERSION_NUM$ готова до встановлення. Для завершення встановлення необхідно перезапустити програму. Хочете зробити це зараз?", "placeholders": { "version_num": { "content": "$1", @@ -1318,7 +1321,7 @@ "message": "Експортовані дані вашого сховища знаходяться в незашифрованому вигляді. Вам не слід зберігати чи надсилати їх через незахищені канали (наприклад, е-поштою). Після використання негайно видаліть їх." }, "encExportKeyWarningDesc": { - "message": "Цей експорт шифрує ваші дані за допомогою ключа шифрування облікового запису. Якщо ви коли-небудь оновите ключ шифрування облікового запису, ви повинні виконати експорт знову, оскільки не зможете розшифрувати цей файл експорту." + "message": "Цей експорт шифрує ваші дані за допомогою ключа шифрування облікового запису. Якщо ви коли-небудь оновите ключ шифрування облікового запису, необхідно виконати експорт знову, оскільки не зможете розшифрувати цей файл експорту." }, "encExportAccountWarningDesc": { "message": "Ключі шифрування унікальні для кожного облікового запису користувача Bitwarden, тому ви не можете імпортувати зашифрований експорт до іншого облікового запису." @@ -1403,7 +1406,7 @@ "message": "Приховувати до панелі завдань" }, "selectOneCollection": { - "message": "Ви повинні обрати принаймні одну збірку." + "message": "Необхідно вибрати принаймні одну збірку." }, "premiumUpdated": { "message": "Ви оновилися до версії premium." @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "Позначивши цей прапорець, ви погоджуєтеся з:" }, - "acceptPoliciesError": { - "message": "Умови користування та політика приватності не погоджені." + "acceptPoliciesRequired": { + "message": "Ви не погодилися з умовами користування та політикою приватності." }, "enableBrowserIntegration": { "message": "Дозволити інтеграцію з браузером" @@ -1776,7 +1779,7 @@ "message": "Оновити головний пароль" }, "updateMasterPasswordWarning": { - "message": "Ваш головний пароль нещодавно був змінений адміністратором організації. Щоб отримати доступ до сховища, ви повинні оновити його зараз. Продовживши, ви вийдете з поточного сеансу, після чого необхідно буде повторно виконати вхід. Сеанси на інших пристроях можуть залишатися активними протягом однієї години." + "message": "Ваш головний пароль нещодавно був змінений адміністратором організації. Щоб отримати доступ до сховища, вам необхідно оновити його зараз. Продовживши, ви вийдете з поточного сеансу, після чого потрібно буде повторно виконати вхід. Сеанси на інших пристроях можуть залишатися активними протягом однієї години." }, "hours": { "message": "Годин" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "Ключ API" + }, + "neverLockWarning": { + "message": "Ви впевнені, що ніколи не хочете блокувати? Встановивши параметр блокування \"Ніколи\", ключ шифрування сховища зберігатиметься на вашому пристрої. Користуючись цим параметром, ви маєте бути впевнені в тому, що ваш пристрій надійно захищений." } } diff --git a/apps/desktop/src/locales/vi/messages.json b/apps/desktop/src/locales/vi/messages.json index e0d2d729c5f..53570e39007 100644 --- a/apps/desktop/src/locales/vi/messages.json +++ b/apps/desktop/src/locales/vi/messages.json @@ -532,11 +532,14 @@ "invalidEmail": { "message": "Địa chỉ email không hợp lệ." }, - "masterPassRequired": { - "message": "Mật khẩu chính là bắt buộc." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Mật khẩu chính phải có ít nhất 8 kí tự." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Xác nhận mật khẩu chính không khớp." @@ -1543,7 +1546,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "Khóa API" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } } diff --git a/apps/desktop/src/locales/zh_CN/messages.json b/apps/desktop/src/locales/zh_CN/messages.json index f4a1443cffd..b62efe23252 100644 --- a/apps/desktop/src/locales/zh_CN/messages.json +++ b/apps/desktop/src/locales/zh_CN/messages.json @@ -116,7 +116,7 @@ "message": "自定义字段" }, "launch": { - "message": "启动" + "message": "前往" }, "copyValue": { "message": "复制值", @@ -126,7 +126,7 @@ "message": "复制到剪贴板时最小化" }, "minimizeOnCopyToClipboardDesc": { - "message": "复制项目数据到剪贴板时最小化。" + "message": "复制项目数据到剪贴板后最小化应用程序。" }, "toggleVisibility": { "message": "切换可见性" @@ -268,6 +268,9 @@ "lastName": { "message": "姓" }, + "fullName": { + "message": "全名" + }, "address1": { "message": "地址 1" }, @@ -320,13 +323,21 @@ "message": "拖动排序" }, "cfTypeText": { - "message": "文本" + "message": "文本型" }, "cfTypeHidden": { - "message": "隐藏的" + "message": "隐藏型" }, "cfTypeBoolean": { - "message": "布尔值" + "message": "布尔型" + }, + "cfTypeLinked": { + "message": "链接型", + "description": "This describes a field that is 'linked' (related) to another field." + }, + "linkedValue": { + "message": "链接的值", + "description": "This describes a value that is 'linked' (related) to another value." }, "remove": { "message": "移除" @@ -358,6 +369,12 @@ "overwritePasswordConfirmation": { "message": "您确定要覆盖当前密码吗?" }, + "overwriteUsername": { + "message": "覆盖用户名" + }, + "overwriteUsernameConfirmation": { + "message": "您确定要覆盖当前用户名吗?" + }, "noneFolder": { "message": "默认文件夹", "description": "This is the folder for uncategorized items" @@ -383,6 +400,18 @@ "length": { "message": "长度" }, + "uppercase": { + "message": "大写 (A-Z)" + }, + "lowercase": { + "message": "小写 (a-z)" + }, + "numbers": { + "message": "数字 (0-9)" + }, + "specialCharacters": { + "message": "特殊字符 (!@#$%^&*)" + }, "numWords": { "message": "单词数" }, @@ -446,9 +475,6 @@ "updateKey": { "message": "在您更新加密密钥前,您不能使用此功能。" }, - "options": { - "message": "选项" - }, "editedFolder": { "message": "文件夹已编辑" }, @@ -462,10 +488,10 @@ "message": "文件夹已删除" }, "loginOrCreateNewAccount": { - "message": "登录或者创建一个账号来访问您的安全密码库。" + "message": "登录或者创建一个账户来访问您的安全密码库。" }, "createAccount": { - "message": "创建账号" + "message": "创建账户" }, "logIn": { "message": "登录" @@ -495,7 +521,7 @@ "message": "密码提示" }, "enterEmailToGetHint": { - "message": "请输入您账号的电子邮件地址来接收密码提示。" + "message": "请输入您账户的电子邮件地址来接收密码提示。" }, "getMasterPasswordHint": { "message": "获取主密码提示" @@ -506,10 +532,13 @@ "invalidEmail": { "message": "无效的电子邮件地址。" }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "必须填写主密码。" }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "必须填写确认主密码。" + }, + "masterPasswordMinLength": { "message": "主密码至少需要 8 个字符。" }, "masterPassDoesntMatch": { @@ -530,12 +559,27 @@ "noItemsInList": { "message": "没有可列出的项目。" }, + "sendVerificationCode": { + "message": "发送验证码到您的电子邮箱" + }, + "sendCode": { + "message": "发送验证码" + }, + "codeSent": { + "message": "验证码已发送" + }, "verificationCode": { "message": "验证码" }, + "confirmIdentity": { + "message": "确认后继续。" + }, "verificationCodeRequired": { "message": "必须填写验证码。" }, + "invalidVerificationCode": { + "message": "无效的验证码" + }, "continue": { "message": "继续" }, @@ -573,7 +617,7 @@ "message": "将您的 YubiKey 插入计算机的 USB 端口,然后按下按钮。" }, "insertU2f": { - "message": "将您的安全钥匙插入计算机的 USB 端口。如果它有一个按钮,按下它。" + "message": "将您的安全钥匙插入计算机的 USB 端口。如果它有按钮,请按下它。" }, "recoveryCodeDesc": { "message": "失去访问您所有的双重身份验证设备?请使用您的恢复代码来禁用您账户中所有的两步登录提供程序。" @@ -606,7 +650,7 @@ "message": "FIDO2 WebAuthn" }, "webAuthnDesc": { - "message": "使用任何 WebAuthn 安全密钥访问您的帐户。" + "message": "使用任何具有 WebAuthn 功能的安全密钥来访问您的账户。" }, "emailTitle": { "message": "电子邮件地址" @@ -672,7 +716,7 @@ "message": "覆盖密码" }, "learnMore": { - "message": "进一步了解" + "message": "了解更多" }, "featureUnavailable": { "message": "功能不可用" @@ -707,17 +751,17 @@ "loading": { "message": "正在加载..." }, - "lockNow": { - "message": "立即锁定" + "lockVault": { + "message": "锁定密码库" }, "passwordGenerator": { "message": "密码生成器" }, - "emailUs": { - "message": "给我们发邮件" + "contactUs": { + "message": "联系我们" }, - "visitOurWebsite": { - "message": "访问我们的网站" + "getHelp": { + "message": "获取帮助" }, "fileBugReport": { "message": "发送错误报告" @@ -761,7 +805,7 @@ "message": "同步失败" }, "yourVaultIsLocked": { - "message": "您的密码库已锁定,请验证您的主密码以继续。" + "message": "您的密码库已锁定。请先验证您的身份。" }, "unlock": { "message": "解锁​​​​" @@ -789,10 +833,10 @@ "message": "两步登录" }, "vaultTimeout": { - "message": "密码库超时" + "message": "密码库超时时间" }, "vaultTimeoutDesc": { - "message": "选择您的密码库何时超时并执行所选的动作。" + "message": "选择您的密码库何时执行密码库超时动作。" }, "immediately": { "message": "立即" @@ -846,24 +890,24 @@ "message": "安全" }, "clearClipboard": { - "message": "清除剪贴板", + "message": "清空剪贴板", "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "clearClipboardDesc": { "message": "自动清除复制到剪贴板的值。", "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, - "disableFavicon": { - "message": "禁用网站图标" + "enableFavicon": { + "message": "显示网站图标" }, - "disableFaviconDesc": { - "message": "在您的密码库的每个登录项旁显示一个可识别的图标。" + "faviconDesc": { + "message": "在每个登录旁显示一个可识别的图像。" }, "enableMinToTray": { "message": "最小化到托盘图标" }, "enableMinToTrayDesc": { - "message": "最小化窗口后,改为在系统托盘中显示一个图标。" + "message": "最小化窗口后,在系统托盘中显示一个图标。" }, "enableMinToMenuBar": { "message": "最小化到菜单栏" @@ -875,7 +919,7 @@ "message": "关闭到托盘图标" }, "enableCloseToTrayDesc": { - "message": "关闭窗口后,改为在系统托盘中显示一个图标。" + "message": "关闭窗口后,在系统托盘中显示一个图标。" }, "enableCloseToMenuBar": { "message": "关闭到菜单栏" @@ -923,7 +967,7 @@ "message": "语言" }, "languageDesc": { - "message": "更改本应用程序使用的语言。需要重新启动才能生效。" + "message": "更改应用程序所使用的语言。重新启动后生效。" }, "theme": { "message": "主题" @@ -932,11 +976,11 @@ "message": "更改本应用程序的颜色主题。" }, "dark": { - "message": "暗", + "message": "深色", "description": "Dark color" }, "light": { - "message": "亮", + "message": "浅色", "description": "Light color" }, "copy": { @@ -1027,7 +1071,7 @@ "message": "密码健康、账户体检以及数据泄露报告,保障您的密码库安全。" }, "premiumSignUpTotp": { - "message": "用于密码库中登录项目的 TOTP 验证码(2FA)生成器。" + "message": "用于密码库中登录项目的 TOTP 验证码 (2FA) 生成器。" }, "premiumSignUpSupport": { "message": "优先客户支持。" @@ -1042,7 +1086,7 @@ "message": "您可以在 bitwarden.com 网页版密码库购买高级会员。现在要访问吗?" }, "premiumCurrentMember": { - "message": "您是高级会员!" + "message": "您目前是高级会员!" }, "premiumCurrentMemberThanks": { "message": "感谢您支持 Bitwarden。" @@ -1165,7 +1209,12 @@ "message": "没有在已知的数据泄露中发现此密码,它暂时比较安全。" }, "baseDomain": { - "message": "基础域" + "message": "基础域", + "description": "Domain name. Ex. website.com" + }, + "domainName": { + "message": "域名", + "description": "Domain name. Ex. website.com" }, "host": { "message": "主机", @@ -1227,6 +1276,40 @@ "fileFormat": { "message": "文件格式" }, + "hCaptchaUrl": { + "message": "hCaptcha URL", + "description": "hCaptcha is the name of a website, should not be translated" + }, + "loadAccessibilityCookie": { + "message": "加载无障碍 Cookie" + }, + "registerAccessibilityUser": { + "message": "注册为无障碍用户到", + "description": "ex. Register as an accessibility user at hcaptcha.com" + }, + "copyPasteLink": { + "message": "复制链接并粘贴在下方以便发送到你的电子邮箱" + }, + "enterhCaptchaUrl": { + "message": "输入 URL 以加载 hCaptcha 的无障碍 Cookie", + "description": "hCaptcha is the name of a website, should not be translated" + }, + "hCaptchaUrlRequired": { + "message": "hCaptcha URL 必填", + "description": "hCaptcha is the name of a website, should not be translated" + }, + "invalidUrl": { + "message": "无效的 URL" + }, + "done": { + "message": "完成" + }, + "accessibilityCookieSaved": { + "message": "无障碍 Cookie 已保存!" + }, + "noAccessibilityCookieSaved": { + "message": "无障碍 Cookie 未保存!" + }, "warning": { "message": "警告", "description": "WARNING (should stay in capitalized letters if the language permits)" @@ -1238,14 +1321,11 @@ "message": "导出的密码库数据包含未加密格式。您不应该通过不安全的渠道(例如电子邮件)来存储或发送导出的文件。用完后请立即将其删除。" }, "encExportKeyWarningDesc": { - "message": "此导出将使用您账户的加密密钥来加密您的数据。 如果您曾经轮换过账户的加密密钥,您应将其重新导出,否则您将无法解密导出的文件。" + "message": "此导出将使用您账户的加密密钥来加密您的数据。如果您曾经轮换过账户的加密密钥,您应将其重新导出,否则您将无法解密导出的文件。" }, "encExportAccountWarningDesc": { "message": "账户加密密钥对每个 Bitwarden 用户账户都是唯一的,所以您不能将加密的导出导入到另一个账户。" }, - "exportMasterPassword": { - "message": "输入主密码来导出你的密码库。" - }, "noOrganizationsList": { "message": "您没有加入任何组织。同一组织的用户可以安全地与其他用户共享项目。" }, @@ -1290,10 +1370,7 @@ "message": "需要 PIN 码。" }, "invalidPin": { - "message": "无效 PIN 码。" - }, - "yourVaultIsLockedPinCode": { - "message": "您的密码库已锁定。请验证您的 PIN 码以继续。" + "message": "无效的 PIN 码。" }, "unlockWithWindowsHello": { "message": "使用 Windows Hello 解锁" @@ -1307,20 +1384,20 @@ "touchIdConsentMessage": { "message": "解锁您的密码库" }, - "noAutoPromptWindowsHello": { - "message": "启动时不提示 Windows Hello。" + "autoPromptWindowsHello": { + "message": "启动时要求 Windows Hello" }, - "noAutoPromptTouchId": { - "message": "启动时不提示 Touch ID。" + "autoPromptTouchId": { + "message": "启动时要求触控 ID" }, "lockWithMasterPassOnRestart": { "message": "重启后使用主密码锁定" }, "preferences": { - "message": "设置" + "message": "偏好设置" }, "enableMenuBar": { - "message": "启用菜单栏图标" + "message": "显示菜单栏图标" }, "enableMenuBarDesc": { "message": "始终显示菜单栏图标。" @@ -1366,10 +1443,10 @@ "message": "密码库超时动作" }, "vaultTimeoutActionLockDesc": { - "message": "已锁定的密码库需要重新输入主密码才能再次访问。" + "message": "需要主密码或其他解锁方式才能再次访问您的密码库。" }, "vaultTimeoutActionLogOutDesc": { - "message": "已注销的密码库需要重新验证才能再次访问。" + "message": "需要重新验证才能再次访问您的密码库。" }, "lock": { "message": "锁定", @@ -1404,13 +1481,13 @@ "message": "永久删除" }, "vaultTimeoutLogOutConfirmation": { - "message": "超时后注销将解除对密码库的所有访问权限,并需要进行在线验证。确定使用此设置吗?" + "message": "超时后注销将解除对密码库的所有访问权限,并需要进行在线身份验证。确定使用此设置吗?" }, "vaultTimeoutLogOutConfirmationTitle": { "message": "超时动作确认" }, "enterpriseSingleSignOn": { - "message": "企业单点登录(SSO)" + "message": "企业单点登录" }, "setMasterPassword": { "message": "设置主密码" @@ -1469,32 +1546,32 @@ "acceptPolicies": { "message": "选中此框表示您同意:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "尚未同意服务条款和隐私政策。" }, "enableBrowserIntegration": { - "message": "启用浏览器整合" + "message": "允许浏览器集成" }, "enableBrowserIntegrationDesc": { - "message": "浏览器整合用于在浏览器中提供生物识别。" + "message": "浏览器集成用于在浏览器中提供生物识别。" }, - "browserIntegrationMasOnlyTitle": { - "message": "不支持浏览器整合" + "browserIntegrationUnsupportedTitle": { + "message": "不支持浏览器集成" }, "browserIntegrationMasOnlyDesc": { - "message": "很遗憾,目前仅 Mac App Store 版本支持浏览器整合。" - }, - "browserIntegrationWindowsStoreTitle": { - "message": "不支持浏览器整合" + "message": "很遗憾,目前仅 Mac App Store 版本支持浏览器集成。" }, "browserIntegrationWindowsStoreDesc": { - "message": "很不幸,当前 Windows Store 版本不支持浏览器整合。" + "message": "很遗憾,Windows Store 版本目前不支持浏览器整合。" + }, + "browserIntegrationLinuxDesc": { + "message": "很遗憾,Linux 版本目前不支持浏览器集成。" }, "enableBrowserIntegrationFingerprint": { - "message": "要求浏览器整合验证" + "message": "要求浏览器集成验证" }, "enableBrowserIntegrationFingerprintDesc": { - "message": "在您的桌面与浏览器间建立连接时,要求验证指纹短语以实现一个额外安全层。此选项启用后,每次建立连接都需要用户干预和验证。" + "message": "在您的桌面与浏览器间建立连接时,通过要求指纹短语确认,来增加一个额外的安全层。每次建立连接都需要用户操作和验证。" }, "approve": { "message": "批准" @@ -1555,14 +1632,15 @@ "message": "过期日期" }, "expirationDateDesc": { - "message": "如果设定,此 Send 将在指定的日期和时间后过期。", + "message": "设置后,对此 Send 的访问将在指定的日期和时间后过期。", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "maxAccessCount": { - "message": "最大访问次数" + "message": "最大访问次数", + "description": "This text will be displayed after a Send has been accessed the maximum amount of times." }, "maxAccessCountDesc": { - "message": "如果设定,达到最大访问次数后用户将无法访问此 Send。", + "message": "设置后,当达到最大访问次数时用户将不再能够访问此 Send。", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "currentAccessCount": { @@ -1589,7 +1667,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "textHiddenByDefault": { - "message": "访问 Send 时,默认将隐藏文本", + "message": "访问 Send 时,默认隐藏文字内容", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "createdSend": { @@ -1695,22 +1773,22 @@ "message": "此操作受到保护。若要继续,请重新输入您的主密码以验证您的身份。" }, "updatedMasterPassword": { - "message": "Updated Master Password" + "message": "已更新主密码" }, "updateMasterPassword": { - "message": "Update Master Password" + "message": "更新主密码" }, "updateMasterPasswordWarning": { - "message": "Your Master Password was recently changed by an administrator in your organization. In order to access the vault, you must update it now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour." + "message": "您的主密码最近被您组织的管理员更改过。要访问密码库,您必须立即更新它。继续操作将使您退出当前会话,要求您重新登录。其他设备上的活动会话可能会继续保持活动状态长达一小时。" }, "hours": { - "message": "Hours" + "message": "小时" }, "minutes": { - "message": "Minutes" + "message": "分钟" }, "vaultTimeoutPolicyInEffect": { - "message": "Your organization policies are affecting your vault timeout. Maximum allowed Vault Timeout is $HOURS$ hour(s) and $MINUTES$ minute(s)", + "message": "您的组织策略正在影响您的密码库超时时间。最大允许的密码库超时时间是 $HOURS$ 小时 $MINUTES$ 分钟。", "placeholders": { "hours": { "content": "$1", @@ -1723,18 +1801,170 @@ } }, "vaultTimeoutTooLarge": { - "message": "Your vault timeout exceeds the restrictions set by your organization." + "message": "您的密码库超时时间超出了组织设置的限制。" }, "resetPasswordPolicyAutoEnroll": { - "message": "Automatic Enrollment" + "message": "自动注册" }, "resetPasswordAutoEnrollInviteWarning": { - "message": "This organization has an enterprise policy that will automatically enroll you in password reset. Enrollment will allow organization administrators to change your master password." + "message": "此组织有一个企业策略,将自动为你注册密码重置。注册后将允许组织管理员更改您的主密码。" }, "vaultExportDisabled": { - "message": "Vault Export Disabled" + "message": "密码库导出已禁用" }, "personalVaultExportPolicyInEffect": { - "message": "One or more organization policies prevents you from exporting your personal vault." + "message": "一个或多个组织策略阻止您导出个人密码库。" + }, + "addAccount": { + "message": "添加账户" + }, + "removeMasterPassword": { + "message": "移除主密码" + }, + "removedMasterPassword": { + "message": "主密码已移除。" + }, + "convertOrganizationEncryptionDesc": { + "message": "$ORGANIZATION$ 使用自托管密钥服务器 SSO。这个组织的成员登录时将不再需要主密码。", + "placeholders": { + "organization": { + "content": "$1", + "example": "My Org Name" + } + } + }, + "leaveOrganization": { + "message": "离开组织" + }, + "leaveOrganizationConfirmation": { + "message": "您确定要离开这个组织吗?" + }, + "leftOrganization": { + "message": "您已经离开该组织。" + }, + "ssoKeyConnectorError": { + "message": "Key Connector 错误:请确保 Key Connector 可用且工作正常。" + }, + "lockAllVaults": { + "message": "锁定所有密码库" + }, + "accountLimitReached": { + "message": "最多只能同时登录 5 个账户。" + }, + "accountPreferences": { + "message": "偏好设置" + }, + "appPreferences": { + "message": "应用设置(所有账户)" + }, + "accountSwitcherLimitReached": { + "message": "已达到账户上限。请注销一个账户后再添加其他账户。" + }, + "settingsTitle": { + "message": "$EMAIL$ 的应用程序设置", + "placeholders": { + "email": { + "content": "$1", + "example": "jdoe@example.com" + } + } + }, + "switchAccount": { + "message": "切换账户" + }, + "options": { + "message": "选项" + }, + "sessionTimeout": { + "message": "您的会话已超时。请返回并尝试重新登录。" + }, + "exportingPersonalVaultTitle": { + "message": "正在导出个人密码库" + }, + "exportingPersonalVaultDescription": { + "message": "仅会导出与 $EMAIL$ 关联的个人密码库。组织密码库的项目不会导出。", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "locked": { + "message": "已锁定" + }, + "unlocked": { + "message": "已解锁" + }, + "generator": { + "message": "生成器" + }, + "whatWouldYouLikeToGenerate": { + "message": "您想要生成什么?" + }, + "passwordType": { + "message": "密码类型" + }, + "regenerateUsername": { + "message": "重新生成用户名" + }, + "generateUsername": { + "message": "生成用户名" + }, + "usernameType": { + "message": "用户名类型" + }, + "plusAddressedEmail": { + "message": "附加地址电子邮件", + "description": "Username generator option that appends a random sub-address to the username. For example: address+subaddress@email.com" + }, + "plusAddressedEmailDesc": { + "message": "使用您的电子邮件供应商的子地址功能。" + }, + "catchallEmail": { + "message": "Catch-all 电子邮件" + }, + "catchallEmailDesc": { + "message": "使用您的域名配置的 Catch-all 收件箱。" + }, + "random": { + "message": "随机" + }, + "randomWord": { + "message": "随机单词" + }, + "websiteName": { + "message": "网站名" + }, + "service": { + "message": "服务" + }, + "allVaults": { + "message": "所有密码库" + }, + "searchOrganization": { + "message": "搜索组织" + }, + "searchMyVault": { + "message": "搜索我的密码库" + }, + "forwardedEmail": { + "message": "转发的电子邮件别名" + }, + "forwardedEmailDesc": { + "message": "使用外部转发服务生成一个电子邮件别名。" + }, + "hostname": { + "message": "主机名", + "description": "Part of a URL." + }, + "apiAccessToken": { + "message": "API 访问令牌" + }, + "apiKey": { + "message": "API 密钥" + }, + "neverLockWarning": { + "message": "您确定要使用「从不」选项吗?将锁定选项设置为「从不」会将密码库的加密密钥存储在您的设备上。如果使用此选项,您必须确保您的设备安全。" } } diff --git a/apps/desktop/src/locales/zh_TW/messages.json b/apps/desktop/src/locales/zh_TW/messages.json index d65e43ef691..c191f7e205d 100644 --- a/apps/desktop/src/locales/zh_TW/messages.json +++ b/apps/desktop/src/locales/zh_TW/messages.json @@ -532,10 +532,13 @@ "invalidEmail": { "message": "無效的電子郵件地址。" }, - "masterPassRequired": { - "message": "必須填入主密碼。" + "masterPasswordRequired": { + "message": "必須填寫主密碼。" }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "必須再次輸入主密碼。" + }, + "masterPasswordMinLength": { "message": "主密碼需要至少 8 個字元。" }, "masterPassDoesntMatch": { @@ -1543,8 +1546,8 @@ "acceptPolicies": { "message": "選中此選取框,代表您同意下列項目:" }, - "acceptPoliciesError": { - "message": "尚未接受服務條款與隱私權保護政策。" + "acceptPoliciesRequired": { + "message": "尚未接受服務條款與隱私權政策。" }, "enableBrowserIntegration": { "message": "允許瀏覽器整合" @@ -1960,5 +1963,8 @@ }, "apiKey": { "message": "API 金鑰" + }, + "neverLockWarning": { + "message": "您確定要使用「永不」選項嗎?將鎖定選項設定為「永不」會將密碼庫的加密金鑰儲存在您的裝置上。如果使用此選項,應確保您的裝置是安全的。" } } From 30200c2c3c5684e53ee4868f234c24efe127784f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 8 Jul 2022 08:48:40 +0200 Subject: [PATCH 20/86] Autosync the updated translations (#3069) Co-authored-by: github-actions <> --- apps/web/src/locales/af/messages.json | 51 +++++- apps/web/src/locales/ar/messages.json | 45 ++++- apps/web/src/locales/az/messages.json | 39 ++++- apps/web/src/locales/be/messages.json | 45 ++++- apps/web/src/locales/bg/messages.json | 41 ++++- apps/web/src/locales/bn/messages.json | 47 ++++- apps/web/src/locales/bs/messages.json | 41 ++++- apps/web/src/locales/ca/messages.json | 45 ++++- apps/web/src/locales/cs/messages.json | 45 ++++- apps/web/src/locales/da/messages.json | 45 ++++- apps/web/src/locales/de/messages.json | 39 ++++- apps/web/src/locales/el/messages.json | 45 ++++- apps/web/src/locales/en_GB/messages.json | 41 ++++- apps/web/src/locales/en_IN/messages.json | 39 ++++- apps/web/src/locales/eo/messages.json | 85 +++++++--- apps/web/src/locales/es/messages.json | 207 +++++++++++++---------- apps/web/src/locales/et/messages.json | 39 ++++- apps/web/src/locales/eu/messages.json | 41 ++++- apps/web/src/locales/fi/messages.json | 55 ++++-- apps/web/src/locales/fil/messages.json | 41 ++++- apps/web/src/locales/fr/messages.json | 43 ++++- apps/web/src/locales/he/messages.json | 45 ++++- apps/web/src/locales/hi/messages.json | 41 ++++- apps/web/src/locales/hr/messages.json | 45 ++++- apps/web/src/locales/hu/messages.json | 39 ++++- apps/web/src/locales/id/messages.json | 45 ++++- apps/web/src/locales/it/messages.json | 45 ++++- apps/web/src/locales/ja/messages.json | 41 ++++- apps/web/src/locales/ka/messages.json | 41 ++++- apps/web/src/locales/km/messages.json | 41 ++++- apps/web/src/locales/kn/messages.json | 45 ++++- apps/web/src/locales/ko/messages.json | 45 ++++- apps/web/src/locales/lv/messages.json | 45 ++++- apps/web/src/locales/ml/messages.json | 45 ++++- apps/web/src/locales/nb/messages.json | 45 ++++- apps/web/src/locales/nl/messages.json | 45 ++++- apps/web/src/locales/nn/messages.json | 45 ++++- apps/web/src/locales/pl/messages.json | 43 ++++- apps/web/src/locales/pt_BR/messages.json | 111 +++++++----- apps/web/src/locales/pt_PT/messages.json | 47 ++++- apps/web/src/locales/ro/messages.json | 45 ++++- apps/web/src/locales/ru/messages.json | 41 ++++- apps/web/src/locales/si/messages.json | 41 ++++- apps/web/src/locales/sk/messages.json | 43 ++++- apps/web/src/locales/sl/messages.json | 45 ++++- apps/web/src/locales/sr/messages.json | 45 ++++- apps/web/src/locales/sr_CS/messages.json | 39 ++++- apps/web/src/locales/sv/messages.json | 53 ++++-- apps/web/src/locales/tr/messages.json | 41 ++++- apps/web/src/locales/uk/messages.json | 67 ++++++-- apps/web/src/locales/vi/messages.json | 43 ++++- apps/web/src/locales/zh_CN/messages.json | 43 ++++- apps/web/src/locales/zh_TW/messages.json | 43 ++++- 53 files changed, 2178 insertions(+), 429 deletions(-) diff --git a/apps/web/src/locales/af/messages.json b/apps/web/src/locales/af/messages.json index 5374e8379fd..d303f494ea1 100644 --- a/apps/web/src/locales/af/messages.json +++ b/apps/web/src/locales/af/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Skep rekening" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Teken aan" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Die hoofwagwoord is die wagwoord wat u gaan gebruik vir toegang tot u kluis. Dit is baie belangrik dat u u hoofwagwoord onthou. Daar is geen manier om dit terug te kry ingeval u dit vergeet het nie." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "’n Hoofwagwoordwenk kan u help om u wagwoord te onthou, sou u dit vergeet." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Ongeldige e-posadres." }, - "masterPassRequired": { - "message": "Hoofwagwoord word benodig." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Hoofwagwoord moet ten minste 8 karakters lank wees." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Hoofwagwoordbevestiging stem nie ooreen nie." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Deur hierdie kassie af te merk stem u in tot die volgende:" }, - "acceptPoliciesError": { - "message": "Gebruiksvoorwaardes en privaatheidsbeleid is nie erken nie." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Gebruiksvoorwaardes" @@ -4099,7 +4108,7 @@ } }, "viewSendHiddenEmailWarning": { - "message": "The Bitwarden user who created this Send has chosen to hide their email address. You should ensure you trust the source of this link before using or downloading its content.", + "message": "Die Bitwarden-gebruiker wat hierdie Send geskep het, het gekies om hul e-posadres te verberg. U moet verseker dat u die bron van hierdie skakel vertrou voordat u die inhoud gebruik of aflaai.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "expirationDateIsInvalid": { @@ -4507,10 +4516,10 @@ "message": "Vault Timeout is not within allowed range." }, "disablePersonalVaultExport": { - "message": "Disable Personal Vault Export" + "message": "Deaktiveer uitstuur van persoonlike kluis" }, "disablePersonalVaultExportDesc": { - "message": "Prohibits users from exporting their private vault data." + "message": "Verbied gebruikers om hul privaatkluisdata uit te stuur." }, "vaultExportDisabled": { "message": "Kluisuitstuur gedeaktiveer" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ veld(e) hierbo benodig u aandag.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/ar/messages.json b/apps/web/src/locales/ar/messages.json index 99729692b31..1ef7234f747 100644 --- a/apps/web/src/locales/ar/messages.json +++ b/apps/web/src/locales/ar/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "إنشاء حساب" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "تسجيل الدخول" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "يمكن أن يساعدك تلميح كلمة المرور الرئيسية في تذكر كلمة المرور الخاصة بك في حال نسيتها." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "عنوان البريد الإلكتروني غير صالح." }, - "masterPassRequired": { - "message": "كلمة المرور الرئيسية مطلوبة." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "يجب أن يكون طول كلمة المرور الرئيسية 8 أحرف على الأقل." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "لا يتطابق تأكيد كلمة المرور مع كلمة المرور." @@ -1076,7 +1085,7 @@ "message": "Account Deleted" }, "accountDeletedDesc": { - "message": "Your account has been closed and all associated data has been deleted." + "message": "Your Bitwarden account and vault data were permanently deleted." }, "myAccount": { "message": "حسابي" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/az/messages.json b/apps/web/src/locales/az/messages.json index 6aa270aee3e..7c7c69e6a4c 100644 --- a/apps/web/src/locales/az/messages.json +++ b/apps/web/src/locales/az/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Hesab yarat" }, + "startTrial": { + "message": "Sınağa Başla" + }, "logIn": { "message": "Giriş et" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Ana parol, anbarınıza müraciət etmək üçün istifadə edəcəyiniz şifrədir. Ana parolu yadda saxlamaq çox vacibdir. Unutsanız, parolu bərpa etməyin heç bir yolu yoxdur." }, + "masterPassImportant": { + "message": "Unutsanız, Ana parollar bərpa edilə bilməz!" + }, "masterPassHintDesc": { "message": "Ana parol məsləhəti, unutduğunuz parolu xatırlamağınıza kömək edir." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Etibarsız e-poçt ünvanı." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Ana parol lazımdır." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Ana parolun yenidən yazılması lazımdır." + }, + "masterPasswordMinLength": { "message": "Ana parol ən azı 8 simvol uzunluğunda olmalıdır." }, "masterPassDoesntMatch": { @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "Bu qutunu işarələyərək aşağıdakılarla razılaşırsınız:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Xidmət Şərtləri və Gizlilik Siyasəti qəbul edilməyib." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Giriş lazımdır." + }, + "inputEmail": { + "message": "Giriş, bir e-poçt ünvanı deyil." + }, + "inputMinLength": { + "message": "Giriş, ən azı $COUNT$ simvol uzunluğunda olmalıdır.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "Yuxarıdakı $COUNT$ sahənin diqqətinizə ehtiyacı var.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/be/messages.json b/apps/web/src/locales/be/messages.json index 6bc3430721a..d221fc0055c 100644 --- a/apps/web/src/locales/be/messages.json +++ b/apps/web/src/locales/be/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Стварыць уліковы запіс" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Увайсці" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Асноўны пароль — ключ да вашага бяспечнага сховішча. Ён вельмі важны, таму не забывайце яго. Аднавіць асноўны пароль немагчыма." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "Падказка да асноўнага пароля можа дапамагчы вам яго ўспомніць." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Памылковы адрас электроннай пошты." }, - "masterPassRequired": { - "message": "Патрабуецца асноўны пароль." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Асноўны пароль павінен быць даўжынёй не менш за 8 сімвалаў." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Асноўныя паролі не супадаюць." @@ -1076,7 +1085,7 @@ "message": "Уліковы запіс выдалены" }, "accountDeletedDesc": { - "message": "Your account has been closed and all associated data has been deleted." + "message": "Your Bitwarden account and vault data were permanently deleted." }, "myAccount": { "message": "Мой уліковы запіс" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/bg/messages.json b/apps/web/src/locales/bg/messages.json index 644b130b3a7..1ba694391c1 100644 --- a/apps/web/src/locales/bg/messages.json +++ b/apps/web/src/locales/bg/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Създаване на абонамент" }, + "startTrial": { + "message": "Стартиране на пробния период" + }, "logIn": { "message": "Вписване" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Главната парола се използва за достъп до трезора ви. Запомнете я добре, защото възстановяването ѝ е абсолютно невъзможно." }, + "masterPassImportant": { + "message": "Главната парола не може да бъде възстановена, ако я забравите!" + }, "masterPassHintDesc": { "message": "Ако сте забравили главната парола, то подсказването може да ви помогне да си я припомните." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Недействителна електронна поща." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Главната парола е задължителна." }, - "masterPassLength": { - "message": "Главната парола трябва да съдържа поне 8 знака." + "confirmMasterPasswordRequired": { + "message": "Повторното въвеждане на главната парола е задължително." + }, + "masterPasswordMinLength": { + "message": "Главната парола трябва да е с дължина поне 8 знака." }, "masterPassDoesntMatch": { "message": "Главната парола и потвърждението ѝ не съвпадат." @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "Чрез тази отметка вие се съгласявате със следните:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Условията за използване и политиката за поверителност не бяха приети." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Полето е задължтелно да бъде попълнено." + }, + "inputEmail": { + "message": "Въведеният в полето текст не е адрес на е-поща." + }, + "inputMinLength": { + "message": "Въведеният в полето текст трябва да бъде с дължина поне $COUNT$ знака.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ поле(та) по-горе се нуждае/ят от вниманието Ви.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/bn/messages.json b/apps/web/src/locales/bn/messages.json index c22d41a07db..7dbdac97863 100644 --- a/apps/web/src/locales/bn/messages.json +++ b/apps/web/src/locales/bn/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "অ্যাকাউন্ট তৈরি" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Log In" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "A master password hint can help you remember your password if you forget it." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "অকার্যকর ইমেইল ঠিকানা।" }, - "masterPassRequired": { - "message": "মূল পাসওয়ার্ড প্রয়োজন।" + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "মূল পাসওয়ার্ড কমপক্ষে ৮ অক্ষর দীর্ঘ হওয়া উচিত।" + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "মূল পাসওয়ার্ড নিশ্চিতকরণ মেলেনি।" @@ -1076,7 +1085,7 @@ "message": "Account Deleted" }, "accountDeletedDesc": { - "message": "Your account has been closed and all associated data has been deleted." + "message": "Your Bitwarden account and vault data were permanently deleted." }, "myAccount": { "message": "My Account" @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "এই বাক্সটি টিক করে আপনি নিম্নলিখিতগুলিতে সম্মত হন:" }, - "acceptPoliciesError": { - "message": "পরিষেবার শর্তাদি এবং গোপনীয়তা নীতি স্বীকার করা হয়নি।" + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "সেবা পাবার শর্ত" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/bs/messages.json b/apps/web/src/locales/bs/messages.json index 464625d877e..3958991c74e 100644 --- a/apps/web/src/locales/bs/messages.json +++ b/apps/web/src/locales/bs/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Create Account" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Log In" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "A master password hint can help you remember your password if you forget it." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1076,7 +1085,7 @@ "message": "Account Deleted" }, "accountDeletedDesc": { - "message": "Your account has been closed and all associated data has been deleted." + "message": "Your Bitwarden account and vault data were permanently deleted." }, "myAccount": { "message": "My Account" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/ca/messages.json b/apps/web/src/locales/ca/messages.json index 7525d51bfc0..9aa5e74ae70 100644 --- a/apps/web/src/locales/ca/messages.json +++ b/apps/web/src/locales/ca/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Crea un compte" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Inicia sessió" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "La contrasenya mestra és la clau que utilitzeu per accedir a la vostra caixa forta. És molt important que no la oblideu. No hi ha manera de recuperar-la en cas que la oblideu." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "Una pista de la contrasenya mestra pot ajudar-vos a recordar-la si la oblideu." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "L’adreça electrònica no és vàlida." }, - "masterPassRequired": { - "message": "La contrasenya és obligatòria." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "La contrasenya ha de contenir almenys 8 caràcters." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "La confirmació de la contrasenya mestra no coincideix." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Si activeu aquesta casella, indiqueu que esteu d’acord amb el següent:" }, - "acceptPoliciesError": { - "message": "No s’han reconegut les condicions del servei i la declaració de privadesa." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Condicions del servei" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/cs/messages.json b/apps/web/src/locales/cs/messages.json index c7505f854c0..0b74162ea7d 100644 --- a/apps/web/src/locales/cs/messages.json +++ b/apps/web/src/locales/cs/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Vytvořit účet" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Přihlásit se" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Hlavní heslo je heslo, které používáte k přístupu do vašeho trezoru. Je velmi důležité, abyste jej nezapomněli. Neexistuje totiž žádný způsob, jak heslo obnovit v případě, že jste na něj zapomněli." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "Nápověda k hlavnímu heslu vám pomůže zapamatovat si heslo, pokud ho zapomenete." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Neplatná e-mailová adresa." }, - "masterPassRequired": { - "message": "Hlavní heslo je povinné." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Hlavní heslo musí obsahovat alespoň 8 znaků." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Potvrzení hlavního hesla se neshoduje." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Zaškrtnutím tohoto políčka souhlasím s následujícím:" }, - "acceptPoliciesError": { - "message": "Podmínky služby a zásady ochrany osobních údajů nebyly uznány." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Podmínky služby" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/da/messages.json b/apps/web/src/locales/da/messages.json index 92ff887e75c..2b15691d50d 100644 --- a/apps/web/src/locales/da/messages.json +++ b/apps/web/src/locales/da/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Opret konto" }, + "startTrial": { + "message": "Start prøveperiode" + }, "logIn": { "message": "Log ind" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Hovedadgangskoden er den adgangskode, du bruger til at få adgang til din boks. Det er meget vigtigt, at du ikke glemmer din hovedadgangskode. Der er ingen måde hvorpå koden kan genoprettes, i tilfælde af at du glemmer den." }, + "masterPassImportant": { + "message": "Hovedadgangskoder kan ikke gendannes, hvis de glemmes!" + }, "masterPassHintDesc": { "message": "Et tip til hovedadgangskoden kan hjælpe dig med at huske din adgangskode, hvis du glemmer den." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Ugyldig e-mailadresse." }, - "masterPassRequired": { - "message": "Hovedadgangskode er påkrævet." + "masterPasswordRequired": { + "message": "Hovedadgangskode er obligatorisk." }, - "masterPassLength": { - "message": "Hovedadgangskoden skal være på mindst 8 tegn." + "confirmMasterPasswordRequired": { + "message": "Hovedadgangskode kræves angivet igen." + }, + "masterPasswordMinLength": { + "message": "Hovedadgangskode skal udgøre min. 8 tegn." }, "masterPassDoesntMatch": { "message": "De to hovedadgangskoder matcher ikke." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Ved at markere dette felt accepterer du følgende:" }, - "acceptPoliciesError": { - "message": "Servicevilkår og fortrolighedspolitik er ikke blevet bekræftet." + "acceptPoliciesRequired": { + "message": "Tjenestevilkår og Fortrolighedspolitik er ikke blevet accepteret." }, "termsOfService": { "message": "Servicevilkår" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input obligatorisk." + }, + "inputEmail": { + "message": "Input er ikke en gyldig e-mailadresse." + }, + "inputMinLength": { + "message": "Input skal udgøre min. $COUNT$ tegn.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$-felt(er) ovenfor kræver din opmærksomhed.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/de/messages.json b/apps/web/src/locales/de/messages.json index 242a25a4ef9..bac505f49e8 100644 --- a/apps/web/src/locales/de/messages.json +++ b/apps/web/src/locales/de/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Konto erstellen" }, + "startTrial": { + "message": "Probephase starten" + }, "logIn": { "message": "Anmelden" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Das Master-Passwort wird verwendet, um den Tresor zu öffnen. Es ist sehr wichtig, dass Sie das Passwort nicht vergessen, da es keine Möglichkeit gibt es zurückzusetzen." }, + "masterPassImportant": { + "message": "Master-Passwörter können nicht wiederhergestellt werden, wenn du sie vergisst!" + }, "masterPassHintDesc": { "message": "Ein Master-Passwort-Hinweis kann Ihnen helfen, sich an das Passwort zu erinnern, wenn Sie es vergessen haben sollten." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Ungültige E-Mail Adresse." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Das Master-Passwort ist erforderlich." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Erneute Eingabe des Master-Passworts ist erforderlich." + }, + "masterPasswordMinLength": { "message": "Das Master-Passwort muss mindestens 8 Zeichen lang sein." }, "masterPassDoesntMatch": { @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "Durch Anwählen dieses Kästchens erklären Sie sich mit folgendem einverstanden:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Die Nutzungsbedingungen und Datenschutzerklärung wurden nicht akzeptiert." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Angabe ist erforderlich." + }, + "inputEmail": { + "message": "Angabe ist keine E-Mail-Adresse." + }, + "inputMinLength": { + "message": "Angabe muss mindestens $COUNT$ Zeichen lang sein.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ Feld(er) oben benötigt deine Aufmerksamkeit.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/el/messages.json b/apps/web/src/locales/el/messages.json index 4552350680e..c03d4c5fefd 100644 --- a/apps/web/src/locales/el/messages.json +++ b/apps/web/src/locales/el/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Δημιουργία Λογαριασμού" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Είσοδος" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Ο κύριος κωδικός είναι ο κωδικός που χρησιμοποιείτε για την πρόσβαση στο vault σας. Είναι πολύ σημαντικό να μην ξεχάσετε τον κύριο κωδικό. Δεν υπάρχει τρόπος να τον ανακτήσετε σε περίπτωση που τον ξεχάσετε." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "Η υπόδειξη του κύριου κωδικού μπορεί να σας βοηθήσει να θυμηθείτε τον κωδικό σας, σε περίπτωση που τον ξεχάσετε." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Μη έγκυρη διεύθυνση e-mail." }, - "masterPassRequired": { - "message": "Απαιτείται κύριος κωδικός πρόσβασης." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Ο κύριος κωδικός πρέπει να έχει μήκος τουλάχιστον 8 χαρακτήρες." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Η επιβεβαίωση του κύριου κωδικού δεν ταιριάζει." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Επιλέγοντας αυτό το πλαίσιο, συμφωνείτε με τα εξής:" }, - "acceptPoliciesError": { - "message": "Οι Όροι Παροχής Υπηρεσιών και η Πολιτική Απορρήτου δεν έχουν αναγνωριστεί." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Όροι Χρήσης" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/en_GB/messages.json b/apps/web/src/locales/en_GB/messages.json index 773af050b3e..c8efde70c1c 100644 --- a/apps/web/src/locales/en_GB/messages.json +++ b/apps/web/src/locales/en_GB/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Create account" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Log in" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "A master password hint can help you remember your password if you forget it." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { - "message": "Terms of service and privacy policy have not been acknowledged." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Terms of service" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/en_IN/messages.json b/apps/web/src/locales/en_IN/messages.json index 512fc02ca3e..1c49619d90e 100644 --- a/apps/web/src/locales/en_IN/messages.json +++ b/apps/web/src/locales/en_IN/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Create account" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Log in" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "A master password hint can help you remember your password if you forget it." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/eo/messages.json b/apps/web/src/locales/eo/messages.json index 63abd2c3d28..a548d988b4d 100644 --- a/apps/web/src/locales/eo/messages.json +++ b/apps/web/src/locales/eo/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Krei konton" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Saluti" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "La ĉefa pasvorto estas la pasvorto, kiun vi uzas por aliri vian trezorejon. Tre gravas, ke vi ne forgesu vian ĉefan pasvorton. Ne eblas retrovi la pasvorton, se vi forgesos ĝin." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "Majstra pasvorta sugesto povas helpi vin memori vian pasvorton se vi forgesas ĝin." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Nevalida retpoŝta adreso." }, - "masterPassRequired": { - "message": "Majstra pasvorto necesas." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Majstra pasvorto devas havi almenaŭ 8 signojn." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "La konfirmo de la ĉefa pasvorto ne interrespondas." @@ -727,7 +736,7 @@ "message": "Sendu retpoŝtan kontrol-kodon denove" }, "useAnotherTwoStepMethod": { - "message": "Uzu alian du-paŝan ensalutan metodon" + "message": "Uzu alian metodon de identigo en du-ŝtupa saluto" }, "insertYubiKey": { "message": "Enmetu vian YubiKey en la USB-havenon de via komputilo, tiam tuŝu ĝian butonon." @@ -745,7 +754,7 @@ "message": "Bonvolu uzi subtenatan tTT-legilon (kiel Chrome) kaj / aŭ aldoni pliajn provizantojn pli bone subtenatajn tra tTT-legiloj (kiel aŭtentikiga programo)." }, "twoStepOptions": { - "message": "Elektebloj de la du-faktora aŭtentigo" + "message": "Elektebloj de la du-ŝtupa saluto" }, "recoveryCodeDesc": { "message": "Ĉu vi perdis aliron al ĉiuj viaj du-faktoraj provizantoj? Uzu vian reakiran kodon por malŝalti ĉiujn du-faktorajn provizantojn de via konto." @@ -1037,7 +1046,7 @@ "message": "Ĉu vi zorgas pri tio, ke via konto estas ensalutinta sur alia aparato? Sekvu sube por senrajtigi ĉiujn komputilojn aŭ aparatojn, kiujn vi antaŭe uzis. Ĉi tiu sekureca paŝo rekomendas se vi antaŭe uzis publikan komputilon aŭ hazarde konservis vian pasvorton sur aparato, kiu ne estas via. Ĉi tiu paŝo ankaŭ malplenigos ĉiujn antaŭe memoritajn du-paŝajn ensalutajn sesiojn. " }, "deauthorizeSessionsWarning": { - "message": "Se vi daŭrigos vian adiaŭadon de la nuna seanco, necesos vin saluti denove. Oni ankaŭ demandos de vi du-faktoran aŭtentigon, se la opcio estas ebligita. La seancoj aktivaj sur aliaj aparatoj povas resti daŭre aktivaj ankoraŭ unu horon." + "message": "Se vi daŭrigos vian adiaŭadon de la nuna seanco, necesos vin saluti denove. Oni ankaŭ demandos de vi du-faktoran aŭtentigon, se tiu elekteblo estas ebligita. La seancoj aktivaj sur aliaj aparatoj povas resti daŭre aktivaj ankoraŭ unu horon." }, "sessionsDeauthorized": { "message": "Ĉiuj Sesioj Neaŭtorizitaj" @@ -1134,7 +1143,7 @@ } }, "options": { - "message": "Opcioj" + "message": "Elektebloj" }, "preferences": { "message": "Preferences" @@ -1214,7 +1223,7 @@ "message": "Domajnoj ĝisdatigitaj" }, "twoStepLogin": { - "message": "Du-faktora aŭtentigo" + "message": "Du-ŝtupa saluto" }, "twoStepLoginDesc": { "message": "Sekurigu vian konton postulante plian paŝon kiam vi ensalutas." @@ -1264,7 +1273,7 @@ "message": "Administri" }, "disable": { - "message": "Malebligi" + "message": "Neebligi" }, "deactivate": { "message": "Deactivate" @@ -1300,7 +1309,7 @@ "message": "Skani ĉi tiun QR-kodon per via aŭtentikiga programo" }, "key": { - "message": "Ŝlosilo" + "message": "Konigilo" }, "twoStepAuthenticatorEnterCode": { "message": "Enigu la rezultan 6-ciferan konfirmkodon de la programo" @@ -1378,7 +1387,7 @@ "message": "YubiKeys ĝisdatigis" }, "disableAllKeys": { - "message": "Malebligi ĉiujn ŝlosilojn" + "message": "Neebligi ĉiujn ŝlosilojn" }, "twoFactorDuoDesc": { "message": "Enmetu la informojn pri Bitwarden-aplikaĵo de via panelo de Duo Admin." @@ -1453,7 +1462,7 @@ "message": "Web vault and browser extensions on a desktop/laptop with a WebAuthn enabled browser (Chrome, Opera, Vivaldi, or Firefox with FIDO U2F enabled)." }, "twoFactorRecoveryYourCode": { - "message": "Via kodo de senpaneigo de la du-faktora aŭtentigo de Bitwarden" + "message": "Via kodo de senpaneigo de la du-ŝtupa saluto de Bitwarden" }, "twoFactorRecoveryNoCode": { "message": "Vi ankoraŭ ne ebligis du-paŝajn ensalutajn provizantojn. Post kiam vi ebligis du-ŝtupan ensalut-provizanton, vi povas kontroli ĉi tie vian reakiran kodon." @@ -2383,10 +2392,10 @@ "message": "Ebligita / ĝisdatigita du-ŝtupa ensaluto." }, "disabled2fa": { - "message": "Du-faktora aŭtentigo malebligita." + "message": "Neebligita du-ŝtupa saluto." }, "recovered2fa": { - "message": "Konto senpaneigita el du-faktora aŭtentigo." + "message": "Konto senpaneigita el du-ŝtupa saluto." }, "failedLogin": { "message": "Ensaluta provo malsukcesis kun malĝusta pasvorto." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Markante ĉi tiun keston vi konsentas pri jeno:" }, - "acceptPoliciesError": { - "message": "Kondiĉoj pri Servo kaj Privateca Politiko ne estis agnoskitaj." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Kondiĉoj por Servo" @@ -3528,7 +3537,7 @@ "message": "Identigilo" }, "organizationIdentifier": { - "message": "Identigilo de la organizaĵo" + "message": "Identigilo de la organizo" }, "ssoLogInWithOrgIdentifier": { "message": "Ensalutu per la unika ensaluta portalo de via organizo. Bonvolu enigi la identigilon de via organizo por komenci." @@ -3552,7 +3561,7 @@ "message": "SSO-Validado Malsukcesis" }, "ssoIdentifierRequired": { - "message": "Organiza Identigilo necesas." + "message": "La identigilo de la organizo estas postulata." }, "unlinkSso": { "message": "Malkonekti SSO" @@ -3664,7 +3673,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "disabled": { - "message": "Malebligita" + "message": "Neebligita" }, "deactivated": { "message": "Deactivated" @@ -3892,7 +3901,7 @@ "message": "Pro entreprena politiko, vi ne rajtas konservi artikolojn al via persona trezorejo. Ŝanĝu la opcion Proprieto al organizo kaj elektu el disponeblaj Kolektoj." }, "disableSend": { - "message": "Malebligi Sendi" + "message": "Neebligi la Send" }, "disableSendPolicyDesc": { "message": "Ne permesu al uzantoj krei aŭ redakti Bitwarden Sendon. Forigi ekzistantan Sendon estas ankoraŭ permesita.", @@ -3902,7 +3911,7 @@ "message": "Organizaj uzantoj, kiuj povas administri la politikojn de la organizo, estas esceptitaj de la devigo de ĉi tiu politiko." }, "sendDisabled": { - "message": "Sendu malebligita", + "message": "Send neebligita", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendDisabledWarning": { @@ -4241,7 +4250,7 @@ "message": "This organization has an enterprise policy that will automatically enroll you in password reset. Enrollment will allow organization administrators to change your master password." }, "resetPasswordOrgKeysError": { - "message": "Organization Keys response is null" + "message": "La respondo de la identigilo de la organizo estas nula" }, "resetPasswordDetailsError": { "message": "Reset Password Details response is null" @@ -4753,7 +4762,7 @@ "message": "Key Connector error: make sure Key Connector is available and working correctly." }, "keyConnectorUrl": { - "message": "Key Connector URL" + "message": "URL de la Key Connector" }, "sendVerificationCode": { "message": "Send a verification code to your email" @@ -4837,10 +4846,10 @@ "message": "Disabled SSO" }, "enabledKeyConnector": { - "message": "Enabled Key Connector" + "message": "Aktivigita Key Connector" }, "disabledKeyConnector": { - "message": "Disabled Key Connector" + "message": "Neebligita Key Connector" }, "keyConnectorWarning": { "message": "Once members begin using Key Connector, your Organization cannot revert to Master Password decryption. Proceed only if you are comfortable deploying and managing a key server." @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/es/messages.json b/apps/web/src/locales/es/messages.json index c3a57c9f652..231b1a82825 100644 --- a/apps/web/src/locales/es/messages.json +++ b/apps/web/src/locales/es/messages.json @@ -428,16 +428,16 @@ "message": "Mi caja fuerte" }, "allVaults": { - "message": "Todas las bóvedas" + "message": "Todas las cajas fuertes" }, "vault": { "message": "Caja fuerte" }, "vaults": { - "message": "Bóvedas" + "message": "Cajas fuertes" }, "vaultItems": { - "message": "Elementos de la bóveda" + "message": "Elementos de la caja fuerte" }, "moveSelectedToOrg": { "message": "Mover los seleccionados a la organización" @@ -572,6 +572,9 @@ "createAccount": { "message": "Crear cuenta" }, + "startTrial": { + "message": "Iniciar período de prueba" + }, "logIn": { "message": "Identificarse" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "La contraseña maestra es la clave que utilizas para acceder a tu caja fuerte. Es muy importante que no olvides tu contraseña maestra. No hay forma de recuperarla si la olvidas." }, + "masterPassImportant": { + "message": "¡Las contraseñas maestras no pueden ser recuperadas si las olvidas!" + }, "masterPassHintDesc": { "message": "Una pista de tu contraseña maestra puede ayudarte a recordarla en caso de que la olvides." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Correo electrónico no válido." }, - "masterPassRequired": { - "message": "Contraseña maestra requerida." + "masterPasswordRequired": { + "message": "Se requiere una contraseña maestra." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Se requiere volver a teclear la contraseña maestra." + }, + "masterPasswordMinLength": { "message": "La contraseña maestra debe tener al menos 8 caracteres." }, "masterPassDoesntMatch": { @@ -667,7 +676,7 @@ "message": "Contraseña maestra no válida" }, "lockNow": { - "message": "Bloquear" + "message": "Bloquear ahora" }, "noItemsInList": { "message": "No hay elementos que listar." @@ -787,7 +796,7 @@ "message": "Utilice cualquier clave de seguridad WebAuthn habilitada para acceder a su cuenta." }, "webAuthnMigrated": { - "message": "(Migrado del FIDO)" + "message": "(Migrado desde FIDO)" }, "emailTitle": { "message": "Correo electrónico" @@ -832,7 +841,7 @@ } }, "moveSelectedItemsCountDesc": { - "message": "Ha seleccionado $COUNT$ elemento(s). $MOVEABLE_COUNT$ elemento(s) pueden ser movidos a una organización, $NONMOVEABLE_COUNT$ no puede.", + "message": "Ha seleccionado $COUNT$ elemento(s). Se pueden mover $MOVEABLE_COUNT$ elemento(s) a una organización, no se pueden mover $NONMOVEABLE_COUNT$.", "placeholders": { "count": { "content": "$1", @@ -924,7 +933,7 @@ "message": "Separador de palabras" }, "capitalize": { - "message": "Mayúsculas iniciales", + "message": "Capitalizar", "description": "Make the first letter of a work uppercase." }, "includeNumber": { @@ -1076,7 +1085,7 @@ "message": "Cuenta eliminada" }, "accountDeletedDesc": { - "message": "Tu cuenta ha sido cerrada y toda la información asociada ha sido eliminada." + "message": "Tu cuenta de Bitwarden y los datos de tu caja fuerte fueron eliminados permanentemente." }, "myAccount": { "message": "Mi cuenta" @@ -1239,7 +1248,7 @@ "message": "Activado" }, "activate": { - "message": "Activate" + "message": "Activar" }, "premium": { "message": "Premium", @@ -1267,7 +1276,7 @@ "message": "Desactivar" }, "deactivate": { - "message": "Deactivate" + "message": "Desactivar" }, "twoStepLoginProviderEnabled": { "message": "Este proveedor de autenticación en dos pasos está habilitado para tu cuenta." @@ -1548,7 +1557,7 @@ } }, "weakPasswordsReport": { - "message": "Informe de contraseñas débiles" + "message": "Contraseñas débiles" }, "weakPasswordsReportDesc": { "message": "Contraseñas débiles pueden ser fácilmente adivinadas por hackers y herramientas automatizadas que se utilizan para descifrar contraseñas- El generador de contraseñas de Bitwarden puede ayudarle a crear contraseñas fuertes." @@ -1569,7 +1578,7 @@ "message": "No hay elementos en su caja fuerte que tengan contraseñas débiles." }, "reusedPasswordsReport": { - "message": "Informe de contraseñas reutilizadas" + "message": "Contraseñas reutilizadas" }, "reusedPasswordsReportDesc": { "message": "Si un servicio que usa está comprometido, reutilizar la misma contraseña en otros lugares puede permitir que los hackers accedan fácilmente a más de sus cuentas en línea. Debe utilizar una contraseña única para cada cuenta o servicio." @@ -1590,7 +1599,7 @@ "message": "No hay inicios de sesión en su caja fuerte que tengan contraseñas que esten siendo reutilizadas." }, "reusedXTimes": { - "message": "Reutilizada $COUNT$ vez/veces", + "message": "Reutilizada $COUNT$ veces", "placeholders": { "count": { "content": "$1", @@ -1620,7 +1629,7 @@ } }, "goodNews": { - "message": "Buenas Noticias", + "message": "Buenas noticias", "description": "ex. Good News, No Breached Accounts Found!" }, "breachUsernameFound": { @@ -1673,7 +1682,7 @@ "description": "Add more credit to your account's balance." }, "amount": { - "message": "Importe", + "message": "Cantidad", "description": "Dollar amount, or quantity." }, "creditDelayed": { @@ -1780,7 +1789,7 @@ "message": "mes" }, "monthAbbr": { - "message": "mo.", + "message": "mes", "description": "Short abbreviation for 'month'" }, "paymentChargedAnnually": { @@ -1802,7 +1811,7 @@ "message": "Información de pago" }, "billingInformation": { - "message": "Información de Facturación" + "message": "Información de facturación" }, "creditCard": { "message": "Tarjeta de crédito" @@ -1844,7 +1853,7 @@ "message": "Estado" }, "nextCharge": { - "message": "Cargo siguiente" + "message": "Siguiente cobro" }, "details": { "message": "Detalles" @@ -1853,7 +1862,7 @@ "message": "Descargar licencia" }, "updateLicense": { - "message": "Actualizar Licencia" + "message": "Actualizar licencia" }, "updatedLicense": { "message": "Licencia actualizada" @@ -1893,7 +1902,7 @@ "message": "Añadir método de pago" }, "changePaymentMethod": { - "message": "Cambiar Método de Pago" + "message": "Cambiar método de pago" }, "invoices": { "message": "Facturas" @@ -2038,7 +2047,7 @@ "description": "Free as in 'free beer'." }, "planDescFree": { - "message": "Para usuarios de prueba o personales, permite compartir con $COUNT$ usuario más.", + "message": "Para usuarios de prueba o personales, permite compartir con $COUNT$ usuarios más.", "placeholders": { "count": { "content": "$1", @@ -2062,7 +2071,7 @@ "message": "Empresas" }, "planDescEnterprise": { - "message": "Para empresas u otras organizaciones grandes." + "message": "Para empresas u otras grandes organizaciones." }, "freeForever": { "message": "Gratis para siempre" @@ -2584,7 +2593,7 @@ } }, "deactivatedUserId": { - "message": "Deactivated user $ID$.", + "message": "Usuario $ID$ desactivado.", "placeholders": { "id": { "content": "$1", @@ -2593,7 +2602,7 @@ } }, "activatedUserId": { - "message": "Activated user $ID$.", + "message": "Usuario $ID$ activado.", "placeholders": { "id": { "content": "$1", @@ -2602,7 +2611,7 @@ } }, "deactivateUserId": { - "message": "Deactivate user $ID$?", + "message": "¿Desactivar el usuario $ID$?", "placeholders": { "id": { "content": "$1", @@ -2611,7 +2620,7 @@ } }, "activateUserId": { - "message": "Activate user $ID$?", + "message": "¿Activar el usuario $ID$?", "placeholders": { "id": { "content": "$1", @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Al seleccionar esta casilla, acepta lo siguiente:" }, - "acceptPoliciesError": { - "message": "Todavía no has aceptado los términos del servicio y la política de privacidad." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Términos y condiciones del servicio" @@ -3667,7 +3676,7 @@ "message": "Deshabilitado" }, "deactivated": { - "message": "Deactivated" + "message": "Desactivado" }, "sendLink": { "message": "Enlace Send", @@ -4307,10 +4316,10 @@ "message": "Eliminado con éxito" }, "bulkDeactivatedMessage": { - "message": "Deactivated successfully" + "message": "Desactivado correctamente" }, "bulkActivatedMessage": { - "message": "Activated successfully" + "message": "Activado correctamente" }, "bulkFilteredMessage": { "message": "Excluido, no aplicable a esta acción." @@ -4322,10 +4331,10 @@ "message": "Eliminar usuarios" }, "deactivateUsers": { - "message": "Deactivate Users" + "message": "Desactivar usuarios" }, "activateUsers": { - "message": "Activate Users" + "message": "Activar usuarios" }, "error": { "message": "Error" @@ -4609,13 +4618,13 @@ "message": "Tipo de enlace" }, "idpSingleSignOnServiceUrl": { - "message": "Single Sign On Service URL" + "message": "URL del servicio de inicio de sesión único" }, "idpSingleLogoutServiceUrl": { "message": "Single Log Out Service URL" }, "idpX509PublicCert": { - "message": "X509 Public Certificate" + "message": "Certificado público X509" }, "idpOutboundSigningAlgorithm": { "message": "Outbound Signing Algorithm" @@ -4657,10 +4666,10 @@ "message": "Reclaimed free plan" }, "redeem": { - "message": "Redeem" + "message": "Canjear" }, "sponsoredFamiliesSelectOffer": { - "message": "Select the organization you would like sponsored" + "message": "Seleccione la organización que desea patrocinar" }, "familiesSponsoringOrgSelect": { "message": "Which Free Families offer would you like to redeem?" @@ -4879,10 +4888,10 @@ "message": "GRATIS con patrocinio" }, "viewBillingSyncToken": { - "message": "View Billing Sync Token" + "message": "Ver el token de sincronización de facturación" }, "generateBillingSyncToken": { - "message": "Generate Billing Sync Token" + "message": "Generar el token de sincronización de facturación" }, "copyPasteBillingSync": { "message": "Copy and paste this token into the Billing Sync settings of your self-hosted organization." @@ -4891,16 +4900,16 @@ "message": "Your Billing Sync token can access and edit this organization's subscription settings." }, "manageBillingSync": { - "message": "Manage Billing Sync" + "message": "Administrar la sincronización de facturación" }, "setUpBillingSync": { - "message": "Set Up Billing Sync" + "message": "Configurar la sincronización de facturación" }, "generateToken": { - "message": "Generate Token" + "message": "Generar token" }, "rotateToken": { - "message": "Rotate Token" + "message": "Rotar token" }, "rotateBillingSyncTokenWarning": { "message": "If you proceed, you will need to re-setup billing sync on your self-hosted server." @@ -4915,7 +4924,7 @@ "message": "To set-up your organization on your own server, you will need to upload your license file. To support Free Families plans and advanced billing capabilities for your self-hosted organization, you will need to set up billing sync." }, "billingSyncApiKeyRotated": { - "message": "Token rotated." + "message": "Token rotado." }, "billingSync": { "message": "Billing Sync" @@ -4930,25 +4939,25 @@ "message": "Billing Sync Token" }, "active": { - "message": "Active" + "message": "Activo" }, "inactive": { "message": "Inactive" }, "sentAwaitingSync": { - "message": "Sent (Awaiting Sync)" + "message": "Enviado (esperando sincronización)" }, "sent": { - "message": "Sent" + "message": "Enviado" }, "requestRemoved": { - "message": "Removed (Awaiting Sync)" + "message": "Eliminado (esperando sincronización)" }, "requested": { - "message": "Requested" + "message": "Solicitado" }, "formErrorSummaryPlural": { - "message": "$COUNT$ fields above need your attention.", + "message": "$COUNT$ campos anteriores necesitan tu atención.", "placeholders": { "count": { "content": "$1", @@ -4957,10 +4966,10 @@ } }, "formErrorSummarySingle": { - "message": "1 field above needs your attention." + "message": "1 campo de los anteriores necesita su atención." }, "fieldRequiredError": { - "message": "$FIELDNAME$ is required.", + "message": "$FIELDNAME$ es requerido.", "placeholders": { "fieldname": { "content": "$1", @@ -4969,19 +4978,19 @@ } }, "required": { - "message": "required" + "message": "requerido" }, "idpSingleSignOnServiceUrlRequired": { - "message": "Required if Entity ID is not a URL." + "message": "Requerido si el ID de la entidad no es una URL." }, "openIdOptionalCustomizations": { - "message": "Optional Customizations" + "message": "Personalizaciones opcionales" }, "openIdAuthorityRequired": { - "message": "Required if Authority is not valid." + "message": "Requerido si la Autoridad no es válida." }, "separateMultipleWithComma": { - "message": "Separate multiple with a comma." + "message": "Separados por comas." }, "sessionTimeout": { "message": "Su sesión ha expirado. Por favor, vuelva e intente iniciar sesión de nuevo." @@ -5011,50 +5020,50 @@ } }, "accessDenied": { - "message": "Access Denied. You do not have permission to view this page." + "message": "Acceso denegado. No tiene permiso para ver esta página." }, "masterPassword": { - "message": "Master Password" + "message": "Contraseña maestra" }, "security": { - "message": "Security" + "message": "Seguridad" }, "keys": { - "message": "Keys" + "message": "Claves" }, "billingHistory": { - "message": "Billing History" + "message": "Historial de facturación" }, "backToReports": { - "message": "Back to Reports" + "message": "Volver a los informes" }, "organizationPicker": { - "message": "Organization picker" + "message": "Nombre de la organización" }, "currentOrganization": { - "message": "Current organization", + "message": "Organización actual", "description": "This is used by screen readers to indicate the organization that is currently being shown to the user." }, "accountSettings": { - "message": "Account Settings" + "message": "Configuración de la cuenta" }, "generator": { - "message": "Generator" + "message": "Generador" }, "whatWouldYouLikeToGenerate": { - "message": "What would you like to generate?" + "message": "¿Qué desea generar?" }, "passwordType": { - "message": "Password Type" + "message": "Tipo de contraseña" }, "regenerateUsername": { - "message": "Regenerate Username" + "message": "Regenerar nombre de usuario" }, "generateUsername": { - "message": "Generate Username" + "message": "Generar nombre de usuario" }, "usernameType": { - "message": "Username Type" + "message": "Tipo de nombre de usuario" }, "plusAddressedEmail": { "message": "Plus Addressed Email", @@ -5070,14 +5079,14 @@ "message": "Use your domain's configured catch-all inbox." }, "random": { - "message": "Random", + "message": "Aleatorio", "description": "Generates domain-based username using random letters" }, "randomWord": { - "message": "Random Word" + "message": "Palabra aleatoria" }, "service": { - "message": "Service" + "message": "Servicio" }, "unknownCipher": { "message": "Unknown Item, you may need to request permission to access this item." @@ -5086,7 +5095,7 @@ "message": "You cannot redeem for the active account. Enter a different email." }, "revokeWhenExpired": { - "message": "Expires $DATE$", + "message": "Caduca $DATE$", "placeholders": { "date": { "content": "$1", @@ -5095,7 +5104,7 @@ } }, "awaitingSyncSingular": { - "message": "Token rotated $DAYS$ day ago. Update the billing sync token in your self-hosted organization settings.", + "message": "El token se ha rotado hace $DAYS$ día. Actualice el token de sincronización de facturación en los ajustes de su organización.", "placeholders": { "days": { "content": "$1", @@ -5104,7 +5113,7 @@ } }, "awaitingSyncPlural": { - "message": "Token rotated $DAYS$ days ago. Update the billing sync token in your self-hosted organization settings.", + "message": "El token se ha rotado hace $DAYS$ días. Actualice el token de sincronización de facturación en los ajustes de su organización.", "placeholders": { "days": { "content": "$1", @@ -5113,14 +5122,14 @@ } }, "lastSync": { - "message": "Last Sync", + "message": "Última sincronización", "Description": "Used as a prefix to indicate the last time a sync occured. Example \"Last sync 1968-11-16 00:00:00\"" }, "sponsorshipsSynced": { "message": "Self-hosted sponsorships synced." }, "billingManagedByProvider": { - "message": "Managed by $PROVIDER$", + "message": "Gestionado por $PROVIDER$", "placeholders": { "provider": { "content": "$1", @@ -5129,21 +5138,21 @@ } }, "billingContactProviderForAssistance": { - "message": "Please reach out to them for further assistance", + "message": "Por favor, contacte con ellos para obtener más ayuda", "description": "This text is displayed if an organization's billing is managed by a Provider. It tells the user to contact the Provider for assistance." }, "forwardedEmail": { "message": "Forwarded Email Alias" }, "forwardedEmailDesc": { - "message": "Generate an email alias with an external forwarding service." + "message": "Generar un alias de correo electrónico mediante un servicio de reenvío externo." }, "hostname": { - "message": "Hostname", + "message": "Nombre del host", "description": "Part of a URL." }, "apiAccessToken": { - "message": "API Access Token" + "message": "Token de acceso API" }, "deviceVerification": { "message": "Verificación del dispositivo" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Entrada requerida." + }, + "inputEmail": { + "message": "La entrada no es una dirección de correo electrónico." + }, + "inputMinLength": { + "message": "La entrada debe tener al menos $COUNT$ caracteres.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ campo(s) anteriores necesitan su atención.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/et/messages.json b/apps/web/src/locales/et/messages.json index 193763ce43b..b1c8e039aad 100644 --- a/apps/web/src/locales/et/messages.json +++ b/apps/web/src/locales/et/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Konto loomine" }, + "startTrial": { + "message": "Alusta prooviperioodi" + }, "logIn": { "message": "Logi sisse" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Ülemparooliga pääsed oma kontole ligi. On äärmiselt tähtis, et ülemparool ei ununeks. Selle parooli taastamine ei ole mingil moel võimalik." }, + "masterPassImportant": { + "message": "Ülemparooli ei saa taastada, kui sa selle unustama peaksid!" + }, "masterPassHintDesc": { "message": "Vihje võib abiks olla olukorras, kui oled ülemparooli unustanud." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Vigane e-posti aadress." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Vajalik on ülemparooli sisestamine." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Vajalik on ülemparooli uuesti sisestamine." + }, + "masterPasswordMinLength": { "message": "Ülemparool peab olema vähemalt 8 tähemärgi pikkune." }, "masterPassDoesntMatch": { @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "Märkeruudu markeerimisel nõustud järgnevaga:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Kasutustingimuste ja Privaatsuspoliitikaga pole nõustutud." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Sisestus on nõutav." + }, + "inputEmail": { + "message": "Tegu pole e-posti aadressiga." + }, + "inputMinLength": { + "message": "Sisend peab olema vähemalt $COUNT$ tähemärki pikk.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ välja vajab sinu tähelepanu.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/eu/messages.json b/apps/web/src/locales/eu/messages.json index 047e6c2fb38..c7064722804 100644 --- a/apps/web/src/locales/eu/messages.json +++ b/apps/web/src/locales/eu/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Create Account" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Log In" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "A master password hint can help you remember your password if you forget it." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1076,7 +1085,7 @@ "message": "Account Deleted" }, "accountDeletedDesc": { - "message": "Your account has been closed and all associated data has been deleted." + "message": "Your Bitwarden account and vault data were permanently deleted." }, "myAccount": { "message": "My Account" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/fi/messages.json b/apps/web/src/locales/fi/messages.json index b5a72a79306..0a67f6838e8 100644 --- a/apps/web/src/locales/fi/messages.json +++ b/apps/web/src/locales/fi/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Luo tili" }, + "startTrial": { + "message": "Aloita kokeilu" + }, "logIn": { "message": "Kirjaudu sisään" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Pääsalasanalla pääset käsiksi holviisi. On erittäin tärkeää, että muistat pääsalasanasi, koska sen palautus ei ole mahdollista, jos unohdat sen." }, + "masterPassImportant": { + "message": "Pääsalasanan palautus ei ole mahdollista, jos unohdat sen!" + }, "masterPassHintDesc": { "message": "Pääsalasanan vihje voi auttaa sinua muistamaan unohtamasi salasanan." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Virheellinen sähköpostiosoite." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Pääsalasana vaaditaan." }, - "masterPassLength": { - "message": "Pääsalasanan on oltava vähintään 8 merkkiä pitkä." + "confirmMasterPasswordRequired": { + "message": "Pääsalasanan uudelleensyöttö vaaditaan." + }, + "masterPasswordMinLength": { + "message": "Pääsalasanan tulee sisältää ainakin 8 merkkiä." }, "masterPassDoesntMatch": { "message": "Pääsalasanan vahvistus ei täsmää." @@ -1076,7 +1085,7 @@ "message": "Tili poistettu" }, "accountDeletedDesc": { - "message": "Tilisi on suljettu ja kaikki siihen liittyvät tiedot on poistettu." + "message": "Bitwarden-tilisi ja -holvin tiedot on poistettu pysyvästi." }, "myAccount": { "message": "Oma tili" @@ -2812,7 +2821,7 @@ "message": "Sähköpostiosoitteesi on vahvistettu." }, "emailVerifiedFailed": { - "message": "Sähköpostiosoitteesi vahvistus ei onnistunut. Yritä lähettää uusi vahvistussähköposti." + "message": "Sähköpostiosoitettasi ei voitu vahvistaa. Yritä lähettää uusi vahvistussähköposti." }, "emailVerificationRequired": { "message": "Sähköpostiosoitteen vahvistus vaaditaan" @@ -2839,7 +2848,7 @@ "message": "Saat organisaation käyttöoikeuden ylläpitäjän vahvistettua jäsentyytesi. Saat vahvistuksesta ilmoituksen sähköpostitse." }, "inviteAcceptFailed": { - "message": "Kutsun hyväksyntä ei onnistu. Pyydä organisaation ylläpitäjää lähettämään uusi kutsu." + "message": "Kutsua ei voitu hyväksyä. Pyydä organisaation ylläpitäjää lähettämään uusi kutsu." }, "inviteAcceptFailedShort": { "message": "Kutsua ei voitu hyväksyä. $DESCRIPTION$", @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "Valitsemalla tämän ruudun hyväksyt seuraavat:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Käyttöehtoja ja tietosuojakäytäntöä ei ole vahvistettu." }, "termsOfService": { @@ -3810,7 +3819,7 @@ "message": "Sinut on kutsuttu yllä mainitun käyttäjän varmuuskontaktiksi. Hyväksyäksesi kutsun, sinun tulee kirjautua tilillesi tai luoda uusi Bitwarden tili." }, "emergencyInviteAcceptFailed": { - "message": "Kutsun hyväksyntä ei onnistu. Pyydä käyttäjää lähettämään uusi kutsu." + "message": "Kutsua ei voitu hyväksyä. Pyydä käyttäjää lähettämään uusi kutsu." }, "emergencyInviteAcceptFailedShort": { "message": "Kutsua ei voitu hyväksyä. $DESCRIPTION$", @@ -4373,7 +4382,7 @@ "message": "Sinut on kutsuttu liittymään yllä mainittuun todentajaan. Hyväksyäksesi kutsun, sinun tulee kirjautua tilillesi tai luoda uusi Bitwarden-tili." }, "providerInviteAcceptFailed": { - "message": "Kutsua ei voida hyväksyä. Pyydä todentajan ylläpitäjää lähettämään uusi kutsu." + "message": "Kutsua ei voitu hyväksyä. Pyydä todentajan ylläpitäjää lähettämään uusi kutsu." }, "providerInviteAcceptedDesc": { "message": "Pääset käyttämään todentajaa ylläpitäjän vahvistettua jäsentyytesi. Saat tästä ilmoituksen sähköpostitse." @@ -4678,10 +4687,10 @@ "message": "Sinulle on tarjottu ilmaista Bitwarden Perheille -organisaatiota. Jatkaaksesi sinun on kirjauduttava tarjouksen saaneelle tilille." }, "sponsoredFamiliesAcceptFailed": { - "message": "Tarjousta ei voida hyväksyä. Lähetä tarjoussähköposti uudestaan yritystililtäsi ja yritä uudelleen." + "message": "Tarjousta ei voitu hyväksyä. Lähetä tarjoussähköposti uudestaan yritystililtäsi ja yritä uudelleen." }, "sponsoredFamiliesAcceptFailedShort": { - "message": "Tarjousta ei voida hyväksyä. $DESCRIPTION$", + "message": "Kutsua ei voitu hyväksyä. $DESCRIPTION$", "placeholders": { "description": { "content": "$1", @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Syöte vaaditaan." + }, + "inputEmail": { + "message": "Syöte ei ole sähköpostiosoite." + }, + "inputMinLength": { + "message": "Syötteen tulee sisältää ainakin $COUNT$ merkkiä.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ yllä oleva(a) kenttä(ä) vaatii huomiotasi.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/fil/messages.json b/apps/web/src/locales/fil/messages.json index ecd7d00efa9..0bc3b0eb250 100644 --- a/apps/web/src/locales/fil/messages.json +++ b/apps/web/src/locales/fil/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Create Account" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Log In" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "A master password hint can help you remember your password if you forget it." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1076,7 +1085,7 @@ "message": "Account Deleted" }, "accountDeletedDesc": { - "message": "Your account has been closed and all associated data has been deleted." + "message": "Your Bitwarden account and vault data were permanently deleted." }, "myAccount": { "message": "My Account" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/fr/messages.json b/apps/web/src/locales/fr/messages.json index 27274b0150f..9ae0281ce2f 100644 --- a/apps/web/src/locales/fr/messages.json +++ b/apps/web/src/locales/fr/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Créer un compte" }, + "startTrial": { + "message": "Commencer la Période d'Essai" + }, "logIn": { "message": "S'identifier" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Le mot de passe maître est le mot de passe que vous utilisez pour accéder à votre coffre. Il est très important de ne pas l'oublier. Il n'existe aucun moyen de le récupérer si vous le perdez." }, + "masterPassImportant": { + "message": "Le mot de passe maître ne peut pas être récupérés si vous l'oubliez!" + }, "masterPassHintDesc": { "message": "Un indice de mot de passe maître peut vous aider à vous rappeler de votre mot de passe en cas d'oubli." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Adresse e-mail invalide." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Le mot de passe maître est requis." }, - "masterPassLength": { - "message": "Le mot de passe maître doit au moins contenir 8 caractères." + "confirmMasterPasswordRequired": { + "message": "Le mot de passe maître doit être entré de nouveau." + }, + "masterPasswordMinLength": { + "message": "Le mot de passe maître doit comporter au moins 8 caractères." }, "masterPassDoesntMatch": { "message": "La confirmation du mot de passe maître ne correspond pas." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "En cochant cette case, vous acceptez les éléments suivants :" }, - "acceptPoliciesError": { - "message": "Les conditions d'utilisation et la politique de confidentialité n'ont pas été acceptées." + "acceptPoliciesRequired": { + "message": "Les Conditions d'Utilisation et la Politique de Confidentialité n'ont pas été acceptées." }, "termsOfService": { "message": "Conditions d'utilisation" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Entrée requise." + }, + "inputEmail": { + "message": "L'entrée n'est pas une adresse e-mail." + }, + "inputMinLength": { + "message": "L'entrée doit comporter au moins $COUNT$ caractères.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ champ(s) ci-dessus nécessitent votre attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/he/messages.json b/apps/web/src/locales/he/messages.json index d8f1706d92d..626507c68bf 100644 --- a/apps/web/src/locales/he/messages.json +++ b/apps/web/src/locales/he/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "צור חשבון" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "התחבר" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "הסיסמה הראשית היא הסיסמה שבאמצעותה תיגש לכספת שלך. חשוב מאוד שלא תשכח את הסיסמה הזו. אין שום דרך לשחזר אותה במקרה ושכחת אותה." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "ניתן להשתמש ברמז לסיסמה הראשית אם שכחת אותה." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "כתובת אימייל לא תקינה." }, - "masterPassRequired": { - "message": "יש להזין את הסיסמה הראשית." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "הסיסמה הראשית חייבת להיות לפחות באורך 8 תווים." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "שדה אימות סיסמה ראשית לא תואם." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "סימון תיבה זו מהווה את הסכמתך לתנאים הבאים:" }, - "acceptPoliciesError": { - "message": "לא הסכמת לתנאי השירות ומדיניות הפרטיות." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "תנאי שירות" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/hi/messages.json b/apps/web/src/locales/hi/messages.json index 324d06f0bc9..986c0069933 100644 --- a/apps/web/src/locales/hi/messages.json +++ b/apps/web/src/locales/hi/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Create Account" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Log In" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "A master password hint can help you remember your password if you forget it." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1076,7 +1085,7 @@ "message": "Account Deleted" }, "accountDeletedDesc": { - "message": "Your account has been closed and all associated data has been deleted." + "message": "Your Bitwarden account and vault data were permanently deleted." }, "myAccount": { "message": "My Account" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/hr/messages.json b/apps/web/src/locales/hr/messages.json index 9ec828fb945..538f33413dd 100644 --- a/apps/web/src/locales/hr/messages.json +++ b/apps/web/src/locales/hr/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Stvori račun" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Prijavi se" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Glavnu lozinku koristiš za pristup svom trezoru. Vrlo je važno da ne zaboraviš glavnu lozinku. Ne postoji način za oporavak lozinke u slučaju da ju zaboraviš." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "Podsjetnik glavne lozinke ti može pomoći da se prisjetiš svoje lozinke ako ju zaboraviš." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Neispravna adresa e-pošte." }, - "masterPassRequired": { - "message": "Potrebna je glavna lozinka." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Glavna lozinka mora imati najmanje 8 znakova." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Potvrda glavne lozinke se ne podudara." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Označavanjem ove kućice slažete se sa sljedećim:" }, - "acceptPoliciesError": { - "message": "Uvjeti korištenja i Pravila privatnosti nisu prihvaćeni." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Uvjeti korištenja" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/hu/messages.json b/apps/web/src/locales/hu/messages.json index 3b6010deaec..e0185c98922 100644 --- a/apps/web/src/locales/hu/messages.json +++ b/apps/web/src/locales/hu/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Fiók létrehozása" }, + "startTrial": { + "message": "Próbaverzió indítása" + }, "logIn": { "message": "Bejelentkezés" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "A mesterjelszó a jelszó a széf eléréséhez. Nagyon fontos a mesterjelszó ismerete. Nincs mód a jelszó visszaállítására." }, + "masterPassImportant": { + "message": "Az elfelejtett mesterjelszavak nem állíthatók helyre!" + }, "masterPassHintDesc": { "message": "A mesterjelszó emlékeztető segíthet emlékezni a jelszóra elfelejtése esetén." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Az email cím érvénytelen." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "A mesterjelszó megadása kötelező." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "A mesterjelszó ismételt megadása kötelező." + }, + "masterPasswordMinLength": { "message": "A mesterjelszó legyen legalább 8 karakter hosszú." }, "masterPassDoesntMatch": { @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "A doboz bejelölésével elfogadjuk a következőket:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "A szolgáltatási feltételeket és az adatvédelmi irányelveket nem vették figyelembe." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Az adatbevitel kötelező." + }, + "inputEmail": { + "message": "Az megadott adat nem email cím." + }, + "inputMinLength": { + "message": "Az adat legyen legalább $COUNT$ karakter hosszú.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ mező fentebb figyelmet érdemel.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/id/messages.json b/apps/web/src/locales/id/messages.json index d663b112759..5fcbecfd486 100644 --- a/apps/web/src/locales/id/messages.json +++ b/apps/web/src/locales/id/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Buat Akun" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Masuk" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Kata sandi utama adalah kata sandi yang Anda gunakan untuk mengakses brankas Anda. Sangat penting bahwa Anda tidak lupa kata sandi utama Anda. Tidak ada cara untuk memulihkan kata sandi jika Anda melupakannya." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "Petunjuk kata sandi utama dapat membantu Anda mengingat kata sandi Anda jika Anda melupakannya." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Alamat surel tidak valid." }, - "masterPassRequired": { - "message": "Sandi utama diperlukan." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Kata sandi utama sedikitnya harus 8 karakter." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Konfirmasi sandi utama tidak cocok." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Dengan mencentang kotak ini, anda menyetujui yang berikut:" }, - "acceptPoliciesError": { - "message": "Persyaratan Layanan dan Kebijakan Privasi belum diakui." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Persyaratan Layanan" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/it/messages.json b/apps/web/src/locales/it/messages.json index 0745bc5b555..5769ed98ba2 100644 --- a/apps/web/src/locales/it/messages.json +++ b/apps/web/src/locales/it/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Crea account" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Accedi" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "La password principale è la password che utilizzi per accedere alla tua cassaforte. È molto importante che tu non la dimentichi. Non c'è modo di recuperare questa password nel caso che tu la dimenticassi." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "Un suggerimento che può aiutarti a ricordare la tua password principale se la dimentichi." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "L'indirizzo email non è valido." }, - "masterPassRequired": { - "message": "La password principale è obbligatoria." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "La password principale deve essere almeno di 8 caratteri." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "La conferma della password principale non corrisponde." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Selezionando la casella accetti quanto segue:" }, - "acceptPoliciesError": { - "message": "I termini di servizio e l'informativa sulla privacy non sono stati accettati." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Termini del servizio" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/ja/messages.json b/apps/web/src/locales/ja/messages.json index 30d640265f8..c1fb67709b4 100644 --- a/apps/web/src/locales/ja/messages.json +++ b/apps/web/src/locales/ja/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "アカウントの作成" }, + "startTrial": { + "message": "試用版を開始" + }, "logIn": { "message": "ログイン" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "マスターパスワードは、パスワード保管庫へのアクセスに使用するパスワードです。あなたのマスターパスワードを忘れないように注意してください。忘れた場合、パスワードを回復する方法はありません。" }, + "masterPassImportant": { + "message": "マスターパスワードを忘れた場合は復元できません!" + }, "masterPassHintDesc": { "message": "マスターパスワードのヒントは、パスワードを忘れた場合に役立ちます。" }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "無効なメールアドレスです。" }, - "masterPassRequired": { - "message": "マスターパスワードは必須です。" + "masterPasswordRequired": { + "message": "マスター パスワードが必要です。" }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "マスターパスワードの再入力が必要です。" + }, + "masterPasswordMinLength": { "message": "マスターパスワードは、少なくとも8文字以上で設定してください。" }, "masterPassDoesntMatch": { @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "以下に同意しチェックします:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "利用規約とプライバシーポリシーを確認してください。" }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "入力が必要です。" + }, + "inputEmail": { + "message": "入力したものはメールアドレスではありません。" + }, + "inputMinLength": { + "message": "$COUNT$ 文字以上でなければなりません。", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "上記の $COUNT$ フィールドを確認してください。", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/ka/messages.json b/apps/web/src/locales/ka/messages.json index 0e32e2dd533..c9ffaf9b01f 100644 --- a/apps/web/src/locales/ka/messages.json +++ b/apps/web/src/locales/ka/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Create Account" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Log In" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "A master password hint can help you remember your password if you forget it." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1076,7 +1085,7 @@ "message": "Account Deleted" }, "accountDeletedDesc": { - "message": "Your account has been closed and all associated data has been deleted." + "message": "Your Bitwarden account and vault data were permanently deleted." }, "myAccount": { "message": "My Account" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/km/messages.json b/apps/web/src/locales/km/messages.json index 0e32e2dd533..c9ffaf9b01f 100644 --- a/apps/web/src/locales/km/messages.json +++ b/apps/web/src/locales/km/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Create Account" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Log In" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "A master password hint can help you remember your password if you forget it." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1076,7 +1085,7 @@ "message": "Account Deleted" }, "accountDeletedDesc": { - "message": "Your account has been closed and all associated data has been deleted." + "message": "Your Bitwarden account and vault data were permanently deleted." }, "myAccount": { "message": "My Account" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/kn/messages.json b/apps/web/src/locales/kn/messages.json index 820c37519af..7ec36be5fed 100644 --- a/apps/web/src/locales/kn/messages.json +++ b/apps/web/src/locales/kn/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "ಖಾತೆ ತೆರೆ" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "ಲಾಗಿನ್" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "ನಿಮ್ಮ ವಾಲ್ಟ್ ಅನ್ನು ಪ್ರವೇಶಿಸಲು ನೀವು ಬಳಸುವ ಪಾಸ್ವರ್ಡ್ ಮಾಸ್ಟರ್ ಪಾಸ್ವರ್ಡ್ ಆಗಿದೆ. ನಿಮ್ಮ ಮಾಸ್ಟರ್ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ನೀವು ಮರೆಯದಿರುವುದು ಬಹಳ ಮುಖ್ಯ. ನೀವು ಅದನ್ನು ಮರೆತ ಸಂದರ್ಭದಲ್ಲಿ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಮರುಪಡೆಯಲು ಯಾವುದೇ ಮಾರ್ಗವಿಲ್ಲ." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ನೀವು ಮರೆತರೆ ಅದನ್ನು ನೆನಪಿಟ್ಟುಕೊಳ್ಳಲು ಮಾಸ್ಟರ್ ಪಾಸ್‌ವರ್ಡ್ ಸುಳಿವು ನಿಮಗೆ ಸಹಾಯ ಮಾಡುತ್ತದೆ." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "ಅಮಾನ್ಯ ಇಮೇಲ್ ವಿಳಾಸ." }, - "masterPassRequired": { - "message": "ಮಾಸ್ಟರ್ ಪಾಸ್ವರ್ಡ್ ಅಗತ್ಯವಿದೆ." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "ಮಾಸ್ಟರ್ ಪಾಸ್‌ವರ್ಡ್ ಕನಿಷ್ಠ 8 ಅಕ್ಷರಗಳಷ್ಟು ಉದ್ದವಾಗಿರಬೇಕು." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "ಮಾಸ್ಟರ್ ಪಾಸ್‌ವರ್ಡ್ ದೃಢೀಕರಣವು ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "ಈ ಪೆಟ್ಟಿಗೆಯನ್ನು ಪರಿಶೀಲಿಸುವ ಮೂಲಕ ನೀವು ಈ ಕೆಳಗಿನವುಗಳನ್ನು ಒಪ್ಪುತ್ತೀರಿ:" }, - "acceptPoliciesError": { - "message": "ಸೇವಾ ನಿಯಮಗಳು ಮತ್ತು ಗೌಪ್ಯತೆ ನೀತಿಯನ್ನು ಅಂಗೀಕರಿಸಲಾಗಿಲ್ಲ." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "ಸೇವಾ ನಿಯಮಗಳು" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/ko/messages.json b/apps/web/src/locales/ko/messages.json index b9f07f19414..1cef4ac5381 100644 --- a/apps/web/src/locales/ko/messages.json +++ b/apps/web/src/locales/ko/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "계정 만들기" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "로그인" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "마스터 비밀번호는 보관함을 열 때 필요한 비밀번호입니다. 절대 마스터 비밀번호를 잊어버리지 마세요. 잊어버리면 복구할 수 있는 방법이 없습니다." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "마스터 비밀번호 힌트는 마스터 비밀번호를 잊었을 때 도움이 될 수 있습니다." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "잘못된 이메일 주소입니다." }, - "masterPassRequired": { - "message": "마스터 비밀번호는 반드시 입력해야 합니다." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "마스터 비밀번호는 최소 8자 이상이어야 합니다." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "마스터 비밀번호 확인과 마스터 비밀번호가 일치하지 않습니다." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "이 박스를 체크하면 다음에 동의하는 것으로 간주됩니다:" }, - "acceptPoliciesError": { - "message": "서비스 약관 및 개인 정보 보호 정책을 확인하지 않았습니다." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "서비스 약관" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/lv/messages.json b/apps/web/src/locales/lv/messages.json index 4a206389ea5..5bdbb4a02cb 100644 --- a/apps/web/src/locales/lv/messages.json +++ b/apps/web/src/locales/lv/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Izveidot kontu" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Pierakstīties" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Galvenā parole ir parole, kas tiek izmantota, lai piekļūtu glabātavai. Ir ļoti svarīgi, ka tā netiek aizmirsta, jo tādā gadījumā to nav iespējams atgūt." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "Galvenās paroles norāde var palīdzēt atcerēties paroli, ja tā ir aizmirsta." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Nederīga e-pasta adrese." }, - "masterPassRequired": { - "message": "Ir jānorāda galvenā parole." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Galvenajai parolei ir jābūt vismaz 8 rakstzīmes garai." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Galvenās paroles apstiprinājums nesakrīt." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Atzīmējot šo rūtiņu, Tu piekrīti sekojošajam:" }, - "acceptPoliciesError": { - "message": "Nav pieņemti izmantošanas nosacījumi un privātuma politika." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Izmantošanas nosacījumi" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/ml/messages.json b/apps/web/src/locales/ml/messages.json index af3cb86c116..9022f02794a 100644 --- a/apps/web/src/locales/ml/messages.json +++ b/apps/web/src/locales/ml/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "അക്കൗണ്ട് സൃഷ്ടിക്കുക" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "പ്രവേശിക്കുക" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "നിങ്ങളുടെ വാൾട്ടിലേക്ക് പ്രവേശിക്കാൻ ഉപയോഗിക്കുന്ന പാസ്‌വേഡാണ് പ്രാഥമിക പാസ്‌വേഡ്. പ്രാഥമിക പാസ്‌വേഡ് നിങ്ങൾ ഒരു കാരണവശാലും മറക്കരുത്. നിങ്ങൾ പാസ്‌വേഡ് മറന്നാൽ, വീണ്ടെടുക്കാൻ വേറെ ഒരു മാർഗ്ഗവുമില്ല." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "നിങ്ങളുടെ പാസ്‌വേഡ് മറന്നാൽ അത് ഓർമ്മിക്കാൻ ഒരു പ്രാഥമിക പാസ്‌വേഡ് സൂചന സഹായിക്കും." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "അസാധുവായ ഇമെയിൽ." }, - "masterPassRequired": { - "message": "പ്രാഥമിക പാസ്‌വേഡ് നിർബന്ധമാണ്‌." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "പ്രാഥമിക പാസ്‌വേഡിന് കുറഞ്ഞത് 8 പ്രതീകങ്ങളെങ്കിലും ദൈർഘ്യമുണ്ടായിരിക്കണം." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "പ്രാഥമിക പാസ്‌വേഡ് സ്ഥിരീകരണം പൊരുത്തപ്പെടുന്നില്ല." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "ഈ ബോക്സ് ചെക്കുചെയ്യുന്നതിലൂടെ നിങ്ങൾ ഇനിപ്പറയുന്നവ അംഗീകരിക്കുന്നു:" }, - "acceptPoliciesError": { - "message": "സേവന നിബന്ധനകളും സ്വകാര്യതാ നയവും അംഗീകരിച്ചിട്ടില്ല." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "സേവന വ്യവസ്ഥകൾ" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/nb/messages.json b/apps/web/src/locales/nb/messages.json index 71b96b032c4..5bd7efbacac 100644 --- a/apps/web/src/locales/nb/messages.json +++ b/apps/web/src/locales/nb/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Opprett en konto" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Logg på" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Superpassordet er passordet du bruker for å få tilgang til hvelvet ditt. Det er veldig viktig at du aldri glemmer ditt superpassord. Det er ingen måter å få tilbake passordet på dersom du noensinne skulle klare å glemme det." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "Et hint for superpassordet kan hjelpe deg med å huske på passordet dersom du skulle glemme det." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Ugyldig E-postadresse." }, - "masterPassRequired": { - "message": "Superpassordet er påkrevd." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Superpassordet må være ≥8 tegn langt." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Superpassord-bekreftelsen er ikke samsvarende." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Ved å huke av denne boksen sier du deg enig i følgende:" }, - "acceptPoliciesError": { - "message": "Bruksvilkårene og personvernerklæring er ikke godkjent." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Tjenestevilkår" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/nl/messages.json b/apps/web/src/locales/nl/messages.json index 345b112909c..01ced9dbc65 100644 --- a/apps/web/src/locales/nl/messages.json +++ b/apps/web/src/locales/nl/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Account aanmaken" }, + "startTrial": { + "message": "Start proefperiode" + }, "logIn": { "message": "Inloggen" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Het hoofdwachtwoord is het wachtwoord waarmee je toegang krijgt tot je beveiligde kluis. Het is belangrijk dat je het hoofdwachtwoord niet vergeet, want er is geen manier om het te herstellen." }, + "masterPassImportant": { + "message": "Hoofdwachtwoorden kun je niet herstellen als je ze vergeet!" + }, "masterPassHintDesc": { "message": "Een hoofdwachtwoordhint kan je helpen je wachtwoord te herinneren als je het vergeten bent." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Ongeldig e-mailadres." }, - "masterPassRequired": { - "message": "Hoofdwachtwoord is vereist." + "masterPasswordRequired": { + "message": "Hoofdwachtwoord vereist." }, - "masterPassLength": { - "message": "Het hoofdwachtwoord moet minimaal 8 tekens lang zijn." + "confirmMasterPasswordRequired": { + "message": "Type je hoofdwachtwoord opnieuw in." + }, + "masterPasswordMinLength": { + "message": "Hoofdwachtwoord moet minimaal 8 tekens lang zijn." }, "masterPassDoesntMatch": { "message": "De hoofdwachtwoorden komen niet overeen." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Door dit vakje aan te vinken ga je akkoord met het volgende:" }, - "acceptPoliciesError": { - "message": "Algemene voorwaarden en privacybeleid zijn nog niet erkend." + "acceptPoliciesRequired": { + "message": "Je hebt de algemene voorwaarden en het privacybeleid nog niet erkend." }, "termsOfService": { "message": "Algemene gebruiksvoorwaarden" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Invoer vereist." + }, + "inputEmail": { + "message": "Invoer is geen e-mailadres." + }, + "inputMinLength": { + "message": "Invoer moet minimaal $COUNT$ tekens lang zijn.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ veld(en) hierboven hebben je aandacht nodig.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/nn/messages.json b/apps/web/src/locales/nn/messages.json index 77dd2db4f5f..dfca1ec01b1 100644 --- a/apps/web/src/locales/nn/messages.json +++ b/apps/web/src/locales/nn/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Create Account" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Log In" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Hovudpassordet er passordet du brukar for å få tilgjenge til kvelvet ditt. Det er veldig viktig at du ikkje gløymer hovudpassordet ditt. Det er umogleg å få tilbake passordet om du so gløymer det." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "Eit hovudpassordvink kan hjelpa deg med å hugsa passordet ditt om du gløymer det." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Ugild e-postadresse." }, - "masterPassRequired": { - "message": "Hovudpassord er påkravt." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Hovudpassordet ditt må vera på minst 8 teikn." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Stadfesting av hovudpassordet samsvarar ikkje." @@ -1076,7 +1085,7 @@ "message": "Kontoen er sletta" }, "accountDeletedDesc": { - "message": "Your account has been closed and all associated data has been deleted." + "message": "Your Bitwarden account and vault data were permanently deleted." }, "myAccount": { "message": "My Account" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/pl/messages.json b/apps/web/src/locales/pl/messages.json index d73a957910c..2a4d37ce497 100644 --- a/apps/web/src/locales/pl/messages.json +++ b/apps/web/src/locales/pl/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Utwórz konto" }, + "startTrial": { + "message": "Rozpocznij okres próbny" + }, "logIn": { "message": "Zaloguj się" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Hasło główne zapewnia dostęp do sejfu. To bardzo ważne, aby je pamiętać, ponieważ zapomnianego hasła nie będzie można odzyskać." }, + "masterPassImportant": { + "message": "Hasła główne nie mogą zostać odzyskane, jeśli je zapomnisz!" + }, "masterPassHintDesc": { "message": "Podpowiedź do hasła głównego może pomóc Ci przypomnieć hasło, jeśli je zapomnisz." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Adres e-mail jest nieprawidłowy." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Hasło główne jest wymagane." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Wymagane jest ponowne wpisanie hasła głównego." + }, + "masterPasswordMinLength": { "message": "Hasło główne musi zawierać co najmniej 8 znaków." }, "masterPassDoesntMatch": { @@ -1152,7 +1161,7 @@ "message": "Zmień język używany przez sejf." }, "enableFavicon": { - "message": "Pokaż ikonkę strony" + "message": "Pokaż ikony stron" }, "faviconDesc": { "message": "Pokaż rozpoznawalny obrazek obok każdego elementu." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Zaznaczając tę opcję, akceptujesz:" }, - "acceptPoliciesError": { - "message": "Nie zaakceptowałeś regulaminu i polityki prywatności." + "acceptPoliciesRequired": { + "message": "Warunki użytkowania i polityka prywatności nie zostały zaakceptowane." }, "termsOfService": { "message": "Regulamin" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Dane wejściowe są wymagane." + }, + "inputEmail": { + "message": "Dane wejściowe nie są adresem e-mail." + }, + "inputMinLength": { + "message": "Dane wejściowe muszą zawierać co najmniej $COUNT$ znaki(-ów).", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "Pola powyżej wymagające Twojej uwagi: $COUNT$.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/pt_BR/messages.json b/apps/web/src/locales/pt_BR/messages.json index 6b5155ff9fd..4faa5126a07 100644 --- a/apps/web/src/locales/pt_BR/messages.json +++ b/apps/web/src/locales/pt_BR/messages.json @@ -191,7 +191,7 @@ "description": "Domain name. Ex. website.com" }, "domainName": { - "message": "Domain Name", + "message": "Nome do domínio", "description": "Domain name. Ex. website.com" }, "host": { @@ -422,22 +422,22 @@ "description": "Copy URI to clipboard" }, "me": { - "message": "Me" + "message": "Eu" }, "myVault": { "message": "Meu Cofre" }, "allVaults": { - "message": "All Vaults" + "message": "Todos os Cofres" }, "vault": { "message": "Cofre" }, "vaults": { - "message": "Vaults" + "message": "Cofres" }, "vaultItems": { - "message": "Vault Items" + "message": "Itens do Cofre" }, "moveSelectedToOrg": { "message": "Mover Selecionados para a organização" @@ -572,6 +572,9 @@ "createAccount": { "message": "Criar Conta" }, + "startTrial": { + "message": "Iniciar Período de Testes" + }, "logIn": { "message": "Iniciar Sessão" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "A senha mestra é a senha que você usa para acessar o seu cofre. É muito importante que você não esqueça sua senha mestra. Não há maneira de recuperar a senha caso você se esqueça." }, + "masterPassImportant": { + "message": "Senhas mestres não podem ser recuperadas se você esquecê-la!" + }, "masterPassHintDesc": { "message": "Uma dica de senha mestra pode ajudá-lo(a) a lembrar a senha caso você esqueça." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Endereço de e-mail inválido." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "A senha mestra é obrigatória." }, - "masterPassLength": { - "message": "A senha mestra deve ter pelo menos 8 caracteres." + "confirmMasterPasswordRequired": { + "message": "A senha mestra é necessária." + }, + "masterPasswordMinLength": { + "message": "A senha mestra deve ter ao menos 8 caracteres." }, "masterPassDoesntMatch": { "message": "A confirmação da senha mestra não corresponde." @@ -1137,13 +1146,13 @@ "message": "Opções" }, "preferences": { - "message": "Preferences" + "message": "Preferências" }, "preferencesDesc": { - "message": "Customize your web vault experience." + "message": "Personalize sua experiência no cofre web." }, "preferencesUpdated": { - "message": "Preferences updated" + "message": "Preferências atualizadas" }, "language": { "message": "Idioma" @@ -1152,10 +1161,10 @@ "message": "Altere o idioma usado pelo cofre web." }, "enableFavicon": { - "message": "Show website icons" + "message": "Mostrar ícones do site" }, "faviconDesc": { - "message": "Show a recognizable image next to each login." + "message": "Mostrar uma imagem reconhecível ao lado de cada login." }, "enableGravatars": { "message": "Habilitar Gravatar", @@ -1239,7 +1248,7 @@ "message": "Habilitado" }, "activate": { - "message": "Activate" + "message": "Ativar" }, "premium": { "message": "Premium", @@ -1267,7 +1276,7 @@ "message": "Desabilitar" }, "deactivate": { - "message": "Deactivate" + "message": "Desativado" }, "twoStepLoginProviderEnabled": { "message": "Este provedor de login em duas etapas está ativado em sua conta." @@ -1466,7 +1475,7 @@ "message": "Relatórios" }, "reportsDesc": { - "message": "Identify and close security gaps in your online accounts by clicking the reports below.", + "message": "Identifique e feche as lacunas de segurança em suas contas online clicando nos relatórios abaixo.", "description": "Vault Health Reports can be used to evaluate the security of your Bitwarden Personal or Organization Vault." }, "unsecuredWebsitesReport": { @@ -2233,10 +2242,10 @@ "message": "Você tem certeza que deseja remover este(a) usuário(a)?" }, "deactivateUserConfirmation": { - "message": "The member will no longer have access to the organization, but will still have access to their individual vault." + "message": "O membro já não terá acesso à organização, mas ainda terá acesso ao seu cofre individual." }, "activateUserConfirmation": { - "message": "Are you sure you want to activate this user, granting them access to the organization?" + "message": "Tem certeza de que deseja ativar este usuário, concedendo-lhes o acesso à organização?" }, "removeUserConfirmationKeyConnector": { "message": "Aviso! Este usuário precisa do Conector de Chave para gerenciar sua criptografia. Remover este usuário de sua organização desativará permanentemente sua conta. Essa ação não pode ser desfeita. Você quer prosseguir?" @@ -2584,7 +2593,7 @@ } }, "deactivatedUserId": { - "message": "Deactivated user $ID$.", + "message": "Usuário $ID$ desativado.", "placeholders": { "id": { "content": "$1", @@ -2593,7 +2602,7 @@ } }, "activatedUserId": { - "message": "Activated user $ID$.", + "message": "Usuário $ID$ ativado.", "placeholders": { "id": { "content": "$1", @@ -2602,7 +2611,7 @@ } }, "deactivateUserId": { - "message": "Deactivate user $ID$?", + "message": "Desativar o usuário $ID$?", "placeholders": { "id": { "content": "$1", @@ -2611,7 +2620,7 @@ } }, "activateUserId": { - "message": "Activate user $ID$?", + "message": "Ativar o usuário $ID$?", "placeholders": { "id": { "content": "$1", @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "Ao marcar esta caixa, você concorda com o seguinte:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Os Termos de Serviço e a Política de Privacidade não foram reconhecidos." }, "termsOfService": { @@ -3667,7 +3676,7 @@ "message": "Desativado" }, "deactivated": { - "message": "Deactivated" + "message": "Desativado" }, "sendLink": { "message": "Link do Send", @@ -4307,10 +4316,10 @@ "message": "Removido com sucesso" }, "bulkDeactivatedMessage": { - "message": "Deactivated successfully" + "message": "Desativado com sucesso" }, "bulkActivatedMessage": { - "message": "Activated successfully" + "message": "Ativado com sucesso" }, "bulkFilteredMessage": { "message": "Excluído, não aplicável para esta ação." @@ -4322,10 +4331,10 @@ "message": "Remover Usuários" }, "deactivateUsers": { - "message": "Deactivate Users" + "message": "Desativar Usuários" }, "activateUsers": { - "message": "Activate Users" + "message": "Ativar usuários" }, "error": { "message": "Erro" @@ -4501,10 +4510,10 @@ "message": "O tempo limite do seu cofre excede a restrição definida por sua organização." }, "vaultCustomTimeoutMinimum": { - "message": "Minimum custom timeout is 1 minute." + "message": "Tempo limite mínimo personalizado é 1 minuto." }, "vaultTimeoutRangeError": { - "message": "Vault Timeout is not within allowed range." + "message": "Tempo limite do cofre não está dentro do intervalo permitido." }, "disablePersonalVaultExport": { "message": "Desabilitar Exportação de Cofre Pessoal" @@ -4624,7 +4633,7 @@ "message": "Permitir Retorno de Autenticação Não Solicitada" }, "idpAllowOutboundLogoutRequests": { - "message": "Allow outbound logout requests" + "message": "Permitir pedidos de saída" }, "idpSignAuthenticationRequests": { "message": "Assinar pedidos de autenticação" @@ -4750,7 +4759,7 @@ "message": "Patrocínio Removido" }, "ssoKeyConnectorError": { - "message": "Key Connector error: make sure Key Connector is available and working correctly." + "message": "Erro de Key Connector: certifique-se de que a Key Connector está disponível e funcionando corretamente." }, "keyConnectorUrl": { "message": "URL de Conector de Chave" @@ -4879,25 +4888,25 @@ "message": "GRÁTIS com patrocínio" }, "viewBillingSyncToken": { - "message": "View Billing Sync Token" + "message": "Ver Token de Faturamento Sync" }, "generateBillingSyncToken": { - "message": "Generate Billing Sync Token" + "message": "Gerar token de faturamento Sync" }, "copyPasteBillingSync": { - "message": "Copy and paste this token into the Billing Sync settings of your self-hosted organization." + "message": "Copie e cole esse token nas configurações de Faturamento Sync da sua organização auto-hospedada." }, "billingSyncCanAccess": { - "message": "Your Billing Sync token can access and edit this organization's subscription settings." + "message": "Seu token de faturamento Sync pode acessar e editar as configurações de assinatura desta organização." }, "manageBillingSync": { - "message": "Manage Billing Sync" + "message": "Gerenciar sincronização de faturamento" }, "setUpBillingSync": { - "message": "Set Up Billing Sync" + "message": "Configurar sincronização de faturamento" }, "generateToken": { - "message": "Generate Token" + "message": "Gerar o token" }, "rotateToken": { "message": "Rotate Token" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/pt_PT/messages.json b/apps/web/src/locales/pt_PT/messages.json index b7069e5327c..7c57caee738 100644 --- a/apps/web/src/locales/pt_PT/messages.json +++ b/apps/web/src/locales/pt_PT/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Criar conta" }, + "startTrial": { + "message": "Iniciar avaliação" + }, "logIn": { "message": "Iniciar sessão" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "A palavra-passe mestra é a palavra-passe que utiliza para aceder ao seu cofre. É muito importante que não se esqueça da sua palavra-passe mestra. Não existe maneira de recuperar a palavra-passe no caso de a esquecer." }, + "masterPassImportant": { + "message": "Senhas mestres não podem ser recuperadas se as esquecer!" + }, "masterPassHintDesc": { "message": "Uma dica da palavra-passe mestra pode ajudar a lembrar-se da sua palavra-passe se a esquecer." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Endereço de email inválido." }, - "masterPassRequired": { - "message": "A palavra-passe mestra é requerida." + "masterPasswordRequired": { + "message": "A senha mestra é obrigatória." }, - "masterPassLength": { - "message": "A palavra-passe mestra tem de ter pelo menos 8 caracteres." + "confirmMasterPasswordRequired": { + "message": "É necessário redigitar a senha mestra." + }, + "masterPasswordMinLength": { + "message": "A senha mestra deve ter pelo menos 8 caracteres." }, "masterPassDoesntMatch": { "message": "A confirmação da palavra-passe mestra não corresponde." @@ -1076,7 +1085,7 @@ "message": "Conta eliminada" }, "accountDeletedDesc": { - "message": "A sua conta foi encerrada e todos os dados associados foram eliminados." + "message": "A sua conta foi encerrada e todos os dados associados eliminados." }, "myAccount": { "message": "Minha conta" @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { - "message": "Terms of Service and Privacy Policy have not been acknowledged." + "acceptPoliciesRequired": { + "message": "Os Termos de Serviço e a Política de Privacidade não foram reconhecidos." }, "termsOfService": { "message": "Termos de serviço" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Entrada necessária." + }, + "inputEmail": { + "message": "A entrada não é um endereço de e-mail." + }, + "inputMinLength": { + "message": "A entrada deve ter pelo menos $COUNT$ caracteres.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ campos(s) acima precisam da sua atenção.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/ro/messages.json b/apps/web/src/locales/ro/messages.json index 74444e8ed85..e6c58a41c95 100644 --- a/apps/web/src/locales/ro/messages.json +++ b/apps/web/src/locales/ro/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Creare cont" }, + "startTrial": { + "message": "Începeți o încercare" + }, "logIn": { "message": "Conectare" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Parola principală este parola pe care o utilizați pentru a vă accesa seiful. Este foarte important să nu uitați această parolă. Nu există nicio modalitate de a recupera parola în cazul în care ați uitat-o." }, + "masterPassImportant": { + "message": "Parolele principale nu pot fi recuperate dacă le uitați!" + }, "masterPassHintDesc": { "message": "Un indiciu pentru parola principală vă poate ajuta să v-o reamintiți dacă o uitați." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Adresă de e-mail greșită." }, - "masterPassRequired": { - "message": "Este necesară parola principală." + "masterPasswordRequired": { + "message": "Este necesară o parolă principală." }, - "masterPassLength": { - "message": "Parola principală trebuie să conțină minimum 8 caractere." + "confirmMasterPasswordRequired": { + "message": "Este necesară rescrierea parolei principale." + }, + "masterPasswordMinLength": { + "message": "Parola principală trebuie să aibă cel puțin 8 caractere." }, "masterPassDoesntMatch": { "message": "Parola principală și confirmarea ei nu coincid!" @@ -1076,7 +1085,7 @@ "message": "Contul a fost șters" }, "accountDeletedDesc": { - "message": "Contul dvs. a fost închis și toate datele asociate au fost șterse." + "message": "Contul dvs. Bitwarden și datele din seif au fost șterse definitiv." }, "myAccount": { "message": "Contul meu" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "Dacă bifați această casetă sunteți de acord cu următoarele:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Termeni de utilizare și Politica de confidențialitate nu au fost recunoscute." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Este necesară o intrare." + }, + "inputEmail": { + "message": "Intrarea nu este o adresă de e-mail." + }, + "inputMinLength": { + "message": "Intrarea trebuie să aibă o lungime de cel puțin $COUNT$ caractere.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ câmp/câmpuri de mai sus necesită atenția dumneavoastră.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/ru/messages.json b/apps/web/src/locales/ru/messages.json index 6dba7fdde01..e2706b03c6b 100644 --- a/apps/web/src/locales/ru/messages.json +++ b/apps/web/src/locales/ru/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Создать аккаунт" }, + "startTrial": { + "message": "Начать пробный период" + }, "logIn": { "message": "Войти" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Мастер-пароль – это ключ к вашему защищенному хранилищу. Он очень важен, поэтому не забывайте его. Восстановить мастер-пароль невозможно." }, + "masterPassImportant": { + "message": "Мастер-пароли невозможно восстановить, если вы их забудете!" + }, "masterPassHintDesc": { "message": "Подсказка к мастер-паролю может помочь вам его вспомнить." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Неверный адрес email." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Требуется мастер-пароль." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Необходимо ввести мастер-пароль повторно." + }, + "masterPasswordMinLength": { "message": "Мастер-пароль должен содержать не менее 8 символов." }, "masterPassDoesntMatch": { @@ -1076,7 +1085,7 @@ "message": "Аккаунт удален" }, "accountDeletedDesc": { - "message": "Ваша учетная запись была закрыта и все связанные с ней данные были удалены." + "message": "Ваш аккаунт был закрыт, а все связанные с ним данные удалены." }, "myAccount": { "message": "Мой аккаунт" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "Отметив этот флажок, вы соглашаетесь со следующим:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Условия предоставления услуг и Политика конфиденциальности не были подтверждены." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Требуются вводные данные." + }, + "inputEmail": { + "message": "Вводные данные — не адрес эл. почты." + }, + "inputMinLength": { + "message": "Вводимые данные должны содежать не менее $COUNT$ символов.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ поля(ей) выше требуют вашего внимания.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/si/messages.json b/apps/web/src/locales/si/messages.json index c92172b87ef..baf0b657611 100644 --- a/apps/web/src/locales/si/messages.json +++ b/apps/web/src/locales/si/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "ගිණුමක් සාදන්න" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "පිවිසෙන්න" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "A master password hint can help you remember your password if you forget it." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -1076,7 +1085,7 @@ "message": "Account Deleted" }, "accountDeletedDesc": { - "message": "Your account has been closed and all associated data has been deleted." + "message": "Your Bitwarden account and vault data were permanently deleted." }, "myAccount": { "message": "My Account" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/sk/messages.json b/apps/web/src/locales/sk/messages.json index 7eb9dab56f5..92204252a7f 100644 --- a/apps/web/src/locales/sk/messages.json +++ b/apps/web/src/locales/sk/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Vytvoriť účet" }, + "startTrial": { + "message": "Začať skúšobné obdobie" + }, "logIn": { "message": "Prihlásiť sa" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Hlavné heslo je heslo, ktoré použijete na prístup k svojmu trezoru. Je veľmi dôležité, aby ste svoje hlavné heslo nezabudli. Neexistuje možnosť, ako heslo obnoviť v prípade, že ho zabudnete." }, + "masterPassImportant": { + "message": "Hlavné heslo sa nedá obnoviť, ak ho zabudnete!" + }, "masterPassHintDesc": { "message": "Nápoveď k hlavnému heslu vám môže pomôcť spomenúť si na heslo, ak ho zabudnete." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Neplatná emailová adresa." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Hlavné heslo je povinné." }, - "masterPassLength": { - "message": "Hlavné heslo musí obsahovať aspoň 8 znakov." + "confirmMasterPasswordRequired": { + "message": "Vyžaduje sa opätovné zadanie hlavného hesla." + }, + "masterPasswordMinLength": { + "message": "Hlavné heslo musí mať aspoň 8 znakov." }, "masterPassDoesntMatch": { "message": "Potvrdenie hlavného hesla sa nezhoduje." @@ -1076,7 +1085,7 @@ "message": "Účet bol odstránený" }, "accountDeletedDesc": { - "message": "Váš účet bol uzavretý a všetky súvisiace dáta vymazané." + "message": "Váš účet a dáta z trezora boli trvalo vymazané." }, "myAccount": { "message": "Môj účet" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "Označením tohto políčka súhlasíte s nasledovným:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Neboli akceptované Podmienky používania a zásady Ochrany osobných údajov." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Vstup je povinný." + }, + "inputEmail": { + "message": "Vstupom nie je e-mailová adresa." + }, + "inputMinLength": { + "message": "Vstup musí mať aspoň $COUNT$ znakov.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "Niektoré polia ($COUNT$) vyžadujú vašu pozornosť.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/sl/messages.json b/apps/web/src/locales/sl/messages.json index d69a433ac01..06c75c27e7e 100644 --- a/apps/web/src/locales/sl/messages.json +++ b/apps/web/src/locales/sl/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Ustvari račun" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Prijava" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Glavno geslo je geslo, ki ga uporabljate za dostop do vašega trezorja. Zelo pomembno je, da ne pozabite vaše glavno geslo. Gesla ni mogoče obnoviti v primeru, če ga pozabite." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "Namig glavnega gesla vam lahko pomaga, da se spomnite vašega gesla, če ga pozabite." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Neveljaven e-poštni naslov." }, - "masterPassRequired": { - "message": "Glavno geslo je obvezno." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Glavno geslo mora biti dolgo najmanj 8 znakov." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Potrditev glavnega gesla se ne ujema." @@ -1076,7 +1085,7 @@ "message": "Account Deleted" }, "accountDeletedDesc": { - "message": "Your account has been closed and all associated data has been deleted." + "message": "Your Bitwarden account and vault data were permanently deleted." }, "myAccount": { "message": "Moj račun" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/sr/messages.json b/apps/web/src/locales/sr/messages.json index ce5d110eb00..e9cd0d6e0c8 100644 --- a/apps/web/src/locales/sr/messages.json +++ b/apps/web/src/locales/sr/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Креирај налог" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Пријавите се" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Главна Лозинка је лозинка коју користите за приступ Вашем сефу. Врло је важно да је не заборавите. Не постоји начин да повратите лозинку у случају да је заборавите." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "Савет Главне Лозинке може да Вам помогне да се је потсетите ако је заборавите." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Неисправан имејл." }, - "masterPassRequired": { - "message": "Главна Лозинка је неопходна." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Главна Лозинка треба имати бар 8 знака." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Потврђена Главна Лозинка се не подудара." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Означавањем овог поља пристајете на следеће:" }, - "acceptPoliciesError": { - "message": "Услови услуге и Политика приватности нису признати." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Услови коришћења услуге" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/sr_CS/messages.json b/apps/web/src/locales/sr_CS/messages.json index 390bc5acf7c..47a1214819a 100644 --- a/apps/web/src/locales/sr_CS/messages.json +++ b/apps/web/src/locales/sr_CS/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Napravi Nalog" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Prijavi Se" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Glavna šifra je šifra koju koristite kako biste pristupili svom trezoru. Veoma je važno da ne zaboravite svoju glavnu šifru. Ukoliko je zaboravite, ne postoji način da je dobijete nazad." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "A master password hint can help you remember your password if you forget it." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Invalid email address." }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "Master password is required." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/sv/messages.json b/apps/web/src/locales/sv/messages.json index c2b1f6a1719..6433df1d5b4 100644 --- a/apps/web/src/locales/sv/messages.json +++ b/apps/web/src/locales/sv/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Skapa konto" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Logga in" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Huvudlösenordet är det lösenord som du använder för att komma åt ditt valv. Det är väldigt viktigt att du inte glömmer bort ditt huvudlösenord, eftersom det inte går att återställa lösenordet ifall du skulle glömma bort det." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "En huvudlösenordsledtråd kan hjälpa dig att komma ihåg ditt lösenord om du glömmer bort det." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Ogiltig e-postadress." }, - "masterPassRequired": { - "message": "Huvudlösenord krävs." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Huvudlösenordet måste vara minst 8 tecken långt." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Huvudlösenorden stämmer inte överens." @@ -1239,7 +1248,7 @@ "message": "Aktiverad" }, "activate": { - "message": "Activate" + "message": "Aktivera" }, "premium": { "message": "Premium", @@ -1267,7 +1276,7 @@ "message": "Inaktivera" }, "deactivate": { - "message": "Deactivate" + "message": "Inaktivera" }, "twoStepLoginProviderEnabled": { "message": "Denna metod för tvåstegsverifiering är aktiverad på ditt konto." @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Genom att markera denna ruta godkänner du följande:" }, - "acceptPoliciesError": { - "message": "Användarvillkoren och Integritetspolicyn har inte accepterats." + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { "message": "Användarvillkor" @@ -4322,10 +4331,10 @@ "message": "Ta bort användare" }, "deactivateUsers": { - "message": "Deactivate Users" + "message": "Inaktivera användare" }, "activateUsers": { - "message": "Activate Users" + "message": "Aktivera användare" }, "error": { "message": "Fel" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/tr/messages.json b/apps/web/src/locales/tr/messages.json index c299e7216ab..0ef7c75c2cc 100644 --- a/apps/web/src/locales/tr/messages.json +++ b/apps/web/src/locales/tr/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Hesap aç" }, + "startTrial": { + "message": "Denemeyi başlat" + }, "logIn": { "message": "Giriş yap" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Ana parola, kasanıza ulaşmak için kullanacağınız paroladır. Ana parolanızı unutmamanız çok önemlidir. Unutursanız parolalarınızı asla kurtaramazsınız." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "Ana parolanızı unutursanız bu ipucuna bakınca size ana parolanızı hatırlatacak bir şey yazabilirsiniz." }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "Geçersiz e-posta adresi." }, - "masterPassRequired": { - "message": "Ana parola gerekli." + "masterPasswordRequired": { + "message": "Ana parola gereklidir." }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "Ana parolayı yeniden yazmalısınız." + }, + "masterPasswordMinLength": { "message": "Ana parola en az 8 karakter uzunluğunda olmalıdır." }, "masterPassDoesntMatch": { @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "Bu kutuyu işaretleyerek aşağıdakileri kabul etmiş olursunuz:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Hizmet Koşulları ve Gizlilik Politikası kabul edilmemiş." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Girdi gerekli." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/uk/messages.json b/apps/web/src/locales/uk/messages.json index 2ca96f92132..385fd8e2753 100644 --- a/apps/web/src/locales/uk/messages.json +++ b/apps/web/src/locales/uk/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Створити обліковий запис" }, + "startTrial": { + "message": "Почати пробний період" + }, "logIn": { "message": "Увійти" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Головний пароль використовується для доступу до вашого сховища. Дуже важливо, щоб ви запам'ятали його. Якщо ви забудете головний пароль, його неможливо буде відновити." }, + "masterPassImportant": { + "message": "Головний пароль неможливо відновити, якщо ви забудете його!" + }, "masterPassHintDesc": { "message": "Якщо ви забудете головний пароль, підказка може допомогти вам згадати його." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Неправильна адреса е-пошти." }, - "masterPassRequired": { - "message": "Потрібен головний пароль." + "masterPasswordRequired": { + "message": "Необхідно ввести головний пароль." }, - "masterPassLength": { - "message": "Довжина головного пароля повинна бути не менше 8 символів." + "confirmMasterPasswordRequired": { + "message": "Необхідно повторно ввести головний пароль." + }, + "masterPasswordMinLength": { + "message": "Довжина головного пароля має бути принаймні 8 символів." }, "masterPassDoesntMatch": { "message": "Підтвердження головного пароля не збігається." @@ -864,7 +873,7 @@ "message": "Експортовані дані вашого сховища знаходяться в незашифрованому вигляді. Вам не слід зберігати чи надсилати їх через незахищені канали (наприклад, е-поштою). Після використання негайно видаліть їх." }, "encExportKeyWarningDesc": { - "message": "Цей експорт шифрує ваші дані за допомогою ключа шифрування облікового запису. Якщо ви коли-небудь оновите ключ шифрування облікового запису, ви повинні виконати експорт знову, оскільки не зможете розшифрувати цей файл експорту." + "message": "Цей експорт шифрує ваші дані за допомогою ключа шифрування облікового запису. Якщо ви коли-небудь оновите ключ шифрування облікового запису, необхідно виконати експорт знову, оскільки не зможете розшифрувати цей файл експорту." }, "encExportAccountWarningDesc": { "message": "Ключі шифрування унікальні для кожного облікового запису користувача Bitwarden, тому ви не можете імпортувати зашифрований експорт до іншого облікового запису." @@ -1494,7 +1503,7 @@ "message": "Неактивна двоетапна перевірка" }, "inactive2faReportDesc": { - "message": "Двоетапна перевірка надає додатковий рівень захисту для ваших облікових записів. Увімкніть двоетапнуперевірку з використанням вбудованих засобів Bitwarden для цих облікових записів, або скористайтеся альтернативним способом." + "message": "Двоетапна перевірка забезпечує додатковий рівень захисту для ваших облікових записів. Увімкніть двоетапну перевірку з використанням вбудованих засобів Bitwarden для цих облікових записів, або скористайтеся альтернативним способом." }, "inactive2faFound": { "message": "Знайдено записи без двоетапної перевірки" @@ -2320,7 +2329,7 @@ "message": "Користувач з найвищими привілеями, який може керувати всіма налаштуваннями організації." }, "clientOwnerDesc": { - "message": "Цей користувач повинен бути незалежним від постачальника. Якщо постачальник не пов'язаний з організацією, цей користувач підтримуватиме право власності організації." + "message": "Цей користувач має бути незалежним від постачальника. Якщо постачальник не пов'язаний з організацією, цей користувач підтримуватиме право власності організації." }, "admin": { "message": "Адміністратор" @@ -3159,8 +3168,8 @@ "acceptPolicies": { "message": "Позначивши цей прапорець, ви погоджуєтеся з:" }, - "acceptPoliciesError": { - "message": "Умови користування та політика приватності не погоджені." + "acceptPoliciesRequired": { + "message": "Ви не погодилися з умовами користування та політикою приватності." }, "termsOfService": { "message": "Умови користування" @@ -3294,7 +3303,7 @@ "message": "Поворот ключа API спричинить анулювання попереднього ключа. Ви можете повернути свій ключ API, якщо вважаєте, що поточний ключ більше не є безпечним для використання." }, "apiKeyWarning": { - "message": "Ваш ключ API має повний доступ до організації. Він повинен зберігатися в секреті." + "message": "Ваш ключ API має повний доступ до організації. Його необхідно надійно зберігати." }, "userApiKeyDesc": { "message": "Ваш ключ API може бути використаний для авторизації в Bitwarden CLI." @@ -3313,7 +3322,7 @@ "message": "Повернути ключ API" }, "selectOneCollection": { - "message": "Ви повинні обрати принаймні одну збірку." + "message": "Необхідно вибрати принаймні одну збірку." }, "couldNotChargeCardPayInvoice": { "message": "Нам не вдалося виконати оплату з вашої картки. Будь ласка, перегляньте і проведіть оплату за рахунком, вказаним внизу." @@ -3325,7 +3334,7 @@ "message": "Ви не можете виконати цю дію під час використання способу оплати покупки в додатку." }, "manageSubscriptionFromStore": { - "message": "Ви повинні керувати своєю передплатою з магазину, в якому виконали покупку в додатку." + "message": "Керувати своєю передплатою потрібно з магазину, в якому ви виконали покупку в додатку." }, "minLength": { "message": "Мінімальна довжина" @@ -4004,7 +4013,7 @@ "message": "Керувати скиданням пароля" }, "disableRequiredError": { - "message": "Перш ніж вимкнути цю політику, ви повинні вручну вимкнути політику $POLICYNAME$.", + "message": "Перш ніж вимкнути цю політику, вам необхідно вручну вимкнути політику $POLICYNAME$.", "placeholders": { "policyName": { "content": "$1", @@ -4223,7 +4232,7 @@ "message": "Дозволити адміністраторам організації скидати головний пароль користувачів." }, "resetPasswordPolicyWarning": { - "message": "Користувачі в організації повинні виконати самостійне розгортання, або отримати автоматичне розгортання, перш ніж адміністратори зможуть скинути їхній пароль." + "message": "Користувачі в організації мають виконати самостійне розгортання, або отримати автоматичне розгортання, перш ніж адміністратори зможуть скинути їхній пароль." }, "resetPasswordPolicyAutoEnroll": { "message": "Автоматичне розгортання" @@ -4331,7 +4340,7 @@ "message": "Помилка" }, "resetPasswordManageUsers": { - "message": "Керування користувачами повинно також бути увімкнено з дозволом Керувати скиданням пароля" + "message": "Керування користувачами має також бути увімкнено з дозволом Керувати скиданням пароля" }, "setupProvider": { "message": "Налаштування постачальника" @@ -4458,10 +4467,10 @@ "message": "Оновити головний пароль" }, "updateMasterPasswordWarning": { - "message": "Ваш головний пароль нещодавно був змінений адміністратором організації. Щоб отримати доступ до сховища, ви повинні оновити свій головний пароль зараз. Продовживши, ви вийдете з поточного сеансу, після чого необхідно буде повторно виконати вхід. Сеанси на інших пристроях можуть залишатися активними протягом однієї години." + "message": "Ваш головний пароль нещодавно був змінений адміністратором організації. Щоб отримати доступ до сховища, вам необхідно оновити свій головний пароль зараз. Продовживши, ви вийдете з поточного сеансу, після чого потрібно буде повторно виконати вхід. Сеанси на інших пристроях можуть залишатися активними протягом однієї години." }, "masterPasswordInvalidWarning": { - "message": "Ваш головний пароль не відповідає вимогам політики цієї організації. Щоб приєднатися до організації, ви повинні оновити свій головний пароль зараз. Продовживши, ви вийдете з поточного сеансу, після чого необхідно буде повторно виконати вхід. Сеанси на інших пристроях можуть залишатися активними протягом однієї години." + "message": "Ваш головний пароль не відповідає вимогам політики цієї організації. Щоб приєднатися до організації, необхідно оновити свій головний пароль зараз. Продовживши, ви вийдете з поточного сеансу, після чого потрібно буде повторно виконати вхід. Сеанси на інших пристроях можуть залишатися активними протягом однієї години." }, "maximumVaultTimeout": { "message": "Час очікування сховища" @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Необхідно ввести дані." + }, + "inputEmail": { + "message": "Введені дані не є адресою е-пошти." + }, + "inputMinLength": { + "message": "Введені дані мають бути довжиною принаймні $COUNT$ символів.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ поле (поля) вище потребують вашої уваги.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/vi/messages.json b/apps/web/src/locales/vi/messages.json index be946bbb524..9fc6178a9ab 100644 --- a/apps/web/src/locales/vi/messages.json +++ b/apps/web/src/locales/vi/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "Tạo tài khoản" }, + "startTrial": { + "message": "Start Trial" + }, "logIn": { "message": "Đăng nhập" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "Mật khẩu chính là mật khẩu cho kho mật khẩu của bạn. Mật khẩu này rất quan trọng và bạn không nên quên nó của mình. Bạn sẽ không thể khôi phục lại mật khẩu chính của bạn nếu bạn quên nó." }, + "masterPassImportant": { + "message": "Master passwords cannot be recovered if you forget it!" + }, "masterPassHintDesc": { "message": "Gợi ý mật khẩu có thể giúp bạn nhớ lại mật khẩu chính của mình nếu bạn quên nó." }, @@ -623,11 +629,14 @@ "invalidEmail": { "message": "Địa chỉ email không hợp lệ." }, - "masterPassRequired": { - "message": "Cần phải có mật khẩu chính." + "masterPasswordRequired": { + "message": "Master password is required." }, - "masterPassLength": { - "message": "Mật khẩu chính phải có ít nhất 8 kí tự." + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinLength": { + "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { "message": "Xác minh mật khẩu chính không đúng." @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "By checking this box you agree to the following:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "Input is required." + }, + "inputEmail": { + "message": "Input is not an email-address." + }, + "inputMinLength": { + "message": "Input must be at least $COUNT$ characters long.", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "$COUNT$ field(s) above need your attention.", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/zh_CN/messages.json b/apps/web/src/locales/zh_CN/messages.json index 5ef2219034c..aafc7456306 100644 --- a/apps/web/src/locales/zh_CN/messages.json +++ b/apps/web/src/locales/zh_CN/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "创建账户" }, + "startTrial": { + "message": "开始试用" + }, "logIn": { "message": "登录" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "主密码是您访问密码库的密码。它非常重要,请您不要忘记。一旦忘记,无任何办法恢复此密码。" }, + "masterPassImportant": { + "message": "主密码忘记后,将无法恢复!" + }, "masterPassHintDesc": { "message": "主密码提示可以在你忘记密码时帮你回忆起来。" }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "无效的电子邮件地址。" }, - "masterPassRequired": { + "masterPasswordRequired": { "message": "必须填写主密码。" }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "必须填写确认主密码。" + }, + "masterPasswordMinLength": { "message": "主密码至少需要 8 个字符。" }, "masterPassDoesntMatch": { @@ -645,7 +654,7 @@ "message": "电子邮件地址" }, "yourVaultIsLocked": { - "message": "您的密码库已被锁定,请验证您的主密码以继续。" + "message": "您的密码库已锁定,请验证您的主密码以继续。" }, "unlock": { "message": "解锁​​​​" @@ -1076,7 +1085,7 @@ "message": "账户已删除" }, "accountDeletedDesc": { - "message": "您的账户已关闭,所有相关数据也已被删除。" + "message": "您的 Bitwarden 账户和密码库数据已被永久删除。" }, "myAccount": { "message": "我的账户" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "选中此框表示您同意:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "尚未同意服务条款和隐私政策。" }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "必须输入内容。" + }, + "inputEmail": { + "message": "输入的不是电子邮件地址。" + }, + "inputMinLength": { + "message": "至少输入 $COUNT$ 个字符。", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "上面的 $COUNT$ 个字段需要您注意。", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } diff --git a/apps/web/src/locales/zh_TW/messages.json b/apps/web/src/locales/zh_TW/messages.json index 3761fec001f..3022f413eb6 100644 --- a/apps/web/src/locales/zh_TW/messages.json +++ b/apps/web/src/locales/zh_TW/messages.json @@ -572,6 +572,9 @@ "createAccount": { "message": "建立帳戶" }, + "startTrial": { + "message": "立即試用" + }, "logIn": { "message": "登入" }, @@ -593,6 +596,9 @@ "masterPassDesc": { "message": "主密碼是用於存取密碼庫的密碼。它非常重要,請您不要忘記它。若您忘記了主密碼,沒有任何方法能將其復原。" }, + "masterPassImportant": { + "message": "如果您忘記主密碼,沒有復原的方法!" + }, "masterPassHintDesc": { "message": "主密碼提示可以在您忘記主密碼時幫助您回憶主密碼。" }, @@ -623,10 +629,13 @@ "invalidEmail": { "message": "無效的電子郵件地址。" }, - "masterPassRequired": { - "message": "必須填入主密碼。" + "masterPasswordRequired": { + "message": "必須填寫主密碼。" }, - "masterPassLength": { + "confirmMasterPasswordRequired": { + "message": "必須再次輸入主密碼。" + }, + "masterPasswordMinLength": { "message": "主密碼需要至少 8 個字元。" }, "masterPassDoesntMatch": { @@ -1076,7 +1085,7 @@ "message": "已刪除帳戶" }, "accountDeletedDesc": { - "message": "您的帳戶已經關閉,所有關聯的資料已經被刪除。" + "message": "您的 Bitwarden 帳戶和密碼庫資料已被永久刪除。" }, "myAccount": { "message": "我的帳戶" @@ -3159,7 +3168,7 @@ "acceptPolicies": { "message": "一旦核取此方塊,即表示您同意下列條款:" }, - "acceptPoliciesError": { + "acceptPoliciesRequired": { "message": "尚未接受服務條款與隱私權政策。" }, "termsOfService": { @@ -5165,5 +5174,29 @@ "example": "My Email" } } + }, + "inputRequired": { + "message": "必須輸入內容。" + }, + "inputEmail": { + "message": "輸入的不是電子郵件地址。" + }, + "inputMinLength": { + "message": "必須輸入至少 $COUNT$ 個字元。", + "placeholders": { + "count": { + "content": "$1", + "example": "8" + } + } + }, + "fieldsNeedAttention": { + "message": "您需注意上方的 $COUNT$ 個欄位。", + "placeholders": { + "count": { + "content": "$1", + "example": "4" + } + } } } From ce2606b406882435448b07024f06cef246d980f5 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Fri, 8 Jul 2022 10:18:07 +0200 Subject: [PATCH 21/86] [EC-267] Unassigned collection has disappeared in web vault (#3000) * feat: add unassigned collection to decrypted collections * feat: add support for unassigned in individual vault * fix: dont activate collection when not selected * fix: remove collection selection completely when pruning * feat: prune collection selection if selecting my vault * fix: filter and only show organization ciphers when unassigned collection is selected * fix: only show unassigned for admins * feat: add unassigned logic to organizational vault buildFilter * refactor: move buildFilter to VaultFilterModel * chore: add buildFilter tests * fix: bugs in filtering logic * refactor: use VaultFilter.buildFilter on desktop * chore: group and reword tests for better readability * feat: add additional test * fix: connect unassigned collection to organization * fix: test by adding missing * chore: tweak test group naming * fix: change undefined to null to better reflect real values --- apps/desktop/src/app/vault/vault.component.ts | 43 +--- .../collection-filter.component.html | 2 +- .../vault-filter/vault-filter.service.ts | 7 + .../individual-vault.component.ts | 39 +-- .../organization-vault.component.ts | 39 +-- .../src/app/modules/vault/vault.service.ts | 2 +- .../components/collection-filter.component.ts | 1 + .../models/vault-filter.model.spec.ts | 237 ++++++++++++++++++ .../vault-filter/models/vault-filter.model.ts | 42 ++++ .../vault-filter/vault-filter.component.ts | 7 +- .../common/src/services/collection.service.ts | 1 + 11 files changed, 309 insertions(+), 111 deletions(-) create mode 100644 libs/angular/src/modules/vault-filter/models/vault-filter.model.spec.ts diff --git a/apps/desktop/src/app/vault/vault.component.ts b/apps/desktop/src/app/vault/vault.component.ts index 70d19b2b6e5..ea454c1cc20 100644 --- a/apps/desktop/src/app/vault/vault.component.ts +++ b/apps/desktop/src/app/vault/vault.component.ts @@ -128,7 +128,7 @@ export class VaultComponent implements OnInit, OnDestroy { await this.openGenerator(false); break; case "syncCompleted": - await this.ciphersComponent.reload(this.buildFilter()); + await this.ciphersComponent.reload(this.activeFilter.buildFilter()); await this.vaultFilterComponent.reloadCollectionsAndFolders(this.activeFilter); await this.vaultFilterComponent.reloadOrganizations(); break; @@ -241,7 +241,7 @@ export class VaultComponent implements OnInit, OnDestroy { selectedOrganizationId: params.selectedOrganizationId, myVaultOnly: params.myVaultOnly ?? false, }); - await this.ciphersComponent.reload(this.buildFilter()); + await this.ciphersComponent.reload(this.activeFilter.buildFilter()); }); } @@ -540,7 +540,10 @@ export class VaultComponent implements OnInit, OnDestroy { this.i18nService.t(this.calculateSearchBarLocalizationString(vaultFilter)) ); this.activeFilter = vaultFilter; - await this.ciphersComponent.reload(this.buildFilter(), vaultFilter.status === "trash"); + await this.ciphersComponent.reload( + this.activeFilter.buildFilter(), + vaultFilter.status === "trash" + ); this.go(); } @@ -570,40 +573,6 @@ export class VaultComponent implements OnInit, OnDestroy { return "searchVault"; } - private buildFilter(): (cipher: CipherView) => boolean { - return (cipher) => { - let cipherPassesFilter = true; - if (this.activeFilter.status === "favorites" && cipherPassesFilter) { - cipherPassesFilter = cipher.favorite; - } - if (this.activeFilter.status === "trash" && cipherPassesFilter) { - cipherPassesFilter = cipher.isDeleted; - } - if (this.activeFilter.cipherType != null && cipherPassesFilter) { - cipherPassesFilter = cipher.type === this.activeFilter.cipherType; - } - if ( - this.activeFilter.selectedFolder && - this.activeFilter.selectedFolderId != "none" && - cipherPassesFilter - ) { - cipherPassesFilter = cipher.folderId === this.activeFilter.selectedFolderId; - } - if (this.activeFilter.selectedCollectionId != null && cipherPassesFilter) { - cipherPassesFilter = - cipher.collectionIds != null && - cipher.collectionIds.indexOf(this.activeFilter.selectedCollectionId) > -1; - } - if (this.activeFilter.selectedOrganizationId != null && cipherPassesFilter) { - cipherPassesFilter = cipher.organizationId === this.activeFilter.selectedOrganizationId; - } - if (this.activeFilter.myVaultOnly && cipherPassesFilter) { - cipherPassesFilter = cipher.organizationId === null; - } - return cipherPassesFilter; - }; - } - async openGenerator(comingFromAddEdit: boolean, passwordType = true) { if (this.modal != null) { this.modal.close(); diff --git a/apps/web/src/app/modules/vault-filter/components/collection-filter.component.html b/apps/web/src/app/modules/vault-filter/components/collection-filter.component.html index 24463dca19d..417d635bad9 100644 --- a/apps/web/src/app/modules/vault-filter/components/collection-filter.component.html +++ b/apps/web/src/app/modules/vault-filter/components/collection-filter.component.html @@ -23,7 +23,7 @@
  • diff --git a/apps/web/src/app/modules/vault-filter/vault-filter.service.ts b/apps/web/src/app/modules/vault-filter/vault-filter.service.ts index 6e5b13a8469..d85ef3df169 100644 --- a/apps/web/src/app/modules/vault-filter/vault-filter.service.ts +++ b/apps/web/src/app/modules/vault-filter/vault-filter.service.ts @@ -7,6 +7,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; import { PolicyService } from "@bitwarden/common/abstractions/policy.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; @@ -27,6 +28,7 @@ export class VaultFilterService extends BaseVaultFilterService { cipherService: CipherService, collectionService: CollectionService, policyService: PolicyService, + private i18nService: I18nService, protected apiService: ApiService ) { super( @@ -69,6 +71,11 @@ export class VaultFilterService extends BaseVaultFilterService { result = await this.collectionService.decryptMany(collectionDomains); } + const noneCollection = new CollectionView(); + noneCollection.name = this.i18nService.t("unassigned"); + noneCollection.organizationId = organizationId; + result.push(noneCollection); + const nestedCollections = await this.collectionService.getAllNested(result); return new DynamicTreeNode({ fullList: result, diff --git a/apps/web/src/app/modules/vault/modules/individual-vault/individual-vault.component.ts b/apps/web/src/app/modules/vault/modules/individual-vault/individual-vault.component.ts index 7178578da8e..567e390c088 100644 --- a/apps/web/src/app/modules/vault/modules/individual-vault/individual-vault.component.ts +++ b/apps/web/src/app/modules/vault/modules/individual-vault/individual-vault.component.ts @@ -173,7 +173,10 @@ export class IndividualVaultComponent implements OnInit, OnDestroy { async applyVaultFilter(vaultFilter: VaultFilter) { this.ciphersComponent.showAddNew = vaultFilter.status !== "trash"; this.activeFilter = vaultFilter; - await this.ciphersComponent.reload(this.buildFilter(), vaultFilter.status === "trash"); + await this.ciphersComponent.reload( + this.activeFilter.buildFilter(), + vaultFilter.status === "trash" + ); this.filterComponent.searchPlaceholder = this.vaultService.calculateSearchBarLocalizationString( this.activeFilter ); @@ -196,40 +199,6 @@ export class IndividualVaultComponent implements OnInit, OnDestroy { this.ciphersComponent.search(200); } - private buildFilter(): (cipher: CipherView) => boolean { - return (cipher) => { - let cipherPassesFilter = true; - if (this.activeFilter.status === "favorites" && cipherPassesFilter) { - cipherPassesFilter = cipher.favorite; - } - if (this.activeFilter.status === "trash" && cipherPassesFilter) { - cipherPassesFilter = cipher.isDeleted; - } - if (this.activeFilter.cipherType != null && cipherPassesFilter) { - cipherPassesFilter = cipher.type === this.activeFilter.cipherType; - } - if ( - this.activeFilter.selectedFolder && - this.activeFilter.selectedFolderId != "none" && - cipherPassesFilter - ) { - cipherPassesFilter = cipher.folderId === this.activeFilter.selectedFolderId; - } - if (this.activeFilter.selectedCollectionId != null && cipherPassesFilter) { - cipherPassesFilter = - cipher.collectionIds != null && - cipher.collectionIds.indexOf(this.activeFilter.selectedCollectionId) > -1; - } - if (this.activeFilter.selectedOrganizationId != null && cipherPassesFilter) { - cipherPassesFilter = cipher.organizationId === this.activeFilter.selectedOrganizationId; - } - if (this.activeFilter.myVaultOnly && cipherPassesFilter) { - cipherPassesFilter = cipher.organizationId === null; - } - return cipherPassesFilter; - }; - } - async editCipherAttachments(cipher: CipherView) { const canAccessPremium = await this.stateService.getCanAccessPremium(); if (cipher.organizationId == null && !canAccessPremium) { diff --git a/apps/web/src/app/modules/vault/modules/organization-vault/organization-vault.component.ts b/apps/web/src/app/modules/vault/modules/organization-vault/organization-vault.component.ts index 088c1370e74..aaf37e97e4c 100644 --- a/apps/web/src/app/modules/vault/modules/organization-vault/organization-vault.component.ts +++ b/apps/web/src/app/modules/vault/modules/organization-vault/organization-vault.component.ts @@ -162,46 +162,15 @@ export class OrganizationVaultComponent implements OnInit, OnDestroy { async applyVaultFilter(vaultFilter: VaultFilter) { this.ciphersComponent.showAddNew = vaultFilter.status !== "trash"; this.activeFilter = vaultFilter; - await this.ciphersComponent.reload(this.buildFilter(), vaultFilter.status === "trash"); + await this.ciphersComponent.reload( + this.activeFilter.buildFilter(), + vaultFilter.status === "trash" + ); this.vaultFilterComponent.searchPlaceholder = this.vaultService.calculateSearchBarLocalizationString(this.activeFilter); this.go(); } - private buildFilter(): (cipher: CipherView) => boolean { - return (cipher) => { - let cipherPassesFilter = true; - if (this.activeFilter.status === "favorites" && cipherPassesFilter) { - cipherPassesFilter = cipher.favorite; - } - if (this.deleted && cipherPassesFilter) { - cipherPassesFilter = cipher.isDeleted; - } - if (this.activeFilter.cipherType != null && cipherPassesFilter) { - cipherPassesFilter = cipher.type === this.activeFilter.cipherType; - } - if ( - this.activeFilter.selectedFolder != null && - this.activeFilter.selectedFolderId != "none" && - cipherPassesFilter - ) { - cipherPassesFilter = cipher.folderId === this.activeFilter.selectedFolderId; - } - if (this.activeFilter.selectedCollectionId != null && cipherPassesFilter) { - cipherPassesFilter = - cipher.collectionIds != null && - cipher.collectionIds.indexOf(this.activeFilter.selectedCollectionId) > -1; - } - if (this.activeFilter.selectedOrganizationId != null && cipherPassesFilter) { - cipherPassesFilter = cipher.organizationId === this.activeFilter.selectedOrganizationId; - } - if (this.activeFilter.myVaultOnly && cipherPassesFilter) { - cipherPassesFilter = cipher.organizationId === null; - } - return cipherPassesFilter; - }; - } - filterSearchText(searchText: string) { this.ciphersComponent.searchText = searchText; this.ciphersComponent.search(200); diff --git a/apps/web/src/app/modules/vault/vault.service.ts b/apps/web/src/app/modules/vault/vault.service.ts index 4488173b4b3..e792ac736f8 100644 --- a/apps/web/src/app/modules/vault/vault.service.ts +++ b/apps/web/src/app/modules/vault/vault.service.ts @@ -14,7 +14,7 @@ export class VaultService { if (vaultFilter.selectedFolderId != null && vaultFilter.selectedFolderId != "none") { return "searchFolder"; } - if (vaultFilter.selectedCollectionId != null) { + if (vaultFilter.selectedCollection) { return "searchCollection"; } if (vaultFilter.selectedOrganizationId != null) { diff --git a/libs/angular/src/modules/vault-filter/components/collection-filter.component.ts b/libs/angular/src/modules/vault-filter/components/collection-filter.component.ts index ed35390daee..313db3f04c5 100644 --- a/libs/angular/src/modules/vault-filter/components/collection-filter.component.ts +++ b/libs/angular/src/modules/vault-filter/components/collection-filter.component.ts @@ -41,6 +41,7 @@ export class CollectionFilterComponent { applyFilter(collection: CollectionView) { this.activeFilter.resetFilter(); + this.activeFilter.selectedCollection = true; this.activeFilter.selectedCollectionId = collection.id; this.onFilterChange.emit(this.activeFilter); } diff --git a/libs/angular/src/modules/vault-filter/models/vault-filter.model.spec.ts b/libs/angular/src/modules/vault-filter/models/vault-filter.model.spec.ts new file mode 100644 index 00000000000..1c63481ab70 --- /dev/null +++ b/libs/angular/src/modules/vault-filter/models/vault-filter.model.spec.ts @@ -0,0 +1,237 @@ +import { CipherType } from "@bitwarden/common/enums/cipherType"; +import { CipherView } from "@bitwarden/common/models/view/cipherView"; + +import { VaultFilter } from "./vault-filter.model"; + +describe("VaultFilter", () => { + describe("filterFunction", () => { + describe("generic cipher", () => { + it("should return true when not filtering for anything specific", () => { + const cipher = createCipher(); + const filterFunction = createFilterFunction({ status: "all" }); + + const result = filterFunction(cipher); + + expect(result).toBe(true); + }); + }); + + describe("given a favorite cipher", () => { + const cipher = createCipher({ favorite: true }); + + it("should return true when filtering for favorites", () => { + const filterFunction = createFilterFunction({ status: "favorites" }); + + const result = filterFunction(cipher); + + expect(result).toBe(true); + }); + + it("should return false when filtering for trash", () => { + const filterFunction = createFilterFunction({ status: "trash" }); + + const result = filterFunction(cipher); + + expect(result).toBe(false); + }); + }); + + describe("given a deleted cipher", () => { + const cipher = createCipher({ deletedDate: new Date() }); + + it("should return true when filtering for trash", () => { + const filterFunction = createFilterFunction({ status: "trash" }); + + const result = filterFunction(cipher); + + expect(result).toBe(true); + }); + + it("should return false when filtering for favorites", () => { + const filterFunction = createFilterFunction({ status: "favorites" }); + + const result = filterFunction(cipher); + + expect(result).toBe(false); + }); + }); + + describe("given a cipher with type", () => { + it("should return true when filter matches cipher type", () => { + const cipher = createCipher({ type: CipherType.Identity }); + const filterFunction = createFilterFunction({ cipherType: CipherType.Identity }); + + const result = filterFunction(cipher); + + expect(result).toBe(true); + }); + + it("should return false when filter does not match cipher type", () => { + const cipher = createCipher({ type: CipherType.Card }); + const filterFunction = createFilterFunction({ cipherType: CipherType.Identity }); + + const result = filterFunction(cipher); + + expect(result).toBe(false); + }); + }); + + describe("given a cipher with folder id", () => { + it("should return true when filter matches folder id", () => { + const cipher = createCipher({ folderId: "folderId" }); + const filterFunction = createFilterFunction({ + selectedFolder: true, + selectedFolderId: "folderId", + }); + + const result = filterFunction(cipher); + + expect(result).toBe(true); + }); + + it("should return false when filter does not match folder id", () => { + const cipher = createCipher({ folderId: "folderId" }); + const filterFunction = createFilterFunction({ + selectedFolder: true, + selectedFolderId: "anotherFolderId", + }); + + const result = filterFunction(cipher); + + expect(result).toBe(false); + }); + }); + + describe("given a cipher without folder", () => { + const cipher = createCipher({ folderId: null }); + + it("should return true when filtering on unassigned folder", () => { + const filterFunction = createFilterFunction({ + selectedFolder: true, + selectedFolderId: null, + }); + + const result = filterFunction(cipher); + + expect(result).toBe(true); + }); + }); + + describe("given an organizational cipher (with organization and collections)", () => { + const cipher = createCipher({ + organizationId: "organizationId", + collectionIds: ["collectionId", "anotherId"], + }); + + it("should return true when filter matches collection id", () => { + const filterFunction = createFilterFunction({ + selectedCollection: true, + selectedCollectionId: "collectionId", + }); + + const result = filterFunction(cipher); + + expect(result).toBe(true); + }); + + it("should return false when filter does not match collection id", () => { + const filterFunction = createFilterFunction({ + selectedCollection: true, + selectedCollectionId: "nonMatchingId", + }); + + const result = filterFunction(cipher); + + expect(result).toBe(false); + }); + + it("should return false when filter does not match organization id", () => { + const filterFunction = createFilterFunction({ + selectedOrganizationId: "anotherOrganizationId", + }); + + const result = filterFunction(cipher); + + expect(result).toBe(false); + }); + + it("should return false when filtering for my vault only", () => { + const filterFunction = createFilterFunction({ + myVaultOnly: true, + }); + + const result = filterFunction(cipher); + + expect(result).toBe(false); + }); + }); + + describe("given an unassigned organizational cipher (with organization, without collection)", () => { + const cipher = createCipher({ organizationId: "organizationId", collectionIds: [] }); + + it("should return true when filtering for unassigned collection", () => { + const filterFunction = createFilterFunction({ + selectedCollection: true, + selectedCollectionId: null, + }); + + const result = filterFunction(cipher); + + expect(result).toBe(true); + }); + + it("should return true when filter matches organization id", () => { + const filterFunction = createFilterFunction({ + selectedOrganizationId: "organizationId", + }); + + const result = filterFunction(cipher); + + expect(result).toBe(true); + }); + }); + + describe("given an individual cipher (without organization or collection)", () => { + const cipher = createCipher({ organizationId: null, collectionIds: [] }); + + it("should return false when filtering for unassigned collection", () => { + const filterFunction = createFilterFunction({ + selectedCollection: true, + selectedCollectionId: null, + }); + + const result = filterFunction(cipher); + + expect(result).toBe(false); + }); + + it("should return true when filtering for my vault only", () => { + const cipher = createCipher({ organizationId: null }); + const filterFunction = createFilterFunction({ + myVaultOnly: true, + }); + + const result = filterFunction(cipher); + + expect(result).toBe(true); + }); + }); + }); +}); + +function createFilterFunction(options: Partial = {}) { + return new VaultFilter(options).buildFilter(); +} + +function createCipher(options: Partial = {}) { + const cipher = new CipherView(); + + cipher.favorite = options.favorite ?? false; + cipher.deletedDate = options.deletedDate; + cipher.type = options.type; + cipher.folderId = options.folderId; + cipher.collectionIds = options.collectionIds; + cipher.organizationId = options.organizationId; + + return cipher; +} diff --git a/libs/angular/src/modules/vault-filter/models/vault-filter.model.ts b/libs/angular/src/modules/vault-filter/models/vault-filter.model.ts index f28cd20336e..942704f1285 100644 --- a/libs/angular/src/modules/vault-filter/models/vault-filter.model.ts +++ b/libs/angular/src/modules/vault-filter/models/vault-filter.model.ts @@ -1,9 +1,13 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; +import { CipherView } from "@bitwarden/common/models/view/cipherView"; import { CipherStatus } from "./cipher-status.model"; +export type VaultFilterFunction = (cipher: CipherView) => boolean; + export class VaultFilter { cipherType?: CipherType; + selectedCollection = false; // This is needed because of how the "Unassigned" collection works. It has a null id. selectedCollectionId?: string; status?: CipherStatus; selectedFolder = false; // This is needed because of how the "No Folder" folder works. It has a null id. @@ -19,6 +23,7 @@ export class VaultFilter { resetFilter() { this.cipherType = null; this.status = null; + this.selectedCollection = false; this.selectedCollectionId = null; this.selectedFolder = false; this.selectedFolderId = null; @@ -29,4 +34,41 @@ export class VaultFilter { this.selectedOrganizationId = null; this.resetFilter(); } + + buildFilter(): VaultFilterFunction { + return (cipher) => { + let cipherPassesFilter = true; + if (this.status === "favorites" && cipherPassesFilter) { + cipherPassesFilter = cipher.favorite; + } + if (this.status === "trash" && cipherPassesFilter) { + cipherPassesFilter = cipher.isDeleted; + } + if (this.cipherType != null && cipherPassesFilter) { + cipherPassesFilter = cipher.type === this.cipherType; + } + if (this.selectedFolder && this.selectedFolderId == null && cipherPassesFilter) { + cipherPassesFilter = cipher.folderId == null; + } + if (this.selectedFolder && this.selectedFolderId != null && cipherPassesFilter) { + cipherPassesFilter = cipher.folderId === this.selectedFolderId; + } + if (this.selectedCollection && this.selectedCollectionId == null && cipherPassesFilter) { + cipherPassesFilter = + cipher.organizationId != null && + (cipher.collectionIds == null || cipher.collectionIds.length === 0); + } + if (this.selectedCollection && this.selectedCollectionId != null && cipherPassesFilter) { + cipherPassesFilter = + cipher.collectionIds != null && cipher.collectionIds.includes(this.selectedCollectionId); + } + if (this.selectedOrganizationId != null && cipherPassesFilter) { + cipherPassesFilter = cipher.organizationId === this.selectedOrganizationId; + } + if (this.myVaultOnly && cipherPassesFilter) { + cipherPassesFilter = cipher.organizationId === null; + } + return cipherPassesFilter; + }; + } } diff --git a/libs/angular/src/modules/vault-filter/vault-filter.component.ts b/libs/angular/src/modules/vault-filter/vault-filter.component.ts index b620ed82e2d..2e77e2fd878 100644 --- a/libs/angular/src/modules/vault-filter/vault-filter.component.ts +++ b/libs/angular/src/modules/vault-filter/vault-filter.component.ts @@ -111,9 +111,12 @@ export class VaultFilterComponent implements OnInit { protected pruneInvalidCollectionSelection(filter: VaultFilter): VaultFilter { if ( - filter.selectedCollectionId != null && - !this.collections?.hasId(filter.selectedCollectionId) + filter.myVaultOnly || + (filter.selectedCollection && + filter.selectedCollectionId != null && + !this.collections?.hasId(filter.selectedCollectionId)) ) { + filter.selectedCollection = false; filter.selectedCollectionId = null; } return filter; diff --git a/libs/common/src/services/collection.service.ts b/libs/common/src/services/collection.service.ts index 4d3563d7c5d..12054916e01 100644 --- a/libs/common/src/services/collection.service.ts +++ b/libs/common/src/services/collection.service.ts @@ -86,6 +86,7 @@ export class CollectionService implements CollectionServiceAbstraction { const collections = await this.getAll(); decryptedCollections = await this.decryptMany(collections); + await this.stateService.setDecryptedCollections(decryptedCollections); return decryptedCollections; } From 41275d4776cd8befb0195476e62d322ad4555068 Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Fri, 8 Jul 2022 11:02:36 +0200 Subject: [PATCH 22/86] Remove shared eslint since it's not used (#3058) --- libs/shared/eslintrc.json | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 libs/shared/eslintrc.json diff --git a/libs/shared/eslintrc.json b/libs/shared/eslintrc.json deleted file mode 100644 index 70c61bc7c4c..00000000000 --- a/libs/shared/eslintrc.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:import/recommended", - "plugin:import/typescript", - "prettier" - ], - "rules": { - "@typescript-eslint/no-explicit-any": "off", // TODO: This should be re-enabled - "@typescript-eslint/no-unused-vars": ["warn", { "args": "none" }], - "@typescript-eslint/explicit-member-accessibility": [ - "error", - { - "accessibility": "no-public" - } - ], - "@typescript-eslint/no-this-alias": [ - "error", - { - "allowedNames": ["self"] - } - ], - "no-console": "warn", - "import/no-unresolved": "off" // TODO: Look into turning off once each package is an actual package. - } -} From f79c4f0c65c775a91ca60b836ffc7d940fbd431b Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Fri, 8 Jul 2022 15:40:31 +0200 Subject: [PATCH 23/86] Extract API logic from FolderService to FolderApiService (#3011) --- .../browser/src/background/main.background.ts | 12 +++-- .../src/background/notification.background.ts | 2 +- .../src/popup/services/services.module.ts | 14 +++++- .../settings/folder-add-edit.component.ts | 6 ++- .../src/popup/settings/folders.component.ts | 2 +- .../src/popup/vault/add-edit.component.ts | 2 +- .../src/popup/vault/ciphers.component.ts | 2 +- .../src/services/vaultFilter.service.ts | 2 +- apps/cli/src/bw.ts | 11 ++-- apps/cli/src/commands/create.command.ts | 8 +-- apps/cli/src/commands/delete.command.ts | 8 +-- apps/cli/src/commands/edit.command.ts | 8 +-- apps/cli/src/commands/get.command.ts | 2 +- apps/cli/src/commands/list.command.ts | 2 +- apps/cli/src/commands/serve.command.ts | 9 ++-- apps/cli/src/vault.program.ts | 9 ++-- apps/desktop/src/app/app.component.ts | 6 +-- .../src/app/vault/add-edit.component.ts | 2 +- .../app/vault/folder-add-edit.component.ts | 6 ++- apps/web/src/app/app.component.ts | 6 +-- .../vault-filter/vault-filter.service.ts | 2 +- .../import-export/org-import-export.module.ts | 2 +- .../organizations/vault/add-edit.component.ts | 2 +- .../app/settings/change-password.component.ts | 2 +- .../settings/emergency-add-edit.component.ts | 2 +- .../src/app/settings/update-key.component.ts | 2 +- .../import-export/import-export.module.ts | 2 +- apps/web/src/app/vault/add-edit.component.ts | 2 +- apps/web/src/app/vault/bulk-move.component.ts | 2 +- .../app/vault/folder-add-edit.component.ts | 6 ++- .../src/components/add-edit.component.ts | 2 +- .../components/folder-add-edit.component.ts | 8 +-- .../vault-filter/vault-filter.service.ts | 2 +- .../src/services/jslib-services.module.ts | 20 ++++++-- .../spec/services/export.service.spec.ts | 2 +- .../spec/services/import.service.spec.ts | 2 +- libs/common/src/abstractions/api.service.ts | 17 ++++--- .../folder/folder-api.service.abstraction.ts | 8 +++ .../folder.service.abstraction.ts} | 15 +++--- libs/common/src/services/api.service.ts | 25 +--------- libs/common/src/services/export.service.ts | 2 +- .../src/services/folder/folder-api.service.ts | 50 +++++++++++++++++++ .../services/{ => folder}/folder.service.ts | 50 +++++-------------- libs/common/src/services/import.service.ts | 2 +- libs/common/src/services/sync.service.ts | 8 +-- .../src/services/vaultTimeout.service.ts | 2 +- 46 files changed, 212 insertions(+), 146 deletions(-) create mode 100644 libs/common/src/abstractions/folder/folder-api.service.abstraction.ts rename libs/common/src/abstractions/{folder.service.ts => folder/folder.service.abstraction.ts} (62%) create mode 100644 libs/common/src/services/folder/folder-api.service.ts rename libs/common/src/services/{ => folder}/folder.service.ts (75%) diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 725cb1954b4..908f1211b5b 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -10,7 +10,8 @@ import { EnvironmentService as EnvironmentServiceAbstraction } from "@bitwarden/ import { EventService as EventServiceAbstraction } from "@bitwarden/common/abstractions/event.service"; import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service"; import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/fileUpload.service"; -import { FolderService as FolderServiceAbstraction } from "@bitwarden/common/abstractions/folder.service"; +import { FolderApiServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder-api.service.abstraction"; +import { InternalFolderService as InternalFolderServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service"; import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/abstractions/keyConnector.service"; import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service"; @@ -52,7 +53,8 @@ import { EnvironmentService } from "@bitwarden/common/services/environment.servi import { EventService } from "@bitwarden/common/services/event.service"; import { ExportService } from "@bitwarden/common/services/export.service"; import { FileUploadService } from "@bitwarden/common/services/fileUpload.service"; -import { FolderService } from "@bitwarden/common/services/folder.service"; +import { FolderApiService } from "@bitwarden/common/services/folder/folder-api.service"; +import { FolderService } from "@bitwarden/common/services/folder/folder.service"; import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service"; import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service"; import { NotificationsService } from "@bitwarden/common/services/notifications.service"; @@ -118,7 +120,7 @@ export default class MainBackground { environmentService: EnvironmentServiceAbstraction; settingsService: SettingsServiceAbstraction; cipherService: CipherServiceAbstraction; - folderService: FolderServiceAbstraction; + folderService: InternalFolderServiceAbstraction; collectionService: CollectionServiceAbstraction; vaultTimeoutService: VaultTimeoutServiceAbstraction; syncService: SyncServiceAbstraction; @@ -147,6 +149,7 @@ export default class MainBackground { vaultFilterService: VaultFilterService; usernameGenerationService: UsernameGenerationServiceAbstraction; encryptService: EncryptService; + folderApiService: FolderApiServiceAbstraction; onUpdatedRan: boolean; onReplacedRan: boolean; @@ -266,11 +269,11 @@ export default class MainBackground { ); this.folderService = new FolderService( this.cryptoService, - this.apiService, this.i18nService, this.cipherService, this.stateService ); + this.folderApiService = new FolderApiService(this.folderService, this.apiService); this.collectionService = new CollectionService( this.cryptoService, this.i18nService, @@ -368,6 +371,7 @@ export default class MainBackground { this.stateService, this.organizationService, this.providerService, + this.folderApiService, logoutCallback ); this.eventService = new EventService( diff --git a/apps/browser/src/background/notification.background.ts b/apps/browser/src/background/notification.background.ts index b44ce820079..f8db259cb70 100644 --- a/apps/browser/src/background/notification.background.ts +++ b/apps/browser/src/background/notification.background.ts @@ -1,6 +1,6 @@ import { AuthService } from "@bitwarden/common/abstractions/auth.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { PolicyService } from "@bitwarden/common/abstractions/policy.service"; import { AuthenticationStatus } from "@bitwarden/common/enums/authenticationStatus"; import { CipherType } from "@bitwarden/common/enums/cipherType"; diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 0c60df6c2f9..63360194cd0 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -20,7 +20,8 @@ import { EventService } from "@bitwarden/common/abstractions/event.service"; import { ExportService } from "@bitwarden/common/abstractions/export.service"; import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service"; import { FileUploadService } from "@bitwarden/common/abstractions/fileUpload.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderApiServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder-api.service.abstraction"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector.service"; import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service"; @@ -148,7 +149,16 @@ function getBgService(service: keyof MainBackground) { useFactory: getBgService("cryptoFunctionService"), deps: [], }, - { provide: FolderService, useFactory: getBgService("folderService"), deps: [] }, + { + provide: FolderService, + useFactory: getBgService("folderService"), + deps: [], + }, + { + provide: FolderApiServiceAbstraction, + useFactory: getBgService("folderApiService"), + deps: [], + }, { provide: CollectionService, useFactory: getBgService("collectionService"), diff --git a/apps/browser/src/popup/settings/folder-add-edit.component.ts b/apps/browser/src/popup/settings/folder-add-edit.component.ts index 6b8a2718e0a..c601292bb81 100644 --- a/apps/browser/src/popup/settings/folder-add-edit.component.ts +++ b/apps/browser/src/popup/settings/folder-add-edit.component.ts @@ -3,7 +3,8 @@ import { ActivatedRoute, Router } from "@angular/router"; import { first } from "rxjs/operators"; import { FolderAddEditComponent as BaseFolderAddEditComponent } from "@bitwarden/angular/components/folder-add-edit.component"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderApiServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder-api.service.abstraction"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; @@ -15,13 +16,14 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti export class FolderAddEditComponent extends BaseFolderAddEditComponent { constructor( folderService: FolderService, + folderApiService: FolderApiServiceAbstraction, i18nService: I18nService, platformUtilsService: PlatformUtilsService, private router: Router, private route: ActivatedRoute, logService: LogService ) { - super(folderService, i18nService, platformUtilsService, logService); + super(folderService, folderApiService, i18nService, platformUtilsService, logService); } async ngOnInit() { diff --git a/apps/browser/src/popup/settings/folders.component.ts b/apps/browser/src/popup/settings/folders.component.ts index eb289e8dcff..0e2a6036218 100644 --- a/apps/browser/src/popup/settings/folders.component.ts +++ b/apps/browser/src/popup/settings/folders.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from "@angular/core"; import { Router } from "@angular/router"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { FolderView } from "@bitwarden/common/models/view/folderView"; @Component({ diff --git a/apps/browser/src/popup/vault/add-edit.component.ts b/apps/browser/src/popup/vault/add-edit.component.ts index 237c3d40fae..899b9d6cff3 100644 --- a/apps/browser/src/popup/vault/add-edit.component.ts +++ b/apps/browser/src/popup/vault/add-edit.component.ts @@ -8,7 +8,7 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { EventService } from "@bitwarden/common/abstractions/event.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; diff --git a/apps/browser/src/popup/vault/ciphers.component.ts b/apps/browser/src/popup/vault/ciphers.component.ts index 8c3675101f6..383633a1c28 100644 --- a/apps/browser/src/popup/vault/ciphers.component.ts +++ b/apps/browser/src/popup/vault/ciphers.component.ts @@ -8,7 +8,7 @@ import { VaultFilter } from "@bitwarden/angular/modules/vault-filter/models/vaul import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; diff --git a/apps/browser/src/services/vaultFilter.service.ts b/apps/browser/src/services/vaultFilter.service.ts index 117cb901195..15fa3523a38 100644 --- a/apps/browser/src/services/vaultFilter.service.ts +++ b/apps/browser/src/services/vaultFilter.service.ts @@ -2,7 +2,7 @@ import { VaultFilter } from "@bitwarden/angular/modules/vault-filter/models/vaul import { VaultFilterService as BaseVaultFilterService } from "@bitwarden/angular/modules/vault-filter/vault-filter.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; import { PolicyService } from "@bitwarden/common/abstractions/policy.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts index 217782aac75..82a63bff96a 100644 --- a/apps/cli/src/bw.ts +++ b/apps/cli/src/bw.ts @@ -4,6 +4,7 @@ import * as path from "path"; import * as program from "commander"; import * as jsdom from "jsdom"; +import { InternalFolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { ClientType } from "@bitwarden/common/enums/clientType"; import { KeySuffixOptions } from "@bitwarden/common/enums/keySuffixOptions"; import { LogLevelType } from "@bitwarden/common/enums/logLevelType"; @@ -21,7 +22,8 @@ import { EncryptService } from "@bitwarden/common/services/encrypt.service"; import { EnvironmentService } from "@bitwarden/common/services/environment.service"; import { ExportService } from "@bitwarden/common/services/export.service"; import { FileUploadService } from "@bitwarden/common/services/fileUpload.service"; -import { FolderService } from "@bitwarden/common/services/folder.service"; +import { FolderApiService } from "@bitwarden/common/services/folder/folder-api.service"; +import { FolderService } from "@bitwarden/common/services/folder/folder.service"; import { ImportService } from "@bitwarden/common/services/import.service"; import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service"; import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service"; @@ -73,7 +75,7 @@ export class Main { environmentService: EnvironmentService; settingsService: SettingsService; cipherService: CipherService; - folderService: FolderService; + folderService: InternalFolderService; collectionService: CollectionService; vaultTimeoutService: VaultTimeoutService; syncService: SyncService; @@ -101,6 +103,7 @@ export class Main { organizationService: OrganizationService; providerService: ProviderService; twoFactorService: TwoFactorService; + folderApiService: FolderApiService; constructor() { let p = null; @@ -197,12 +200,13 @@ export class Main { this.folderService = new FolderService( this.cryptoService, - this.apiService, this.i18nService, this.cipherService, this.stateService ); + this.folderApiService = new FolderApiService(this.folderService, this.apiService); + this.collectionService = new CollectionService( this.cryptoService, this.i18nService, @@ -293,6 +297,7 @@ export class Main { this.stateService, this.organizationService, this.providerService, + this.folderApiService, async (expired: boolean) => await this.logout() ); diff --git a/apps/cli/src/commands/create.command.ts b/apps/cli/src/commands/create.command.ts index 3951c9ec78e..ad69efe51e8 100644 --- a/apps/cli/src/commands/create.command.ts +++ b/apps/cli/src/commands/create.command.ts @@ -4,7 +4,8 @@ import * as path from "path"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderApiServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder-api.service.abstraction"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { Utils } from "@bitwarden/common/misc/utils"; import { CipherExport } from "@bitwarden/common/models/export/cipherExport"; @@ -26,7 +27,8 @@ export class CreateCommand { private folderService: FolderService, private stateService: StateService, private cryptoService: CryptoService, - private apiService: ApiService + private apiService: ApiService, + private folderApiService: FolderApiServiceAbstraction ) {} async run( @@ -148,7 +150,7 @@ export class CreateCommand { private async createFolder(req: FolderExport) { const folder = await this.folderService.encrypt(FolderExport.toView(req)); try { - await this.folderService.saveWithServer(folder); + await this.folderApiService.save(folder); const newFolder = await this.folderService.get(folder.id); const decFolder = await newFolder.decrypt(); const res = new FolderResponse(decFolder); diff --git a/apps/cli/src/commands/delete.command.ts b/apps/cli/src/commands/delete.command.ts index 2a35b46637e..4ad4ac592af 100644 --- a/apps/cli/src/commands/delete.command.ts +++ b/apps/cli/src/commands/delete.command.ts @@ -1,6 +1,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderApiServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder-api.service.abstraction"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { Utils } from "@bitwarden/common/misc/utils"; import { Response } from "@bitwarden/node/cli/models/response"; @@ -12,7 +13,8 @@ export class DeleteCommand { private cipherService: CipherService, private folderService: FolderService, private stateService: StateService, - private apiService: ApiService + private apiService: ApiService, + private folderApiService: FolderApiServiceAbstraction ) {} async run(object: string, id: string, cmdOptions: Record): Promise { @@ -92,7 +94,7 @@ export class DeleteCommand { } try { - await this.folderService.deleteWithServer(id); + await this.folderApiService.delete(id); return Response.success(); } catch (e) { return Response.error(e); diff --git a/apps/cli/src/commands/edit.command.ts b/apps/cli/src/commands/edit.command.ts index b331b0551bc..9c8f68c8285 100644 --- a/apps/cli/src/commands/edit.command.ts +++ b/apps/cli/src/commands/edit.command.ts @@ -1,7 +1,8 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderApiServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder-api.service.abstraction"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { Utils } from "@bitwarden/common/misc/utils"; import { CipherExport } from "@bitwarden/common/models/export/cipherExport"; import { CollectionExport } from "@bitwarden/common/models/export/collectionExport"; @@ -21,7 +22,8 @@ export class EditCommand { private cipherService: CipherService, private folderService: FolderService, private cryptoService: CryptoService, - private apiService: ApiService + private apiService: ApiService, + private folderApiService: FolderApiServiceAbstraction ) {} async run( @@ -125,7 +127,7 @@ export class EditCommand { folderView = FolderExport.toView(req, folderView); const encFolder = await this.folderService.encrypt(folderView); try { - await this.folderService.saveWithServer(encFolder); + await this.folderApiService.save(encFolder); const updatedFolder = await this.folderService.get(folder.id); const decFolder = await updatedFolder.decrypt(); const res = new FolderResponse(decFolder); diff --git a/apps/cli/src/commands/get.command.ts b/apps/cli/src/commands/get.command.ts index 8fa9598dc9d..c597745fcb5 100644 --- a/apps/cli/src/commands/get.command.ts +++ b/apps/cli/src/commands/get.command.ts @@ -3,7 +3,7 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; diff --git a/apps/cli/src/commands/list.command.ts b/apps/cli/src/commands/list.command.ts index e7dfef3104a..e32bc3f7914 100644 --- a/apps/cli/src/commands/list.command.ts +++ b/apps/cli/src/commands/list.command.ts @@ -1,7 +1,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { Utils } from "@bitwarden/common/misc/utils"; diff --git a/apps/cli/src/commands/serve.command.ts b/apps/cli/src/commands/serve.command.ts index 2ce8b90409e..6900b1f93f1 100644 --- a/apps/cli/src/commands/serve.command.ts +++ b/apps/cli/src/commands/serve.command.ts @@ -79,13 +79,15 @@ export class ServeCommand { this.main.folderService, this.main.stateService, this.main.cryptoService, - this.main.apiService + this.main.apiService, + this.main.folderApiService ); this.editCommand = new EditCommand( this.main.cipherService, this.main.folderService, this.main.cryptoService, - this.main.apiService + this.main.apiService, + this.main.folderApiService ); this.generateCommand = new GenerateCommand( this.main.passwordGenerationService, @@ -102,7 +104,8 @@ export class ServeCommand { this.main.cipherService, this.main.folderService, this.main.stateService, - this.main.apiService + this.main.apiService, + this.main.folderApiService ); this.confirmCommand = new ConfirmCommand(this.main.apiService, this.main.cryptoService); this.restoreCommand = new RestoreCommand(this.main.cipherService); diff --git a/apps/cli/src/vault.program.ts b/apps/cli/src/vault.program.ts index 0237b164d18..616568fe248 100644 --- a/apps/cli/src/vault.program.ts +++ b/apps/cli/src/vault.program.ts @@ -229,7 +229,8 @@ export class VaultProgram extends Program { this.main.folderService, this.main.stateService, this.main.cryptoService, - this.main.apiService + this.main.apiService, + this.main.folderApiService ); const response = await command.run(object, encodedJson, cmd); this.processResponse(response); @@ -272,7 +273,8 @@ export class VaultProgram extends Program { this.main.cipherService, this.main.folderService, this.main.cryptoService, - this.main.apiService + this.main.apiService, + this.main.folderApiService ); const response = await command.run(object, id, encodedJson, cmd); this.processResponse(response); @@ -314,7 +316,8 @@ export class VaultProgram extends Program { this.main.cipherService, this.main.folderService, this.main.stateService, - this.main.apiService + this.main.apiService, + this.main.folderApiService ); const response = await command.run(object, id, cmd); this.processResponse(response); diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts index 9732173b564..36afd026e23 100644 --- a/apps/desktop/src/app/app.component.ts +++ b/apps/desktop/src/app/app.component.ts @@ -20,7 +20,7 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { EventService } from "@bitwarden/common/abstractions/event.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { InternalFolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; @@ -34,7 +34,6 @@ import { SettingsService } from "@bitwarden/common/abstractions/settings.service import { StateService } from "@bitwarden/common/abstractions/state.service"; import { SyncService } from "@bitwarden/common/abstractions/sync.service"; import { SystemService } from "@bitwarden/common/abstractions/system.service"; -import { TokenService } from "@bitwarden/common/abstractions/token.service"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout.service"; import { AuthenticationStatus } from "@bitwarden/common/enums/authenticationStatus"; import { CipherType } from "@bitwarden/common/enums/cipherType"; @@ -101,8 +100,7 @@ export class AppComponent implements OnInit { constructor( private broadcasterService: BroadcasterService, - private tokenService: TokenService, - private folderService: FolderService, + private folderService: InternalFolderService, private settingsService: SettingsService, private syncService: SyncService, private passwordGenerationService: PasswordGenerationService, diff --git a/apps/desktop/src/app/vault/add-edit.component.ts b/apps/desktop/src/app/vault/add-edit.component.ts index b37d27b8ecc..0d3842998d2 100644 --- a/apps/desktop/src/app/vault/add-edit.component.ts +++ b/apps/desktop/src/app/vault/add-edit.component.ts @@ -7,7 +7,7 @@ import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.s import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { EventService } from "@bitwarden/common/abstractions/event.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; diff --git a/apps/desktop/src/app/vault/folder-add-edit.component.ts b/apps/desktop/src/app/vault/folder-add-edit.component.ts index 9c7369ac876..a014389577d 100644 --- a/apps/desktop/src/app/vault/folder-add-edit.component.ts +++ b/apps/desktop/src/app/vault/folder-add-edit.component.ts @@ -1,7 +1,8 @@ import { Component } from "@angular/core"; import { FolderAddEditComponent as BaseFolderAddEditComponent } from "@bitwarden/angular/components/folder-add-edit.component"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderApiServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder-api.service.abstraction"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; @@ -13,10 +14,11 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti export class FolderAddEditComponent extends BaseFolderAddEditComponent { constructor( folderService: FolderService, + folderApiService: FolderApiServiceAbstraction, i18nService: I18nService, platformUtilsService: PlatformUtilsService, logService: LogService ) { - super(folderService, i18nService, platformUtilsService, logService); + super(folderService, folderApiService, i18nService, platformUtilsService, logService); } } diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts index 4d934820730..16e6236c015 100644 --- a/apps/web/src/app/app.component.ts +++ b/apps/web/src/app/app.component.ts @@ -12,7 +12,7 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { EventService } from "@bitwarden/common/abstractions/event.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { InternalFolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector.service"; import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; @@ -23,7 +23,6 @@ import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { SyncService } from "@bitwarden/common/abstractions/sync.service"; -import { TokenService } from "@bitwarden/common/abstractions/token.service"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout.service"; import { DisableSendPolicy } from "./organizations/policies/disable-send.component"; @@ -53,8 +52,7 @@ export class AppComponent implements OnDestroy, OnInit { constructor( @Inject(DOCUMENT) private document: Document, private broadcasterService: BroadcasterService, - private tokenService: TokenService, - private folderService: FolderService, + private folderService: InternalFolderService, private settingsService: SettingsService, private syncService: SyncService, private passwordGenerationService: PasswordGenerationService, diff --git a/apps/web/src/app/modules/vault-filter/vault-filter.service.ts b/apps/web/src/app/modules/vault-filter/vault-filter.service.ts index d85ef3df169..6e221b219ac 100644 --- a/apps/web/src/app/modules/vault-filter/vault-filter.service.ts +++ b/apps/web/src/app/modules/vault-filter/vault-filter.service.ts @@ -6,7 +6,7 @@ import { VaultFilterService as BaseVaultFilterService } from "@bitwarden/angular import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; import { PolicyService } from "@bitwarden/common/abstractions/policy.service"; diff --git a/apps/web/src/app/organizations/tools/import-export/org-import-export.module.ts b/apps/web/src/app/organizations/tools/import-export/org-import-export.module.ts index b450f12dbd4..4de8023d4b9 100644 --- a/apps/web/src/app/organizations/tools/import-export/org-import-export.module.ts +++ b/apps/web/src/app/organizations/tools/import-export/org-import-export.module.ts @@ -7,7 +7,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { ImportService as ImportServiceAbstraction } from "@bitwarden/common/abstractions/import.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; diff --git a/apps/web/src/app/organizations/vault/add-edit.component.ts b/apps/web/src/app/organizations/vault/add-edit.component.ts index d271a568044..dac29f4e33f 100644 --- a/apps/web/src/app/organizations/vault/add-edit.component.ts +++ b/apps/web/src/app/organizations/vault/add-edit.component.ts @@ -5,7 +5,7 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { EventService } from "@bitwarden/common/abstractions/event.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; diff --git a/apps/web/src/app/settings/change-password.component.ts b/apps/web/src/app/settings/change-password.component.ts index 9e4fde680be..073314510fa 100644 --- a/apps/web/src/app/settings/change-password.component.ts +++ b/apps/web/src/app/settings/change-password.component.ts @@ -5,7 +5,7 @@ import { ChangePasswordComponent as BaseChangePasswordComponent } from "@bitward import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; diff --git a/apps/web/src/app/settings/emergency-add-edit.component.ts b/apps/web/src/app/settings/emergency-add-edit.component.ts index c0aabd8da36..28b69693431 100644 --- a/apps/web/src/app/settings/emergency-add-edit.component.ts +++ b/apps/web/src/app/settings/emergency-add-edit.component.ts @@ -4,7 +4,7 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { EventService } from "@bitwarden/common/abstractions/event.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; diff --git a/apps/web/src/app/settings/update-key.component.ts b/apps/web/src/app/settings/update-key.component.ts index 77aaab86aba..d771d57a79e 100644 --- a/apps/web/src/app/settings/update-key.component.ts +++ b/apps/web/src/app/settings/update-key.component.ts @@ -3,7 +3,7 @@ import { Component } from "@angular/core"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; diff --git a/apps/web/src/app/tools/import-export/import-export.module.ts b/apps/web/src/app/tools/import-export/import-export.module.ts index b34f78324a6..917df5cd6fc 100644 --- a/apps/web/src/app/tools/import-export/import-export.module.ts +++ b/apps/web/src/app/tools/import-export/import-export.module.ts @@ -7,7 +7,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { ImportService as ImportServiceAbstraction } from "@bitwarden/common/abstractions/import.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; diff --git a/apps/web/src/app/vault/add-edit.component.ts b/apps/web/src/app/vault/add-edit.component.ts index c5da24f8919..45afad6b583 100644 --- a/apps/web/src/app/vault/add-edit.component.ts +++ b/apps/web/src/app/vault/add-edit.component.ts @@ -5,7 +5,7 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { EventService } from "@bitwarden/common/abstractions/event.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; diff --git a/apps/web/src/app/vault/bulk-move.component.ts b/apps/web/src/app/vault/bulk-move.component.ts index 3dd906e5834..c4c674a9cce 100644 --- a/apps/web/src/app/vault/bulk-move.component.ts +++ b/apps/web/src/app/vault/bulk-move.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { FolderView } from "@bitwarden/common/models/view/folderView"; diff --git a/apps/web/src/app/vault/folder-add-edit.component.ts b/apps/web/src/app/vault/folder-add-edit.component.ts index 9c7369ac876..a014389577d 100644 --- a/apps/web/src/app/vault/folder-add-edit.component.ts +++ b/apps/web/src/app/vault/folder-add-edit.component.ts @@ -1,7 +1,8 @@ import { Component } from "@angular/core"; import { FolderAddEditComponent as BaseFolderAddEditComponent } from "@bitwarden/angular/components/folder-add-edit.component"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderApiServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder-api.service.abstraction"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; @@ -13,10 +14,11 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti export class FolderAddEditComponent extends BaseFolderAddEditComponent { constructor( folderService: FolderService, + folderApiService: FolderApiServiceAbstraction, i18nService: I18nService, platformUtilsService: PlatformUtilsService, logService: LogService ) { - super(folderService, i18nService, platformUtilsService, logService); + super(folderService, folderApiService, i18nService, platformUtilsService, logService); } } diff --git a/libs/angular/src/components/add-edit.component.ts b/libs/angular/src/components/add-edit.component.ts index aa6ec4aee14..aeac25aade2 100644 --- a/libs/angular/src/components/add-edit.component.ts +++ b/libs/angular/src/components/add-edit.component.ts @@ -4,7 +4,7 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { EventService } from "@bitwarden/common/abstractions/event.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; diff --git a/libs/angular/src/components/folder-add-edit.component.ts b/libs/angular/src/components/folder-add-edit.component.ts index 9668f372ecd..2558482c2da 100644 --- a/libs/angular/src/components/folder-add-edit.component.ts +++ b/libs/angular/src/components/folder-add-edit.component.ts @@ -1,6 +1,7 @@ import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderApiServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder-api.service.abstraction"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; @@ -20,6 +21,7 @@ export class FolderAddEditComponent implements OnInit { constructor( protected folderService: FolderService, + protected folderApiService: FolderApiServiceAbstraction, protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService, private logService: LogService @@ -41,7 +43,7 @@ export class FolderAddEditComponent implements OnInit { try { const folder = await this.folderService.encrypt(this.folder); - this.formPromise = this.folderService.saveWithServer(folder); + this.formPromise = this.folderApiService.save(folder); await this.formPromise; this.platformUtilsService.showToast( "success", @@ -70,7 +72,7 @@ export class FolderAddEditComponent implements OnInit { } try { - this.deletePromise = this.folderService.deleteWithServer(this.folder.id); + this.deletePromise = this.folderApiService.delete(this.folder.id); await this.deletePromise; this.platformUtilsService.showToast("success", null, this.i18nService.t("deletedFolder")); this.onDeletedFolder.emit(this.folder); diff --git a/libs/angular/src/modules/vault-filter/vault-filter.service.ts b/libs/angular/src/modules/vault-filter/vault-filter.service.ts index ea5f52ee909..6223433c036 100644 --- a/libs/angular/src/modules/vault-filter/vault-filter.service.ts +++ b/libs/angular/src/modules/vault-filter/vault-filter.service.ts @@ -2,7 +2,7 @@ import { Injectable } from "@angular/core"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; import { PolicyService } from "@bitwarden/common/abstractions/policy.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 245fa58bf95..e90acd075e7 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -16,7 +16,11 @@ import { EnvironmentService as EnvironmentServiceAbstraction } from "@bitwarden/ import { EventService as EventServiceAbstraction } from "@bitwarden/common/abstractions/event.service"; import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service"; import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/fileUpload.service"; -import { FolderService as FolderServiceAbstraction } from "@bitwarden/common/abstractions/folder.service"; +import { FolderApiServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder-api.service.abstraction"; +import { + FolderService as FolderServiceAbstraction, + InternalFolderService, +} from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { FormValidationErrorsService as FormValidationErrorsServiceAbstraction } from "@bitwarden/common/abstractions/formValidationErrors.service"; import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service"; import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/abstractions/keyConnector.service"; @@ -58,7 +62,8 @@ import { EnvironmentService } from "@bitwarden/common/services/environment.servi import { EventService } from "@bitwarden/common/services/event.service"; import { ExportService } from "@bitwarden/common/services/export.service"; import { FileUploadService } from "@bitwarden/common/services/fileUpload.service"; -import { FolderService } from "@bitwarden/common/services/folder.service"; +import { FolderApiService } from "@bitwarden/common/services/folder/folder-api.service"; +import { FolderService } from "@bitwarden/common/services/folder/folder.service"; import { FormValidationErrorsService } from "@bitwarden/common/services/formValidationErrors.service"; import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service"; import { NotificationsService } from "@bitwarden/common/services/notifications.service"; @@ -215,12 +220,20 @@ export const LOG_MAC_FAILURES = new InjectionToken("LOG_MAC_FAILURES"); useClass: FolderService, deps: [ CryptoServiceAbstraction, - ApiServiceAbstraction, I18nServiceAbstraction, CipherServiceAbstraction, StateServiceAbstraction, ], }, + { + provide: InternalFolderService, + useExisting: FolderServiceAbstraction, + }, + { + provide: FolderApiServiceAbstraction, + useClass: FolderApiService, + deps: [FolderServiceAbstraction, ApiServiceAbstraction], + }, { provide: LogService, useFactory: () => new ConsoleLogService(false) }, { provide: CollectionServiceAbstraction, @@ -293,6 +306,7 @@ export const LOG_MAC_FAILURES = new InjectionToken("LOG_MAC_FAILURES"); StateServiceAbstraction, OrganizationServiceAbstraction, ProviderServiceAbstraction, + FolderApiServiceAbstraction, LOGOUT_CALLBACK, ], }, diff --git a/libs/common/spec/services/export.service.spec.ts b/libs/common/spec/services/export.service.spec.ts index 7c0a20c4507..089073cb37a 100644 --- a/libs/common/spec/services/export.service.spec.ts +++ b/libs/common/spec/services/export.service.spec.ts @@ -4,7 +4,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { CipherType } from "@bitwarden/common/enums/cipherType"; import { KdfType } from "@bitwarden/common/enums/kdfType"; import { Utils } from "@bitwarden/common/misc/utils"; diff --git a/libs/common/spec/services/import.service.spec.ts b/libs/common/spec/services/import.service.spec.ts index 5f0789943b5..34646565684 100644 --- a/libs/common/spec/services/import.service.spec.ts +++ b/libs/common/spec/services/import.service.spec.ts @@ -4,7 +4,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; -import { FolderService } from "@bitwarden/common/abstractions/folder.service"; +import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { BitwardenPasswordProtectedImporter } from "@bitwarden/common/importers/bitwardenPasswordProtectedImporter"; diff --git a/libs/common/src/abstractions/api.service.ts b/libs/common/src/abstractions/api.service.ts index d485328d0d2..8405c533663 100644 --- a/libs/common/src/abstractions/api.service.ts +++ b/libs/common/src/abstractions/api.service.ts @@ -23,7 +23,6 @@ import { EmergencyAccessInviteRequest } from "../models/request/emergencyAccessI import { EmergencyAccessPasswordRequest } from "../models/request/emergencyAccessPasswordRequest"; import { EmergencyAccessUpdateRequest } from "../models/request/emergencyAccessUpdateRequest"; import { EventRequest } from "../models/request/eventRequest"; -import { FolderRequest } from "../models/request/folderRequest"; import { GroupRequest } from "../models/request/groupRequest"; import { IapCheckRequest } from "../models/request/iapCheckRequest"; import { ApiTokenRequest } from "../models/request/identityToken/apiTokenRequest"; @@ -117,7 +116,6 @@ import { EmergencyAccessViewResponse, } from "../models/response/emergencyAccessResponse"; import { EventResponse } from "../models/response/eventResponse"; -import { FolderResponse } from "../models/response/folderResponse"; import { GroupDetailsResponse, GroupResponse } from "../models/response/groupResponse"; import { IdentityCaptchaResponse } from "../models/response/identityCaptchaResponse"; import { IdentityTokenResponse } from "../models/response/identityTokenResponse"; @@ -182,6 +180,16 @@ import { UserKeyResponse } from "../models/response/userKeyResponse"; import { SendAccessView } from "../models/view/sendAccessView"; export abstract class ApiService { + send: ( + method: "GET" | "POST" | "PUT" | "DELETE", + path: string, + body: any, + authed: boolean, + hasResponse: boolean, + apiUrl?: string, + alterHeaders?: (headers: Headers) => void + ) => Promise; + postIdentityToken: ( request: PasswordTokenRequest | SsoTokenRequest | ApiTokenRequest ) => Promise; @@ -228,11 +236,6 @@ export abstract class ApiService { getUserBillingHistory: () => Promise; getUserBillingPayment: () => Promise; - getFolder: (id: string) => Promise; - postFolder: (request: FolderRequest) => Promise; - putFolder: (id: string, request: FolderRequest) => Promise; - deleteFolder: (id: string) => Promise; - getSend: (id: string) => Promise; postSendAccess: ( id: string, diff --git a/libs/common/src/abstractions/folder/folder-api.service.abstraction.ts b/libs/common/src/abstractions/folder/folder-api.service.abstraction.ts new file mode 100644 index 00000000000..97f3b724afe --- /dev/null +++ b/libs/common/src/abstractions/folder/folder-api.service.abstraction.ts @@ -0,0 +1,8 @@ +import { Folder } from "@bitwarden/common/models/domain/folder"; +import { FolderResponse } from "@bitwarden/common/models/response/folderResponse"; + +export class FolderApiServiceAbstraction { + save: (folder: Folder) => Promise; + delete: (id: string) => Promise; + get: (id: string) => Promise; +} diff --git a/libs/common/src/abstractions/folder.service.ts b/libs/common/src/abstractions/folder/folder.service.abstraction.ts similarity index 62% rename from libs/common/src/abstractions/folder.service.ts rename to libs/common/src/abstractions/folder/folder.service.abstraction.ts index f848de90920..e7655bbd815 100644 --- a/libs/common/src/abstractions/folder.service.ts +++ b/libs/common/src/abstractions/folder/folder.service.abstraction.ts @@ -1,8 +1,8 @@ -import { FolderData } from "../models/data/folderData"; -import { Folder } from "../models/domain/folder"; -import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey"; -import { TreeNode } from "../models/domain/treeNode"; -import { FolderView } from "../models/view/folderView"; +import { FolderData } from "../../models/data/folderData"; +import { Folder } from "../../models/domain/folder"; +import { SymmetricCryptoKey } from "../../models/domain/symmetricCryptoKey"; +import { TreeNode } from "../../models/domain/treeNode"; +import { FolderView } from "../../models/view/folderView"; export abstract class FolderService { clearCache: (userId?: string) => Promise; @@ -12,10 +12,11 @@ export abstract class FolderService { getAllDecrypted: () => Promise; getAllNested: (folders?: FolderView[]) => Promise[]>; getNested: (id: string) => Promise>; - saveWithServer: (folder: Folder) => Promise; +} + +export abstract class InternalFolderService extends FolderService { upsert: (folder: FolderData | FolderData[]) => Promise; replace: (folders: { [id: string]: FolderData }) => Promise; clear: (userId: string) => Promise; delete: (id: string | string[]) => Promise; - deleteWithServer: (id: string) => Promise; } diff --git a/libs/common/src/services/api.service.ts b/libs/common/src/services/api.service.ts index 9f2108663cf..7cf4964caf9 100644 --- a/libs/common/src/services/api.service.ts +++ b/libs/common/src/services/api.service.ts @@ -30,7 +30,6 @@ import { EmergencyAccessInviteRequest } from "../models/request/emergencyAccessI import { EmergencyAccessPasswordRequest } from "../models/request/emergencyAccessPasswordRequest"; import { EmergencyAccessUpdateRequest } from "../models/request/emergencyAccessUpdateRequest"; import { EventRequest } from "../models/request/eventRequest"; -import { FolderRequest } from "../models/request/folderRequest"; import { GroupRequest } from "../models/request/groupRequest"; import { IapCheckRequest } from "../models/request/iapCheckRequest"; import { ApiTokenRequest } from "../models/request/identityToken/apiTokenRequest"; @@ -126,7 +125,6 @@ import { } from "../models/response/emergencyAccessResponse"; import { ErrorResponse } from "../models/response/errorResponse"; import { EventResponse } from "../models/response/eventResponse"; -import { FolderResponse } from "../models/response/folderResponse"; import { GroupDetailsResponse, GroupResponse } from "../models/response/groupResponse"; import { IdentityCaptchaResponse } from "../models/response/identityCaptchaResponse"; import { IdentityTokenResponse } from "../models/response/identityTokenResponse"; @@ -487,27 +485,6 @@ export class ApiService implements ApiServiceAbstraction { return new BillingPaymentResponse(r); } - // Folder APIs - - async getFolder(id: string): Promise { - const r = await this.send("GET", "/folders/" + id, null, true, true); - return new FolderResponse(r); - } - - async postFolder(request: FolderRequest): Promise { - const r = await this.send("POST", "/folders", request, true, true); - return new FolderResponse(r); - } - - async putFolder(id: string, request: FolderRequest): Promise { - const r = await this.send("PUT", "/folders/" + id, request, true, true); - return new FolderResponse(r); - } - - deleteFolder(id: string): Promise { - return this.send("DELETE", "/folders/" + id, null, true, false); - } - // Send APIs async getSend(id: string): Promise { @@ -2566,7 +2543,7 @@ export class ApiService implements ApiServiceAbstraction { await this.tokenService.setToken(response.accessToken); } - private async send( + async send( method: "GET" | "POST" | "PUT" | "DELETE", path: string, body: any, diff --git a/libs/common/src/services/export.service.ts b/libs/common/src/services/export.service.ts index c6f08be6d26..06b4221ba0d 100644 --- a/libs/common/src/services/export.service.ts +++ b/libs/common/src/services/export.service.ts @@ -8,7 +8,7 @@ import { ExportFormat, ExportService as ExportServiceAbstraction, } from "../abstractions/export.service"; -import { FolderService } from "../abstractions/folder.service"; +import { FolderService } from "../abstractions/folder/folder.service.abstraction"; import { CipherType } from "../enums/cipherType"; import { DEFAULT_KDF_ITERATIONS, KdfType } from "../enums/kdfType"; import { Utils } from "../misc/utils"; diff --git a/libs/common/src/services/folder/folder-api.service.ts b/libs/common/src/services/folder/folder-api.service.ts new file mode 100644 index 00000000000..d855c063539 --- /dev/null +++ b/libs/common/src/services/folder/folder-api.service.ts @@ -0,0 +1,50 @@ +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { FolderApiServiceAbstraction } from "@bitwarden/common/abstractions/folder/folder-api.service.abstraction"; +import { InternalFolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; +import { FolderData } from "@bitwarden/common/models/data/folderData"; +import { Folder } from "@bitwarden/common/models/domain/folder"; +import { FolderRequest } from "@bitwarden/common/models/request/folderRequest"; +import { FolderResponse } from "@bitwarden/common/models/response/folderResponse"; + +export class FolderApiService implements FolderApiServiceAbstraction { + constructor(private folderService: InternalFolderService, private apiService: ApiService) {} + + async save(folder: Folder): Promise { + const request = new FolderRequest(folder); + + let response: FolderResponse; + if (folder.id == null) { + response = await this.postFolder(request); + folder.id = response.id; + } else { + response = await this.putFolder(folder.id, request); + } + + const data = new FolderData(response); + await this.folderService.upsert(data); + } + + async delete(id: string): Promise { + await this.deleteFolder(id); + await this.folderService.delete(id); + } + + async get(id: string): Promise { + const r = await this.apiService.send("GET", "/folders/" + id, null, true, true); + return new FolderResponse(r); + } + + private async postFolder(request: FolderRequest): Promise { + const r = await this.apiService.send("POST", "/folders", request, true, true); + return new FolderResponse(r); + } + + async putFolder(id: string, request: FolderRequest): Promise { + const r = await this.apiService.send("PUT", "/folders/" + id, request, true, true); + return new FolderResponse(r); + } + + private deleteFolder(id: string): Promise { + return this.apiService.send("DELETE", "/folders/" + id, null, true, false); + } +} diff --git a/libs/common/src/services/folder.service.ts b/libs/common/src/services/folder/folder.service.ts similarity index 75% rename from libs/common/src/services/folder.service.ts rename to libs/common/src/services/folder/folder.service.ts index f791c07f4d2..77d8cfc0a93 100644 --- a/libs/common/src/services/folder.service.ts +++ b/libs/common/src/services/folder/folder.service.ts @@ -1,26 +1,22 @@ -import { ApiService } from "../abstractions/api.service"; -import { CipherService } from "../abstractions/cipher.service"; -import { CryptoService } from "../abstractions/crypto.service"; -import { FolderService as FolderServiceAbstraction } from "../abstractions/folder.service"; -import { I18nService } from "../abstractions/i18n.service"; -import { StateService } from "../abstractions/state.service"; -import { ServiceUtils } from "../misc/serviceUtils"; -import { Utils } from "../misc/utils"; -import { CipherData } from "../models/data/cipherData"; -import { FolderData } from "../models/data/folderData"; -import { Folder } from "../models/domain/folder"; -import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey"; -import { TreeNode } from "../models/domain/treeNode"; -import { FolderRequest } from "../models/request/folderRequest"; -import { FolderResponse } from "../models/response/folderResponse"; -import { FolderView } from "../models/view/folderView"; +import { CipherService } from "../../abstractions/cipher.service"; +import { CryptoService } from "../../abstractions/crypto.service"; +import { FolderService as FolderServiceAbstraction } from "../../abstractions/folder/folder.service.abstraction"; +import { I18nService } from "../../abstractions/i18n.service"; +import { StateService } from "../../abstractions/state.service"; +import { ServiceUtils } from "../../misc/serviceUtils"; +import { Utils } from "../../misc/utils"; +import { CipherData } from "../../models/data/cipherData"; +import { FolderData } from "../../models/data/folderData"; +import { Folder } from "../../models/domain/folder"; +import { SymmetricCryptoKey } from "../../models/domain/symmetricCryptoKey"; +import { TreeNode } from "../../models/domain/treeNode"; +import { FolderView } from "../../models/view/folderView"; const NestingDelimiter = "/"; export class FolderService implements FolderServiceAbstraction { constructor( private cryptoService: CryptoService, - private apiService: ApiService, private i18nService: I18nService, private cipherService: CipherService, private stateService: StateService @@ -106,21 +102,6 @@ export class FolderService implements FolderServiceAbstraction { return ServiceUtils.getTreeNodeObject(folders, id) as TreeNode; } - async saveWithServer(folder: Folder): Promise { - const request = new FolderRequest(folder); - - let response: FolderResponse; - if (folder.id == null) { - response = await this.apiService.postFolder(request); - folder.id = response.id; - } else { - response = await this.apiService.putFolder(folder.id, request); - } - - const data = new FolderData(response); - await this.upsert(data); - } - async upsert(folder: FolderData | FolderData[]): Promise { let folders = await this.stateService.getEncryptedFolders(); if (folders == null) { @@ -185,9 +166,4 @@ export class FolderService implements FolderServiceAbstraction { } } } - - async deleteWithServer(id: string): Promise { - await this.apiService.deleteFolder(id); - await this.delete(id); - } } diff --git a/libs/common/src/services/import.service.ts b/libs/common/src/services/import.service.ts index 86226d7d6a7..2b1b7bd5678 100644 --- a/libs/common/src/services/import.service.ts +++ b/libs/common/src/services/import.service.ts @@ -2,7 +2,7 @@ import { ApiService } from "../abstractions/api.service"; import { CipherService } from "../abstractions/cipher.service"; import { CollectionService } from "../abstractions/collection.service"; import { CryptoService } from "../abstractions/crypto.service"; -import { FolderService } from "../abstractions/folder.service"; +import { FolderService } from "../abstractions/folder/folder.service.abstraction"; import { I18nService } from "../abstractions/i18n.service"; import { ImportService as ImportServiceAbstraction } from "../abstractions/import.service"; import { PlatformUtilsService } from "../abstractions/platformUtils.service"; diff --git a/libs/common/src/services/sync.service.ts b/libs/common/src/services/sync.service.ts index c054a211f1c..8a061bcbb17 100644 --- a/libs/common/src/services/sync.service.ts +++ b/libs/common/src/services/sync.service.ts @@ -2,7 +2,8 @@ import { ApiService } from "../abstractions/api.service"; import { CipherService } from "../abstractions/cipher.service"; import { CollectionService } from "../abstractions/collection.service"; import { CryptoService } from "../abstractions/crypto.service"; -import { FolderService } from "../abstractions/folder.service"; +import { FolderApiServiceAbstraction } from "../abstractions/folder/folder-api.service.abstraction"; +import { InternalFolderService } from "../abstractions/folder/folder.service.abstraction"; import { KeyConnectorService } from "../abstractions/keyConnector.service"; import { LogService } from "../abstractions/log.service"; import { MessagingService } from "../abstractions/messaging.service"; @@ -40,7 +41,7 @@ export class SyncService implements SyncServiceAbstraction { constructor( private apiService: ApiService, private settingsService: SettingsService, - private folderService: FolderService, + private folderService: InternalFolderService, private cipherService: CipherService, private cryptoService: CryptoService, private collectionService: CollectionService, @@ -52,6 +53,7 @@ export class SyncService implements SyncServiceAbstraction { private stateService: StateService, private organizationService: OrganizationService, private providerService: ProviderService, + private folderApiService: FolderApiServiceAbstraction, private logoutCallback: (expired: boolean) => Promise ) {} @@ -127,7 +129,7 @@ export class SyncService implements SyncServiceAbstraction { (!isEdit && localFolder == null) || (isEdit && localFolder != null && localFolder.revisionDate < notification.revisionDate) ) { - const remoteFolder = await this.apiService.getFolder(notification.id); + const remoteFolder = await this.folderApiService.get(notification.id); if (remoteFolder != null) { await this.folderService.upsert(new FolderData(remoteFolder)); this.messagingService.send("syncedUpsertedFolder", { folderId: notification.id }); diff --git a/libs/common/src/services/vaultTimeout.service.ts b/libs/common/src/services/vaultTimeout.service.ts index 935c55d8e6b..dcb5db62d24 100644 --- a/libs/common/src/services/vaultTimeout.service.ts +++ b/libs/common/src/services/vaultTimeout.service.ts @@ -2,7 +2,7 @@ import { AuthService } from "../abstractions/auth.service"; import { CipherService } from "../abstractions/cipher.service"; import { CollectionService } from "../abstractions/collection.service"; import { CryptoService } from "../abstractions/crypto.service"; -import { FolderService } from "../abstractions/folder.service"; +import { FolderService } from "../abstractions/folder/folder.service.abstraction"; import { KeyConnectorService } from "../abstractions/keyConnector.service"; import { MessagingService } from "../abstractions/messaging.service"; import { PlatformUtilsService } from "../abstractions/platformUtils.service"; From 7d5df80d2f135e249f560171ebb493668f9fc074 Mon Sep 17 00:00:00 2001 From: Addison Beck Date: Fri, 8 Jul 2022 14:28:02 -0400 Subject: [PATCH 24/86] [fix] Adjust extraResources in electronBuilder to account for the monorepo move (#3072) --- apps/desktop/electron-builder.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/electron-builder.json b/apps/desktop/electron-builder.json index 22c579d9600..1feb33069a5 100644 --- a/apps/desktop/electron-builder.json +++ b/apps/desktop/electron-builder.json @@ -69,7 +69,7 @@ "sign": "./sign.js", "extraResources": [ { - "from": "node_modules/regedit/vbs", + "from": "../../node_modules/regedit/vbs", "to": "regedit/vbs", "filter": ["**/*"] }, From 1b0ab38ada682f779e9c5e19ad4d3416f8eee375 Mon Sep 17 00:00:00 2001 From: Addison Beck Date: Fri, 8 Jul 2022 16:54:15 -0400 Subject: [PATCH 25/86] [fix] Generator settings not persisting across web sessions (#3074) --- libs/common/src/services/state.service.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libs/common/src/services/state.service.ts b/libs/common/src/services/state.service.ts index c2ae787482a..fcb4a785950 100644 --- a/libs/common/src/services/state.service.ts +++ b/libs/common/src/services/state.service.ts @@ -1940,52 +1940,52 @@ export class StateService< async getPasswordGenerationOptions(options?: StorageOptions): Promise { return ( - await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) + await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskLocalOptions())) )?.settings?.passwordGenerationOptions; } async setPasswordGenerationOptions(value: any, options?: StorageOptions): Promise { const account = await this.getAccount( - this.reconcileOptions(options, await this.defaultOnDiskOptions()) + this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); account.settings.passwordGenerationOptions = value; await this.saveAccount( account, - this.reconcileOptions(options, await this.defaultOnDiskOptions()) + this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } async getUsernameGenerationOptions(options?: StorageOptions): Promise { return ( - await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) + await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskLocalOptions())) )?.settings?.usernameGenerationOptions; } async setUsernameGenerationOptions(value: any, options?: StorageOptions): Promise { const account = await this.getAccount( - this.reconcileOptions(options, await this.defaultOnDiskOptions()) + this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); account.settings.usernameGenerationOptions = value; await this.saveAccount( account, - this.reconcileOptions(options, await this.defaultOnDiskOptions()) + this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } async getGeneratorOptions(options?: StorageOptions): Promise { return ( - await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) + await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskLocalOptions())) )?.settings?.generatorOptions; } async setGeneratorOptions(value: any, options?: StorageOptions): Promise { const account = await this.getAccount( - this.reconcileOptions(options, await this.defaultOnDiskOptions()) + this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); account.settings.generatorOptions = value; await this.saveAccount( account, - this.reconcileOptions(options, await this.defaultOnDiskOptions()) + this.reconcileOptions(options, await this.defaultOnDiskLocalOptions()) ); } From 9347b13a76508b2d8fe5a28e47f610133242c614 Mon Sep 17 00:00:00 2001 From: Robyn MacCallum Date: Fri, 8 Jul 2022 21:05:35 -0400 Subject: [PATCH 26/86] [SG-73] Make Organization Info a reusable component (#3007) * Create reusable organization info component * remove extra import * Use observable for form value changes * Remove unnecessary null checks * Refactor reactive controls --- .../app/modules/loose-components.module.ts | 2 + .../create/organization-create.module.ts | 12 ++ .../organization-information.component.html | 32 ++++++ .../organization-information.component.ts | 12 ++ apps/web/src/app/oss.module.ts | 2 + .../organization-plans.component.html | 106 +++++------------- .../settings/organization-plans.component.ts | 106 +++++++++++------- 7 files changed, 157 insertions(+), 115 deletions(-) create mode 100644 apps/web/src/app/modules/organizations/create/organization-create.module.ts create mode 100644 apps/web/src/app/modules/organizations/create/organization-information.component.html create mode 100644 apps/web/src/app/modules/organizations/create/organization-information.component.ts diff --git a/apps/web/src/app/modules/loose-components.module.ts b/apps/web/src/app/modules/loose-components.module.ts index 37a87cee364..a84ac4fb9a7 100644 --- a/apps/web/src/app/modules/loose-components.module.ts +++ b/apps/web/src/app/modules/loose-components.module.ts @@ -156,6 +156,7 @@ import { CollectionsComponent } from "../vault/collections.component"; import { FolderAddEditComponent } from "../vault/folder-add-edit.component"; import { ShareComponent } from "../vault/share.component"; +import { OrganizationCreateModule } from "./organizations/create/organization-create.module"; import { PipesModule } from "./pipes/pipes.module"; import { RegisterFormModule } from "./register-form/register-form.module"; import { SharedModule } from "./shared.module"; @@ -170,6 +171,7 @@ import { OrganizationBadgeModule } from "./vault/modules/organization-badge/orga VaultFilterModule, OrganizationBadgeModule, PipesModule, + OrganizationCreateModule, RegisterFormModule, ], declarations: [ diff --git a/apps/web/src/app/modules/organizations/create/organization-create.module.ts b/apps/web/src/app/modules/organizations/create/organization-create.module.ts new file mode 100644 index 00000000000..2ee84fdd680 --- /dev/null +++ b/apps/web/src/app/modules/organizations/create/organization-create.module.ts @@ -0,0 +1,12 @@ +import { NgModule } from "@angular/core"; + +import { SharedModule } from "../../shared.module"; + +import { OrganizationInformationComponent } from "./organization-information.component"; + +@NgModule({ + imports: [SharedModule], + declarations: [OrganizationInformationComponent], + exports: [OrganizationInformationComponent], +}) +export class OrganizationCreateModule {} diff --git a/apps/web/src/app/modules/organizations/create/organization-information.component.html b/apps/web/src/app/modules/organizations/create/organization-information.component.html new file mode 100644 index 00000000000..7550bfbf4c6 --- /dev/null +++ b/apps/web/src/app/modules/organizations/create/organization-information.component.html @@ -0,0 +1,32 @@ +
    + + {{ "organizationName" | i18n }} + + +
    +
    +

    {{ "generalInformation" | i18n }}

    +
    + + {{ "organizationName" | i18n }} + + + + {{ "billingEmail" | i18n }} + + +
    + + {{ "accountOwnedBusiness" | i18n }} +
    + + {{ "businessName" | i18n }} + + +
    +
    diff --git a/apps/web/src/app/modules/organizations/create/organization-information.component.ts b/apps/web/src/app/modules/organizations/create/organization-information.component.ts new file mode 100644 index 00000000000..5d35f6df8ac --- /dev/null +++ b/apps/web/src/app/modules/organizations/create/organization-information.component.ts @@ -0,0 +1,12 @@ +import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { FormGroup } from "@angular/forms"; + +@Component({ + selector: "app-org-info", + templateUrl: "organization-information.component.html", +}) +export class OrganizationInformationComponent { + @Input() nameOnly = false; + @Input() formGroup: FormGroup; + @Output() changedBusinessOwned = new EventEmitter(); +} diff --git a/apps/web/src/app/oss.module.ts b/apps/web/src/app/oss.module.ts index af19fa08d04..c43f8a4d5f5 100644 --- a/apps/web/src/app/oss.module.ts +++ b/apps/web/src/app/oss.module.ts @@ -1,6 +1,7 @@ import { NgModule } from "@angular/core"; import { LooseComponentsModule } from "./modules/loose-components.module"; +import { OrganizationCreateModule } from "./modules/organizations/create/organization-create.module"; import { OrganizationManageModule } from "./modules/organizations/manage/organization-manage.module"; import { OrganizationUserModule } from "./modules/organizations/users/organization-user.module"; import { PipesModule } from "./modules/pipes/pipes.module"; @@ -19,6 +20,7 @@ import { OrganizationBadgeModule } from "./modules/vault/modules/organization-ba PipesModule, OrganizationManageModule, OrganizationUserModule, + OrganizationCreateModule, ], exports: [ SharedModule, diff --git a/apps/web/src/app/settings/organization-plans.component.html b/apps/web/src/app/settings/organization-plans.component.html index 7b827ce7c79..4fe4c3263e8 100644 --- a/apps/web/src/app/settings/organization-plans.component.html +++ b/apps/web/src/app/settings/organization-plans.component.html @@ -24,68 +24,17 @@
    -

    {{ "generalInformation" | i18n }}

    -
    -
    - - -
    -
    - - -
    -
    - - - {{ "clientOwnerDesc" | i18n: "20" }} -
    -
    -
    -
    - - -
    -
    -
    - - -
    -
    -
    +

    {{ "chooseYourPlan" | i18n }}

    -
    +

    {{ "users" | i18n }}

    @@ -177,8 +126,8 @@ id="additionalSeats" class="form-control" type="number" - name="AdditionalSeats" - [(ngModel)]="additionalSeats" + name="additionalSeats" + formControlName="additionalSeats" min="1" max="100000" placeholder="{{ 'userSeatsDesc' | i18n }}" @@ -196,8 +145,8 @@ id="additionalSeats" class="form-control" type="number" - name="AdditionalSeats" - [(ngModel)]="additionalSeats" + name="additionalSeats" + formControlName="additionalSeats" min="0" max="100000" placeholder="{{ 'userSeatsDesc' | i18n }}" @@ -215,8 +164,8 @@ id="additionalStorage" class="form-control" type="number" - name="AdditionalStorageGb" - [(ngModel)]="additionalStorage" + name="additionalStorageGb" + formControlName="additionalStorage" min="0" max="99" step="1" @@ -238,8 +187,8 @@ id="premiumAccess" class="form-check-input" type="checkbox" - name="PremiumAccessAddon" - [(ngModel)]="premiumAccessAddon" + name="premiumAccessAddon" + formControlName="premiumAccessAddon" />
    diff --git a/apps/web/src/app/organizations/policies/master-password.component.html b/apps/web/src/app/organizations/policies/master-password.component.html index 5fdb1053321..6d806f84b5d 100644 --- a/apps/web/src/app/organizations/policies/master-password.component.html +++ b/apps/web/src/app/organizations/policies/master-password.component.html @@ -12,7 +12,7 @@ [formControl]="enabled" name="Enabled" /> - +
    diff --git a/apps/web/src/app/organizations/policies/master-password.component.ts b/apps/web/src/app/organizations/policies/master-password.component.ts index 663e3ee7dd3..42cfcafe667 100644 --- a/apps/web/src/app/organizations/policies/master-password.component.ts +++ b/apps/web/src/app/organizations/policies/master-password.component.ts @@ -8,7 +8,7 @@ import { PolicyType } from "@bitwarden/common/enums/policyType"; import { BasePolicy, BasePolicyComponent } from "./base-policy.component"; export class MasterPasswordPolicy extends BasePolicy { - name = "masterPass"; + name = "masterPassPolicyTitle"; description = "masterPassPolicyDesc"; type = PolicyType.MasterPassword; component = MasterPasswordPolicyComponent; diff --git a/apps/web/src/app/organizations/policies/password-generator.component.html b/apps/web/src/app/organizations/policies/password-generator.component.html index 2d9fa14f00a..350f7da7b4b 100644 --- a/apps/web/src/app/organizations/policies/password-generator.component.html +++ b/apps/web/src/app/organizations/policies/password-generator.component.html @@ -8,7 +8,7 @@ [formControl]="enabled" name="Enabled" /> - + diff --git a/apps/web/src/app/organizations/policies/personal-ownership.component.html b/apps/web/src/app/organizations/policies/personal-ownership.component.html index add197df9a2..34cf1b5aa5f 100644 --- a/apps/web/src/app/organizations/policies/personal-ownership.component.html +++ b/apps/web/src/app/organizations/policies/personal-ownership.component.html @@ -11,8 +11,6 @@ [formControl]="enabled" name="Enabled" /> - + diff --git a/apps/web/src/app/organizations/policies/require-sso.component.html b/apps/web/src/app/organizations/policies/require-sso.component.html index 85d60f41b60..095b12ff366 100644 --- a/apps/web/src/app/organizations/policies/require-sso.component.html +++ b/apps/web/src/app/organizations/policies/require-sso.component.html @@ -14,6 +14,6 @@ [formControl]="enabled" name="Enabled" /> - + diff --git a/apps/web/src/app/organizations/policies/reset-password.component.html b/apps/web/src/app/organizations/policies/reset-password.component.html index 5e911deb0b0..f8d99180599 100644 --- a/apps/web/src/app/organizations/policies/reset-password.component.html +++ b/apps/web/src/app/organizations/policies/reset-password.component.html @@ -15,7 +15,7 @@ [formControl]="enabled" name="Enabled" /> - + diff --git a/apps/web/src/app/organizations/policies/send-options.component.html b/apps/web/src/app/organizations/policies/send-options.component.html index f204cc8e57a..c2e5ae8a34c 100644 --- a/apps/web/src/app/organizations/policies/send-options.component.html +++ b/apps/web/src/app/organizations/policies/send-options.component.html @@ -11,7 +11,7 @@ [formControl]="enabled" name="Enabled" /> - + diff --git a/apps/web/src/app/organizations/policies/single-org.component.html b/apps/web/src/app/organizations/policies/single-org.component.html index e11ac3f0578..a270adcfc00 100644 --- a/apps/web/src/app/organizations/policies/single-org.component.html +++ b/apps/web/src/app/organizations/policies/single-org.component.html @@ -11,6 +11,6 @@ [formControl]="enabled" name="Enabled" /> - + diff --git a/apps/web/src/app/organizations/policies/two-factor-authentication.component.html b/apps/web/src/app/organizations/policies/two-factor-authentication.component.html index 1b97ab3616b..3286c086894 100644 --- a/apps/web/src/app/organizations/policies/two-factor-authentication.component.html +++ b/apps/web/src/app/organizations/policies/two-factor-authentication.component.html @@ -11,6 +11,6 @@ [formControl]="enabled" name="Enabled" /> - + diff --git a/apps/web/src/app/organizations/policies/two-factor-authentication.component.ts b/apps/web/src/app/organizations/policies/two-factor-authentication.component.ts index d01d9b0a5a1..d1c4df60d42 100644 --- a/apps/web/src/app/organizations/policies/two-factor-authentication.component.ts +++ b/apps/web/src/app/organizations/policies/two-factor-authentication.component.ts @@ -5,7 +5,7 @@ import { PolicyType } from "@bitwarden/common/enums/policyType"; import { BasePolicy, BasePolicyComponent } from "./base-policy.component"; export class TwoFactorAuthenticationPolicy extends BasePolicy { - name = "twoStepLogin"; + name = "twoStepLoginPolicyTitle"; description = "twoStepLoginPolicyDesc"; type = PolicyType.TwoFactorAuthentication; component = TwoFactorAuthenticationPolicyComponent; diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index c9ffaf9b01f..0a49f2918fb 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -891,7 +891,7 @@ "message": "Your vault data has been exported." }, "passwordGenerator": { - "message": "Password Generator" + "message": "Password generator" }, "minComplexityScore": { "message": "Minimum Complexity Score" @@ -1223,7 +1223,7 @@ "message": "Domains updated" }, "twoStepLogin": { - "message": "Two-step Login" + "message": "Two-step login" }, "twoStepLoginDesc": { "message": "Secure your account by requiring an additional step when logging in." @@ -3342,20 +3342,26 @@ "clone": { "message": "Clone" }, + "masterPassPolicyTitle": { + "message": "Master password requirements" + }, "masterPassPolicyDesc": { - "message": "Set minimum requirements for master password strength." + "message": "Set requirements for master password strength." + }, + "twoStepLoginPolicyTitle": { + "message": "Require two-step login" }, "twoStepLoginPolicyDesc": { - "message": "Require users to set up two-step login on their personal accounts." + "message": "Require members to set up two-step login." }, "twoStepLoginPolicyWarning": { - "message": "Organization members who are not Owners or Administrators and do not have two-step login enabled for their personal account will be removed from the organization and will receive an email notifying them about the change." + "message": "Organization members who are not Owners or Administrators and do not have two-step login turned on for their account will be removed from the organization and will receive an email notifying them about the change." }, "twoStepLoginPolicyUserWarning": { "message": "You are a member of an organization that requires two-step login to be enabled on your user account. If you disable all two-step login providers you will be automatically removed from these organizations." }, "passwordGeneratorPolicyDesc": { - "message": "Set minimum requirements for password generator configuration." + "message": "Set requirements for password generator." }, "passwordGeneratorPolicyInEffect": { "message": "One or more organization policies are affecting your generator settings." @@ -3573,10 +3579,10 @@ "message": "Link SSO" }, "singleOrg": { - "message": "Single Organization" + "message": "Single organization" }, "singleOrgDesc": { - "message": "Restrict users from being able to join any other organizations." + "message": "Restrict members from joining other organizations." }, "singleOrgBlockCreateMessage": { "message": "Your current organization has a policy that does not allow you to join more than one organization. Please contact your organization admins or sign up from a different Bitwarden account." @@ -3585,16 +3591,16 @@ "message": "Organization members who are not Owners or Administrators and are already a member of another organization will be removed from your organization." }, "requireSso": { - "message": "Single Sign-On Authentication" + "message": "Require single sign-on authentication" }, "requireSsoPolicyDesc": { - "message": "Require users to log in with the Enterprise Single Sign-On method." + "message": "Require members to log in with the Enterprise Single Sign-On method." }, "prerequisite": { "message": "Prerequisite" }, "requireSsoPolicyReq": { - "message": "The Single Organization enterprise policy must be enabled before activating this policy." + "message": "The Single Organization enterprise policy must be turned on before activating this policy." }, "requireSsoPolicyReqError": { "message": "Single Organization policy not enabled." @@ -3889,10 +3895,10 @@ } }, "personalOwnership": { - "message": "Personal Ownership" + "message": "Remove individual vault" }, "personalOwnershipPolicyDesc": { - "message": "Require users to save vault items to an organization by removing the personal ownership option." + "message": "Require members to save items to an organization by removing the individual vault option." }, "personalOwnershipExemption": { "message": "Organization Owners and Administrators are exempt from this policy's enforcement." @@ -3901,10 +3907,10 @@ "message": "Due to an enterprise policy, you are restricted from saving items to your personal vault. Change the Ownership option to an organization and choose from available Collections." }, "disableSend": { - "message": "Disable Send" + "message": "Remove Send" }, "disableSendPolicyDesc": { - "message": "Do not allow users to create or edit a Bitwarden Send. Deleting an existing Send is still allowed.", + "message": "Do not allow members to create or edit sends.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "disableSendExemption": { @@ -3919,7 +3925,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendOptions": { - "message": "Send Options", + "message": "Send options", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendOptionsPolicyDesc": { @@ -3930,7 +3936,7 @@ "message": "Organization users that can manage the organization's policies are exempt from this policy's enforcement." }, "disableHideEmail": { - "message": "Do not allow users to hide their email address from recipients when creating or editing a Send.", + "message": "Always show member’s email address with recipients when creating or editing a send.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendOptionsPolicyInEffect": { @@ -4226,10 +4232,10 @@ "message": "Enrollment will allow organization administrators to change your master password" }, "resetPasswordPolicy": { - "message": "Master Password Reset" + "message": "Master password reset" }, "resetPasswordPolicyDescription": { - "message": "Allow administrators in the organization to reset organization users' master password." + "message": "Allow admins to reset master passwords for members." }, "resetPasswordPolicyWarning": { "message": "Users in the organization will need to self-enroll or be auto-enrolled before administrators can reset their master password." @@ -4473,10 +4479,10 @@ "message": "Your Master Password does not meet the policy requirements of this organization. In order to join the organization, you must update your Master Password now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour." }, "maximumVaultTimeout": { - "message": "Vault Timeout" + "message": "Vault timeout" }, "maximumVaultTimeoutDesc": { - "message": "Configure a maximum vault timeout for all users." + "message": "Set a maximum vault timeout for members." }, "maximumVaultTimeoutLabel": { "message": "Maximum Vault Timeout" @@ -4516,10 +4522,10 @@ "message": "Vault Timeout is not within allowed range." }, "disablePersonalVaultExport": { - "message": "Disable Personal Vault Export" + "message": "Remove individual vault export" }, "disablePersonalVaultExportDesc": { - "message": "Prohibits users from exporting their private vault data." + "message": "Do not allow members to export their individual vault data." }, "vaultExportDisabled": { "message": "Vault Export Disabled" @@ -4810,19 +4816,19 @@ "message": "Once set up, your configuration will be saved and members will be able to authenticate using their Identity Provider credentials." }, "ssoPolicyHelpStart": { - "message": "Enable the", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Enable the SSO Authentication policy to require all members to log in with SSO.'" + "message": "Use the", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'" }, "ssoPolicyHelpLink": { - "message": "SSO Authentication policy", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Enable the SSO Authentication policy to require all members to log in with SSO.'" + "message": "require single-sign-on authentication policy", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'" }, "ssoPolicyHelpEnd": { "message": "to require all members to log in with SSO.", - "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Enable the SSO Authentication policy to require all members to log in with SSO.'" + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'" }, "ssoPolicyHelpKeyConnector": { - "message": "SSO Authentication and Single Organization policies are required to set up Key Connector decryption." + "message": "The require SSO authentication and single organization policies are required to set up Key Connector decryption." }, "memberDecryptionOption": { "message": "Member Decryption Options" @@ -5198,5 +5204,11 @@ "example": "4" } } + }, + "turnOn": { + "message": "Turn on" + }, + "on": { + "message": "On" } } diff --git a/bitwarden_license/bit-web/src/app/policies/disable-personal-vault-export.component.html b/bitwarden_license/bit-web/src/app/policies/disable-personal-vault-export.component.html index 317a9c8f1d4..3db81efc48a 100644 --- a/bitwarden_license/bit-web/src/app/policies/disable-personal-vault-export.component.html +++ b/bitwarden_license/bit-web/src/app/policies/disable-personal-vault-export.component.html @@ -7,6 +7,6 @@ [formControl]="enabled" name="Enabled" /> - + diff --git a/bitwarden_license/bit-web/src/app/policies/maximum-vault-timeout.component.html b/bitwarden_license/bit-web/src/app/policies/maximum-vault-timeout.component.html index 344cf009ec0..c2c42718e2f 100644 --- a/bitwarden_license/bit-web/src/app/policies/maximum-vault-timeout.component.html +++ b/bitwarden_license/bit-web/src/app/policies/maximum-vault-timeout.component.html @@ -11,7 +11,7 @@ [formControl]="enabled" name="Enabled" /> - + From f6571346c2695ef4aa326564e94cd264026dd8a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Tom=C3=A9?= <108268980+r-tome@users.noreply.github.com> Date: Mon, 11 Jul 2022 11:25:30 +0100 Subject: [PATCH 28/86] Updated the Delete account modal description (#3064) --- apps/web/src/locales/en/messages.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 0a49f2918fb..a00b34346b6 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -1076,7 +1076,7 @@ "message": "Delete Account" }, "deleteAccountDesc": { - "message": "Proceed below to delete your account and all associated data." + "message": "Proceed below to delete your account and all vault data." }, "deleteAccountWarning": { "message": "Deleting your account is permanent. It cannot be undone." From c0bcdf46376a30b923ef2aff116a87a9d4813e31 Mon Sep 17 00:00:00 2001 From: Robyn MacCallum Date: Mon, 11 Jul 2022 11:03:44 -0400 Subject: [PATCH 29/86] Get full cipher details when update cipher notification is received (#3063) --- libs/common/src/abstractions/api.service.ts | 1 + libs/common/src/services/api.service.ts | 5 +++++ libs/common/src/services/sync.service.ts | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libs/common/src/abstractions/api.service.ts b/libs/common/src/abstractions/api.service.ts index 8405c533663..24517be5228 100644 --- a/libs/common/src/abstractions/api.service.ts +++ b/libs/common/src/abstractions/api.service.ts @@ -262,6 +262,7 @@ export abstract class ApiService { renewSendFileUploadUrl: (sendId: string, fileId: string) => Promise; getCipher: (id: string) => Promise; + getFullCipherDetails: (id: string) => Promise; getCipherAdmin: (id: string) => Promise; getAttachmentData: ( cipherId: string, diff --git a/libs/common/src/services/api.service.ts b/libs/common/src/services/api.service.ts index 7cf4964caf9..ab41555d9c5 100644 --- a/libs/common/src/services/api.service.ts +++ b/libs/common/src/services/api.service.ts @@ -589,6 +589,11 @@ export class ApiService implements ApiServiceAbstraction { return new CipherResponse(r); } + async getFullCipherDetails(id: string): Promise { + const r = await this.send("GET", "/ciphers/" + id + "/details", null, true, true); + return new CipherResponse(r); + } + async getCipherAdmin(id: string): Promise { const r = await this.send("GET", "/ciphers/" + id + "/admin", null, true, true); return new CipherResponse(r); diff --git a/libs/common/src/services/sync.service.ts b/libs/common/src/services/sync.service.ts index 8a061bcbb17..b96ff24d392 100644 --- a/libs/common/src/services/sync.service.ts +++ b/libs/common/src/services/sync.service.ts @@ -198,7 +198,7 @@ export class SyncService implements SyncServiceAbstraction { } if (shouldUpdate) { - const remoteCipher = await this.apiService.getCipher(notification.id); + const remoteCipher = await this.apiService.getFullCipherDetails(notification.id); if (remoteCipher != null) { await this.cipherService.upsert(new CipherData(remoteCipher)); this.messagingService.send("syncedUpsertedCipher", { cipherId: notification.id }); From 5ed6b9fb74b37d09077b23968b2f83151dde537e Mon Sep 17 00:00:00 2001 From: Robyn MacCallum Date: Mon, 11 Jul 2022 11:06:32 -0400 Subject: [PATCH 30/86] Implement create account step (#3073) --- .../trial-initiation/trial-initiation.component.html | 11 ++++++----- .../trial-initiation/trial-initiation.component.ts | 10 +++++++++- .../trial-initiation/trial-initiation.module.ts | 9 ++++++++- libs/angular/src/components/register.component.ts | 11 +++++++++-- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/apps/web/src/app/modules/trial-initiation/trial-initiation.component.html b/apps/web/src/app/modules/trial-initiation/trial-initiation.component.html index 7e6be8485cf..7f94c3ffaee 100644 --- a/apps/web/src/app/modules/trial-initiation/trial-initiation.component.html +++ b/apps/web/src/app/modules/trial-initiation/trial-initiation.component.html @@ -28,12 +28,13 @@ Start your 7-Day free trial of Bitwarden for {{ org }} - + - - -

    This is content of "Step 1" that has editable set to false

    - + + diff --git a/apps/web/src/app/modules/trial-initiation/trial-initiation.component.ts b/apps/web/src/app/modules/trial-initiation/trial-initiation.component.ts index b3b00f1771d..b8c5a75acf6 100644 --- a/apps/web/src/app/modules/trial-initiation/trial-initiation.component.ts +++ b/apps/web/src/app/modules/trial-initiation/trial-initiation.component.ts @@ -1,7 +1,9 @@ -import { Component, OnInit } from "@angular/core"; +import { Component, OnInit, ViewChild } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { first } from "rxjs"; +import { VerticalStepperComponent } from "../vertical-stepper/vertical-stepper.component"; + @Component({ selector: "app-trial", templateUrl: "trial-initiation.component.html", @@ -9,6 +11,7 @@ import { first } from "rxjs"; export class TrialInitiationComponent implements OnInit { email = ""; org = "teams"; + @ViewChild("stepper", { static: true }) verticalStepper: VerticalStepperComponent; constructor(private route: ActivatedRoute) {} @@ -22,4 +25,9 @@ export class TrialInitiationComponent implements OnInit { } }); } + + createdAccount(email: string) { + this.email = email; + this.verticalStepper.next(); + } } diff --git a/apps/web/src/app/modules/trial-initiation/trial-initiation.module.ts b/apps/web/src/app/modules/trial-initiation/trial-initiation.module.ts index 35370acb50b..9b091ed4c99 100644 --- a/apps/web/src/app/modules/trial-initiation/trial-initiation.module.ts +++ b/apps/web/src/app/modules/trial-initiation/trial-initiation.module.ts @@ -3,6 +3,7 @@ import { NgModule } from "@angular/core"; import { FormFieldModule } from "@bitwarden/components"; +import { RegisterFormModule } from "../register-form/register-form.module"; import { SharedModule } from "../shared.module"; import { VerticalStepperModule } from "../vertical-stepper/vertical-stepper.module"; @@ -12,7 +13,13 @@ import { TeamsContentComponent } from "./teams-content.component"; import { TrialInitiationComponent } from "./trial-initiation.component"; @NgModule({ - imports: [SharedModule, CdkStepperModule, VerticalStepperModule, FormFieldModule], + imports: [ + SharedModule, + CdkStepperModule, + VerticalStepperModule, + FormFieldModule, + RegisterFormModule, + ], declarations: [ TrialInitiationComponent, EnterpriseContentComponent, diff --git a/libs/angular/src/components/register.component.ts b/libs/angular/src/components/register.component.ts index 15694ec8383..50d7f8a1502 100644 --- a/libs/angular/src/components/register.component.ts +++ b/libs/angular/src/components/register.component.ts @@ -1,4 +1,4 @@ -import { Directive, OnInit } from "@angular/core"; +import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { FormBuilder, Validators } from "@angular/forms"; import { Router } from "@angular/router"; @@ -28,6 +28,9 @@ import { CaptchaProtectedComponent } from "./captchaProtected.component"; @Directive() export class RegisterComponent extends CaptchaProtectedComponent implements OnInit { + @Input() isInTrialFlow = false; + @Output() createdAccount = new EventEmitter(); + showPassword = false; formPromise: Promise; masterPasswordScore: number; @@ -194,7 +197,11 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn } } this.platformUtilsService.showToast("success", null, this.i18nService.t("newAccountCreated")); - this.router.navigate([this.successRoute], { queryParams: { email: email } }); + if (this.isInTrialFlow) { + this.createdAccount.emit(this.formGroup.get("email")?.value); + } else { + this.router.navigate([this.successRoute], { queryParams: { email: email } }); + } } catch (e) { this.logService.error(e); } From 543c84d0fa364deba023fcf859bf1c07e53941c2 Mon Sep 17 00:00:00 2001 From: Gbubemi Smith Date: Mon, 11 Jul 2022 19:58:38 +0100 Subject: [PATCH 31/86] renamed minlength error key (#3077) --- apps/browser/src/_locales/en/messages.json | 2 +- apps/desktop/src/locales/en/messages.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index baa4e0066c3..20298701d41 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -429,7 +429,7 @@ "confirmMasterPasswordRequired": { "message": "Master password retype is required." }, - "masterPasswordMinLength": { + "masterPasswordMinlength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index 94c44b53eb1..64c1b443d48 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -538,7 +538,7 @@ "confirmMasterPasswordRequired": { "message": "Master password retype is required." }, - "masterPasswordMinLength": { + "masterPasswordMinlength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { From 9bf27a20502e691f9909ea2b3da84f1754c7da51 Mon Sep 17 00:00:00 2001 From: Gbubemi Smith Date: Mon, 11 Jul 2022 19:58:56 +0100 Subject: [PATCH 32/86] [SG-420] Fixed password match defect (#3075) * fixed password match defect * change custom validator to static methods --- .../src/components/register.component.ts | 46 ++++++++------- .../validators/fieldsInputCheck.validator.ts | 37 ------------ .../validators/inputsFieldMatch.validator.ts | 57 +++++++++++++++++++ 3 files changed, 82 insertions(+), 58 deletions(-) delete mode 100644 libs/angular/src/validators/fieldsInputCheck.validator.ts create mode 100644 libs/angular/src/validators/inputsFieldMatch.validator.ts diff --git a/libs/angular/src/components/register.component.ts b/libs/angular/src/components/register.component.ts index 50d7f8a1502..b07891371bd 100644 --- a/libs/angular/src/components/register.component.ts +++ b/libs/angular/src/components/register.component.ts @@ -2,10 +2,7 @@ import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { FormBuilder, Validators } from "@angular/forms"; import { Router } from "@angular/router"; -import { - validateInputsDoesntMatch, - validateInputsMatch, -} from "@bitwarden/angular/validators/fieldsInputCheck.validator"; +import { InputsFieldMatch } from "@bitwarden/angular/validators/inputsFieldMatch.validator"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuthService } from "@bitwarden/common/abstractions/auth.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; @@ -38,24 +35,31 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn showTerms = true; showErrorSummary = false; - formGroup = this.formBuilder.group({ - email: ["", [Validators.required, Validators.email]], - name: [""], - masterPassword: ["", [Validators.required, Validators.minLength(8)]], - confirmMasterPassword: [ - "", - [ - Validators.required, - Validators.minLength(8), - validateInputsMatch("masterPassword", this.i18nService.t("masterPassDoesntMatch")), + formGroup = this.formBuilder.group( + { + email: ["", [Validators.required, Validators.email]], + name: [""], + masterPassword: ["", [Validators.required, Validators.minLength(8)]], + confirmMasterPassword: ["", [Validators.required, Validators.minLength(8)]], + hint: [ + null, + [ + InputsFieldMatch.validateInputsDoesntMatch( + "masterPassword", + this.i18nService.t("hintEqualsPassword") + ), + ], ], - ], - hint: [ - null, - [validateInputsDoesntMatch("masterPassword", this.i18nService.t("hintEqualsPassword"))], - ], - acceptPolicies: [false, [Validators.requiredTrue]], - }); + acceptPolicies: [false, [Validators.requiredTrue]], + }, + { + validator: InputsFieldMatch.validateFormInputsMatch( + "masterPassword", + "confirmMasterPassword", + this.i18nService.t("masterPassDoesntMatch") + ), + } + ); protected successRoute = "login"; private masterPasswordStrengthTimeout: any; diff --git a/libs/angular/src/validators/fieldsInputCheck.validator.ts b/libs/angular/src/validators/fieldsInputCheck.validator.ts deleted file mode 100644 index ac1b4d5a404..00000000000 --- a/libs/angular/src/validators/fieldsInputCheck.validator.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { AbstractControl, ValidatorFn } from "@angular/forms"; - -import { FormGroupControls } from "@bitwarden/common/abstractions/formValidationErrors.service"; - -//check to ensure two fields do not have the same value -export function validateInputsDoesntMatch(matchTo: string, errorMessage: string): ValidatorFn { - return (control: AbstractControl) => { - if (control.parent && control.parent.controls) { - return control?.value === (control?.parent?.controls as FormGroupControls)[matchTo].value - ? { - inputsMatchError: { - message: errorMessage, - }, - } - : null; - } - - return null; - }; -} - -//check to ensure two fields have the same value -export function validateInputsMatch(matchTo: string, errorMessage: string): ValidatorFn { - return (control: AbstractControl) => { - if (control.parent && control.parent.controls) { - return control?.value === (control?.parent?.controls as FormGroupControls)[matchTo].value - ? null - : { - inputsDoesntMatchError: { - message: errorMessage, - }, - }; - } - - return null; - }; -} diff --git a/libs/angular/src/validators/inputsFieldMatch.validator.ts b/libs/angular/src/validators/inputsFieldMatch.validator.ts new file mode 100644 index 00000000000..9ef1ab789df --- /dev/null +++ b/libs/angular/src/validators/inputsFieldMatch.validator.ts @@ -0,0 +1,57 @@ +import { AbstractControl, FormGroup, ValidatorFn } from "@angular/forms"; + +import { FormGroupControls } from "@bitwarden/common/abstractions/formValidationErrors.service"; + +export class InputsFieldMatch { + //check to ensure two fields do not have the same value + static validateInputsDoesntMatch(matchTo: string, errorMessage: string): ValidatorFn { + return (control: AbstractControl) => { + if (control.parent && control.parent.controls) { + return control?.value === (control?.parent?.controls as FormGroupControls)[matchTo].value + ? { + inputsMatchError: { + message: errorMessage, + }, + } + : null; + } + + return null; + }; + } + + //check to ensure two fields have the same value + static validateInputsMatch(matchTo: string, errorMessage: string): ValidatorFn { + return (control: AbstractControl) => { + if (control.parent && control.parent.controls) { + return control?.value === (control?.parent?.controls as FormGroupControls)[matchTo].value + ? null + : { + inputsDoesntMatchError: { + message: errorMessage, + }, + }; + } + + return null; + }; + } + + //checks the formGroup if two fields have the same value and validation is controlled from either field + static validateFormInputsMatch(field: string, fieldMatchTo: string, errorMessage: string) { + return (formGroup: FormGroup) => { + const fieldCtrl = formGroup.controls[field]; + const fieldMatchToCtrl = formGroup.controls[fieldMatchTo]; + + if (fieldCtrl.value !== fieldMatchToCtrl.value) { + fieldMatchToCtrl.setErrors({ + inputsDoesntMatchError: { + message: errorMessage, + }, + }); + } else { + fieldMatchToCtrl.setErrors(null); + } + }; + } +} From 94cba4b917ef92b96cf588021907111e9ad2f604 Mon Sep 17 00:00:00 2001 From: Joseph Flinn <58369717+joseph-flinn@users.noreply.github.com> Date: Mon, 11 Jul 2022 14:14:52 -0700 Subject: [PATCH 33/86] Web Version Bump 2022.6.2 (#3085) --- apps/web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/package.json b/apps/web/package.json index 52492d800dd..0a35321979b 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/web-vault", - "version": "2022.6.1", + "version": "2022.6.2", "scripts": { "build:oss": "webpack", "build:bit": "webpack -c ../../bitwarden_license/bit-web/webpack.config.js", From b864bdab6ebf0a8741b013a2158050bc958a93bc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 14:17:13 -0700 Subject: [PATCH 34/86] Bumped desktop version to 2022.6.2 (#3084) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- apps/desktop/src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/src/package.json b/apps/desktop/src/package.json index 7108dae48c9..af9581ca24b 100644 --- a/apps/desktop/src/package.json +++ b/apps/desktop/src/package.json @@ -2,7 +2,7 @@ "name": "@bitwarden/desktop", "productName": "Bitwarden", "description": "A secure and free password manager for all of your devices.", - "version": "2022.6.1", + "version": "2022.6.2", "author": "Bitwarden Inc. (https://bitwarden.com)", "homepage": "https://bitwarden.com", "license": "GPL-3.0", From 35adf9d6e9833a70b8ee81ded50024d736758f3e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 11 Jul 2022 15:40:56 -0700 Subject: [PATCH 35/86] Bumped desktop version to 2022.6.3 (#3087) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- apps/desktop/src/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/src/package.json b/apps/desktop/src/package.json index af9581ca24b..3c686dd46dd 100644 --- a/apps/desktop/src/package.json +++ b/apps/desktop/src/package.json @@ -2,7 +2,7 @@ "name": "@bitwarden/desktop", "productName": "Bitwarden", "description": "A secure and free password manager for all of your devices.", - "version": "2022.6.2", + "version": "2022.6.3", "author": "Bitwarden Inc. (https://bitwarden.com)", "homepage": "https://bitwarden.com", "license": "GPL-3.0", From 59eac668a7b045f22c4df29dfde3d99d77916da7 Mon Sep 17 00:00:00 2001 From: Colton Hurst Date: Tue, 12 Jul 2022 09:02:19 -0400 Subject: [PATCH 36/86] [PS-713] Fix locale search bug (#3014) * [PS-713] Fix locale search bug * [PS-713] Add new locales to start at 1 char search * [PS-713] Switch to ReplaySubject and other edits from PR comments * PS-713: Add destroy to other sub and make locale inline a const * PS-713: Use firstValueFrom instead of takeUntil * PS-713: get this.locale asynchronously Co-authored-by: Colton Hurst --- apps/web/src/app/app.component.ts | 10 ++++++++-- .../app/settings/sponsoring-org-row.component.ts | 9 +++++++-- libs/common/src/abstractions/i18n.service.ts | 4 +++- libs/common/src/services/i18n.service.ts | 13 ++++++++++--- libs/common/src/services/search.service.ts | 15 +++++++++++---- libs/components/src/utils/i18n-mock.service.ts | 4 +++- 6 files changed, 42 insertions(+), 13 deletions(-) diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts index b29823f53e9..7c02076191c 100644 --- a/apps/web/src/app/app.component.ts +++ b/apps/web/src/app/app.component.ts @@ -4,6 +4,7 @@ import { DomSanitizer } from "@angular/platform-browser"; import { NavigationEnd, Router } from "@angular/router"; import * as jq from "jquery"; import { IndividualConfig, ToastrService } from "ngx-toastr"; +import { Subject, takeUntil } from "rxjs"; import Swal from "sweetalert2"; import { AuthService } from "@bitwarden/common/abstractions/auth.service"; @@ -48,6 +49,7 @@ export class AppComponent implements OnDestroy, OnInit { private lastActivity: number = null; private idleTimer: number = null; private isIdle = false; + private destroy$ = new Subject(); constructor( @Inject(DOCUMENT) private document: Document, @@ -78,7 +80,9 @@ export class AppComponent implements OnDestroy, OnInit { ) {} ngOnInit() { - this.document.documentElement.lang = this.i18nService.locale; + this.i18nService.locale$.pipe(takeUntil(this.destroy$)).subscribe((locale) => { + this.document.documentElement.lang = locale; + }); this.ngZone.runOutsideAngular(() => { window.onmousemove = () => this.recordActivity(); @@ -181,7 +185,7 @@ export class AppComponent implements OnDestroy, OnInit { }); }); - this.router.events.subscribe((event) => { + this.router.events.pipe(takeUntil(this.destroy$)).subscribe((event) => { if (event instanceof NavigationEnd) { const modals = Array.from(document.querySelectorAll(".modal")); for (const modal of modals) { @@ -211,6 +215,8 @@ export class AppComponent implements OnDestroy, OnInit { ngOnDestroy() { this.broadcasterService.unsubscribe(BroadcasterSubscriptionId); + this.destroy$.next(); + this.destroy$.unsubscribe(); } private async logOut(expired: boolean) { diff --git a/apps/web/src/app/settings/sponsoring-org-row.component.ts b/apps/web/src/app/settings/sponsoring-org-row.component.ts index 4dabff04b60..db898e5cbac 100644 --- a/apps/web/src/app/settings/sponsoring-org-row.component.ts +++ b/apps/web/src/app/settings/sponsoring-org-row.component.ts @@ -1,5 +1,6 @@ import { formatDate } from "@angular/common"; import { Component, EventEmitter, Input, Output, OnInit } from "@angular/core"; +import { firstValueFrom } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; @@ -23,6 +24,8 @@ export class SponsoringOrgRowComponent implements OnInit { revokeSponsorshipPromise: Promise; resendEmailPromise: Promise; + private locale = ""; + constructor( private apiService: ApiService, private i18nService: I18nService, @@ -30,7 +33,9 @@ export class SponsoringOrgRowComponent implements OnInit { private platformUtilsService: PlatformUtilsService ) {} - ngOnInit(): void { + async ngOnInit() { + this.locale = await firstValueFrom(this.i18nService.locale$); + this.setStatus( this.isSelfHosted, this.sponsoringOrg.familySponsorshipToDelete, @@ -98,7 +103,7 @@ export class SponsoringOrgRowComponent implements OnInit { // They want to delete but there is a valid until date which means there is an active sponsorship this.statusMessage = this.i18nService.t( "revokeWhenExpired", - formatDate(validUntil, "MM/dd/yyyy", this.i18nService.locale) + formatDate(validUntil, "MM/dd/yyyy", this.locale) ); this.statusClass = "text-danger"; } else if (toDelete) { diff --git a/libs/common/src/abstractions/i18n.service.ts b/libs/common/src/abstractions/i18n.service.ts index 4706e0d1aa8..23f2d4fd235 100644 --- a/libs/common/src/abstractions/i18n.service.ts +++ b/libs/common/src/abstractions/i18n.service.ts @@ -1,5 +1,7 @@ +import { Observable } from "rxjs"; + export abstract class I18nService { - locale: string; + locale$: Observable; supportedTranslationLocales: string[]; translationLocale: string; collator: Intl.Collator; diff --git a/libs/common/src/services/i18n.service.ts b/libs/common/src/services/i18n.service.ts index fda8f839ead..9281cc8cf4d 100644 --- a/libs/common/src/services/i18n.service.ts +++ b/libs/common/src/services/i18n.service.ts @@ -1,7 +1,10 @@ +import { Observable, ReplaySubject } from "rxjs"; + import { I18nService as I18nServiceAbstraction } from "../abstractions/i18n.service"; export class I18nService implements I18nServiceAbstraction { - locale: string; + private _locale = new ReplaySubject(1); + locale$: Observable = this._locale.asObservable(); // First locale is the default (English) supportedTranslationLocales: string[] = ["en"]; translationLocale: string; @@ -85,10 +88,14 @@ export class I18nService implements I18nServiceAbstraction { } this.inited = true; - this.locale = this.translationLocale = locale != null ? locale : this.systemLanguage; + this.translationLocale = locale != null ? locale : this.systemLanguage; + this._locale.next(this.translationLocale); try { - this.collator = new Intl.Collator(this.locale, { numeric: true, sensitivity: "base" }); + this.collator = new Intl.Collator(this.translationLocale, { + numeric: true, + sensitivity: "base", + }); } catch { this.collator = null; } diff --git a/libs/common/src/services/search.service.ts b/libs/common/src/services/search.service.ts index c020dd299f9..fe2c87c33d8 100644 --- a/libs/common/src/services/search.service.ts +++ b/libs/common/src/services/search.service.ts @@ -14,16 +14,23 @@ export class SearchService implements SearchServiceAbstraction { indexedEntityId?: string = null; private indexing = false; private index: lunr.Index = null; - private searchableMinLength = 2; + private readonly immediateSearchLocales: string[] = ["zh-CN", "zh-TW", "ja", "ko", "vi"]; + private readonly defaultSearchableMinLength: number = 2; + private searchableMinLength: number = this.defaultSearchableMinLength; constructor( private cipherService: CipherService, private logService: LogService, private i18nService: I18nService ) { - if (["zh-CN", "zh-TW"].indexOf(i18nService.locale) !== -1) { - this.searchableMinLength = 1; - } + this.i18nService.locale$.subscribe((locale) => { + if (this.immediateSearchLocales.indexOf(locale) !== -1) { + this.searchableMinLength = 1; + } else { + this.searchableMinLength = this.defaultSearchableMinLength; + } + }); + //register lunr pipeline function lunr.Pipeline.registerFunction(this.normalizeAccentsPipelineFunction, "normalizeAccents"); } diff --git a/libs/components/src/utils/i18n-mock.service.ts b/libs/components/src/utils/i18n-mock.service.ts index ffc2b031d37..19f756fc360 100644 --- a/libs/components/src/utils/i18n-mock.service.ts +++ b/libs/components/src/utils/i18n-mock.service.ts @@ -1,7 +1,9 @@ +import { Observable } from "rxjs"; + import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; export class I18nMockService implements I18nService { - locale: string; + locale$: Observable; supportedTranslationLocales: string[]; translationLocale: string; collator: Intl.Collator; From 31a5fdbebbb597779cc38f67dfbc3ee0a5166f42 Mon Sep 17 00:00:00 2001 From: Robyn MacCallum Date: Tue, 12 Jul 2022 13:27:03 -0400 Subject: [PATCH 37/86] [SG-68] Implement org info step (#3083) * Implement org info step * Set org info sub label properly --- .../trial-initiation.component.html | 17 +++++++---- .../trial-initiation.component.ts | 29 ++++++++++++++++++- .../trial-initiation.module.ts | 4 +++ 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/apps/web/src/app/modules/trial-initiation/trial-initiation.component.html b/apps/web/src/app/modules/trial-initiation/trial-initiation.component.html index 7f94c3ffaee..b0c98486dc8 100644 --- a/apps/web/src/app/modules/trial-initiation/trial-initiation.component.html +++ b/apps/web/src/app/modules/trial-initiation/trial-initiation.component.html @@ -28,18 +28,23 @@ Start your 7-Day free trial of Bitwarden for {{ org }} - - + - - -

    This is content of "Step 2"

    - + + + diff --git a/apps/web/src/app/modules/trial-initiation/trial-initiation.component.ts b/apps/web/src/app/modules/trial-initiation/trial-initiation.component.ts index b8c5a75acf6..0e6772ff3d2 100644 --- a/apps/web/src/app/modules/trial-initiation/trial-initiation.component.ts +++ b/apps/web/src/app/modules/trial-initiation/trial-initiation.component.ts @@ -1,4 +1,7 @@ +import { StepperSelectionEvent } from "@angular/cdk/stepper"; +import { TitleCasePipe } from "@angular/common"; import { Component, OnInit, ViewChild } from "@angular/core"; +import { FormBuilder, Validators } from "@angular/forms"; import { ActivatedRoute } from "@angular/router"; import { first } from "rxjs"; @@ -11,9 +14,23 @@ import { VerticalStepperComponent } from "../vertical-stepper/vertical-stepper.c export class TrialInitiationComponent implements OnInit { email = ""; org = "teams"; + orgInfoSubLabel = ""; @ViewChild("stepper", { static: true }) verticalStepper: VerticalStepperComponent; - constructor(private route: ActivatedRoute) {} + orgInfoFormGroup = this.formBuilder.group({ + name: ["", [Validators.required]], + additionalStorage: [0, [Validators.min(0), Validators.max(99)]], + additionalSeats: [0, [Validators.min(0), Validators.max(100000)]], + businessName: [""], + plan: [], + product: [], + }); + + constructor( + private route: ActivatedRoute, + private formBuilder: FormBuilder, + private titleCasePipe: TitleCasePipe + ) {} ngOnInit(): void { this.route.queryParams.pipe(first()).subscribe((qParams) => { @@ -26,6 +43,16 @@ export class TrialInitiationComponent implements OnInit { }); } + stepSelectionChange(event: StepperSelectionEvent) { + // Set org info sub label + if (event.selectedIndex === 1 && this.orgInfoFormGroup.controls.name.value === "") { + this.orgInfoSubLabel = + "Enter your " + this.titleCasePipe.transform(this.org) + " organization information"; + } else if (event.previouslySelectedIndex === 1) { + this.orgInfoSubLabel = this.orgInfoFormGroup.controls.name.value; + } + } + createdAccount(email: string) { this.email = email; this.verticalStepper.next(); diff --git a/apps/web/src/app/modules/trial-initiation/trial-initiation.module.ts b/apps/web/src/app/modules/trial-initiation/trial-initiation.module.ts index 9b091ed4c99..1df93915802 100644 --- a/apps/web/src/app/modules/trial-initiation/trial-initiation.module.ts +++ b/apps/web/src/app/modules/trial-initiation/trial-initiation.module.ts @@ -1,8 +1,10 @@ import { CdkStepperModule } from "@angular/cdk/stepper"; +import { TitleCasePipe } from "@angular/common"; import { NgModule } from "@angular/core"; import { FormFieldModule } from "@bitwarden/components"; +import { OrganizationCreateModule } from "../organizations/create/organization-create.module"; import { RegisterFormModule } from "../register-form/register-form.module"; import { SharedModule } from "../shared.module"; import { VerticalStepperModule } from "../vertical-stepper/vertical-stepper.module"; @@ -19,6 +21,7 @@ import { TrialInitiationComponent } from "./trial-initiation.component"; VerticalStepperModule, FormFieldModule, RegisterFormModule, + OrganizationCreateModule, ], declarations: [ TrialInitiationComponent, @@ -27,5 +30,6 @@ import { TrialInitiationComponent } from "./trial-initiation.component"; TeamsContentComponent, ], exports: [TrialInitiationComponent], + providers: [TitleCasePipe], }) export class TrialInitiationModule {} From a43aa9612c7fe5e0d492cce1ad52e686ee31947a Mon Sep 17 00:00:00 2001 From: Robyn MacCallum Date: Tue, 12 Jul 2022 13:58:33 -0400 Subject: [PATCH 38/86] Fix org upgrade issues (#3091) --- .../organization-information.component.html | 32 +++++++++++-------- .../organization-information.component.ts | 3 ++ .../organization-plans.component.html | 3 ++ .../settings/organization-plans.component.ts | 7 +++- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/apps/web/src/app/modules/organizations/create/organization-information.component.html b/apps/web/src/app/modules/organizations/create/organization-information.component.html index 7550bfbf4c6..6029cfd833a 100644 --- a/apps/web/src/app/modules/organizations/create/organization-information.component.html +++ b/apps/web/src/app/modules/organizations/create/organization-information.component.html @@ -6,7 +6,7 @@

    {{ "generalInformation" | i18n }}

    -
    +
    {{ "organizationName" | i18n }} @@ -15,18 +15,24 @@ {{ "billingEmail" | i18n }} -
    - - {{ "accountOwnedBusiness" | i18n }} -
    - - {{ "businessName" | i18n }} - + + {{ "clientOwnerEmail" | i18n }} +
    +
    + + {{ "accountOwnedBusiness" | i18n }} +
    + + {{ "businessName" | i18n }} + + +
    +
    diff --git a/apps/web/src/app/modules/organizations/create/organization-information.component.ts b/apps/web/src/app/modules/organizations/create/organization-information.component.ts index 5d35f6df8ac..bd59a472ed9 100644 --- a/apps/web/src/app/modules/organizations/create/organization-information.component.ts +++ b/apps/web/src/app/modules/organizations/create/organization-information.component.ts @@ -7,6 +7,9 @@ import { FormGroup } from "@angular/forms"; }) export class OrganizationInformationComponent { @Input() nameOnly = false; + @Input() createOrganization = true; + @Input() isProvider = false; + @Input() acceptingSponsorship = false; @Input() formGroup: FormGroup; @Output() changedBusinessOwned = new EventEmitter(); } diff --git a/apps/web/src/app/settings/organization-plans.component.html b/apps/web/src/app/settings/organization-plans.component.html index 4fe4c3263e8..827554ea533 100644 --- a/apps/web/src/app/settings/organization-plans.component.html +++ b/apps/web/src/app/settings/organization-plans.component.html @@ -34,6 +34,9 @@

    {{ "chooseYourPlan" | i18n }}

    diff --git a/apps/web/src/app/settings/organization-plans.component.ts b/apps/web/src/app/settings/organization-plans.component.ts index 72086a4d420..c894e3a2da0 100644 --- a/apps/web/src/app/settings/organization-plans.component.ts +++ b/apps/web/src/app/settings/organization-plans.component.ts @@ -58,7 +58,7 @@ export class OrganizationPlansComponent implements OnInit { premiumAccessAddon: [false], additionalStorage: [0, [Validators.min(0), Validators.max(99)]], additionalSeats: [0, [Validators.min(0), Validators.max(100000)]], - clientOwnerEmail: [""], + clientOwnerEmail: ["", [Validators.email]], businessName: [""], plan: [this.plan], product: [this.product], @@ -96,6 +96,11 @@ export class OrganizationPlansComponent implements OnInit { this.changedOwnedBusiness(); } + if (!this.createOrganization) { + this.formGroup.controls.product.setValue(ProductType.Families); + this.changedProduct(); + } + this.loading = false; } From 23253b38828e330854353b621f952d17bc2da03b Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Tue, 12 Jul 2022 20:25:18 +0200 Subject: [PATCH 39/86] [PS-1078] Refactor FolderService to use Observables (#3022) --- .../browser/src/background/main.background.ts | 6 +- .../src/background/notification.background.ts | 6 +- .../src/popup/services/services.module.ts | 5 + .../src/popup/settings/folders.component.html | 6 +- .../src/popup/settings/folders.component.ts | 23 ++- .../src/popup/vault/add-edit.component.html | 2 +- .../src/popup/vault/ciphers.component.ts | 2 +- .../src/popup/vault/vault-filter.component.ts | 7 +- apps/cli/src/bw.ts | 7 +- apps/cli/src/commands/get.command.ts | 4 +- apps/cli/src/commands/list.command.ts | 4 +- .../vault-filter/vault-filter.component.html | 2 +- .../src/app/vault/add-edit.component.html | 2 +- .../vault-filter/vault-filter.component.html | 2 +- .../app/settings/change-password.component.ts | 3 +- .../src/app/settings/update-key.component.ts | 3 +- .../web/src/app/vault/add-edit.component.html | 2 +- .../src/app/vault/bulk-move.component.html | 2 +- apps/web/src/app/vault/bulk-move.component.ts | 7 +- .../src/components/add-edit.component.ts | 5 +- .../vault-filter/vault-filter.component.ts | 20 +- .../vault-filter/vault-filter.service.ts | 65 ++++-- .../src/services/jslib-services.module.ts | 1 + .../spec/services/export.service.spec.ts | 5 +- .../spec/services/folder.service.spec.ts | 195 ++++++++++++++++++ .../folder/folder.service.abstraction.ts | 16 +- libs/common/src/abstractions/state.service.ts | 9 +- libs/common/src/models/domain/account.ts | 13 +- libs/common/src/services/export.service.ts | 5 +- .../src/services/folder/folder.service.ts | 151 +++++++------- libs/common/src/services/state.service.ts | 19 -- .../src/services/vaultTimeout.service.ts | 2 +- 32 files changed, 421 insertions(+), 180 deletions(-) create mode 100644 libs/common/spec/services/folder.service.spec.ts diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 908f1211b5b..f4ffb1f9780 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -44,6 +44,7 @@ import { ApiService } from "@bitwarden/common/services/api.service"; import { AppIdService } from "@bitwarden/common/services/appId.service"; import { AuditService } from "@bitwarden/common/services/audit.service"; import { AuthService } from "@bitwarden/common/services/auth.service"; +import { BroadcasterService } from "@bitwarden/common/services/broadcaster.service"; import { CipherService } from "@bitwarden/common/services/cipher.service"; import { CollectionService } from "@bitwarden/common/services/collection.service"; import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service"; @@ -149,6 +150,7 @@ export default class MainBackground { vaultFilterService: VaultFilterService; usernameGenerationService: UsernameGenerationServiceAbstraction; encryptService: EncryptService; + broadcasterService: BroadcasterService; folderApiService: FolderApiServiceAbstraction; onUpdatedRan: boolean; @@ -267,11 +269,13 @@ export default class MainBackground { this.logService, this.stateService ); + this.broadcasterService = new BroadcasterService(); this.folderService = new FolderService( this.cryptoService, this.i18nService, this.cipherService, - this.stateService + this.stateService, + this.broadcasterService ); this.folderApiService = new FolderApiService(this.folderService, this.apiService); this.collectionService = new CollectionService( diff --git a/apps/browser/src/background/notification.background.ts b/apps/browser/src/background/notification.background.ts index f8db259cb70..7cbdd0993e5 100644 --- a/apps/browser/src/background/notification.background.ts +++ b/apps/browser/src/background/notification.background.ts @@ -1,3 +1,5 @@ +import { firstValueFrom } from "rxjs"; + import { AuthService } from "@bitwarden/common/abstractions/auth.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; @@ -385,7 +387,7 @@ export default class NotificationBackground { model.login = loginModel; if (!Utils.isNullOrWhitespace(folderId)) { - const folders = await this.folderService.getAllDecrypted(); + const folders = await firstValueFrom(this.folderService.folderViews$); if (folders.some((x) => x.id === folderId)) { model.folderId = folderId; } @@ -437,7 +439,7 @@ export default class NotificationBackground { private async getDataForTab(tab: chrome.tabs.Tab, responseCommand: string) { const responseData: any = {}; if (responseCommand === "notificationBarGetFoldersList") { - responseData.folders = await this.folderService.getAllDecrypted(); + responseData.folders = await firstValueFrom(this.folderService.folderViews$); } await BrowserApi.tabSendMessageData(tab, responseCommand, responseData); diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 63360194cd0..657c64fe725 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -11,6 +11,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AppIdService } from "@bitwarden/common/abstractions/appId.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/abstractions/auth.service"; +import { BroadcasterService as BroadcasterServiceAbstraction } from "@bitwarden/common/abstractions/broadcaster.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; @@ -111,6 +112,10 @@ function getBgService(service: keyof MainBackground) { : new BrowserMessagingService(); }, }, + { + provide: BroadcasterServiceAbstraction, + useFactory: getBgService("broadcasterService"), + }, { provide: TwoFactorService, useFactory: getBgService("twoFactorService"), diff --git a/apps/browser/src/popup/settings/folders.component.html b/apps/browser/src/popup/settings/folders.component.html index 47b6f78a1d1..23e2e227898 100644 --- a/apps/browser/src/popup/settings/folders.component.html +++ b/apps/browser/src/popup/settings/folders.component.html @@ -20,20 +20,20 @@
    -
    +
    -
    +

    {{ "noFolders" | i18n }}

    diff --git a/apps/browser/src/popup/settings/folders.component.ts b/apps/browser/src/popup/settings/folders.component.ts index 0e2a6036218..f0fb2204d88 100644 --- a/apps/browser/src/popup/settings/folders.component.ts +++ b/apps/browser/src/popup/settings/folders.component.ts @@ -1,5 +1,6 @@ -import { Component, OnInit } from "@angular/core"; +import { Component } from "@angular/core"; import { Router } from "@angular/router"; +import { map, Observable } from "rxjs"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { FolderView } from "@bitwarden/common/models/view/folderView"; @@ -8,17 +9,19 @@ import { FolderView } from "@bitwarden/common/models/view/folderView"; selector: "app-folders", templateUrl: "folders.component.html", }) -export class FoldersComponent implements OnInit { - folders: FolderView[]; +export class FoldersComponent { + folders$: Observable; - constructor(private folderService: FolderService, private router: Router) {} + constructor(private folderService: FolderService, private router: Router) { + this.folders$ = this.folderService.folderViews$.pipe( + map((folders) => { + if (folders.length > 0) { + folders = folders.slice(0, folders.length - 1); + } - async ngOnInit() { - this.folders = await this.folderService.getAllDecrypted(); - // Remove "No Folder" - if (this.folders.length > 0) { - this.folders = this.folders.slice(0, this.folders.length - 1); - } + return folders; + }) + ); } folderSelected(folder: FolderView) { diff --git a/apps/browser/src/popup/vault/add-edit.component.html b/apps/browser/src/popup/vault/add-edit.component.html index 9876da114c4..2686eb32fb8 100644 --- a/apps/browser/src/popup/vault/add-edit.component.html +++ b/apps/browser/src/popup/vault/add-edit.component.html @@ -515,7 +515,7 @@
    diff --git a/apps/browser/src/popup/vault/ciphers.component.ts b/apps/browser/src/popup/vault/ciphers.component.ts index 383633a1c28..8637cc57b62 100644 --- a/apps/browser/src/popup/vault/ciphers.component.ts +++ b/apps/browser/src/popup/vault/ciphers.component.ts @@ -120,7 +120,7 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On this.searchPlaceholder = this.i18nService.t("searchFolder"); if (this.folderId != null) { this.showOrganizations = false; - const folderNode = await this.folderService.getNested(this.folderId); + const folderNode = await this.vaultFilterService.getFolderNested(this.folderId); if (folderNode != null && folderNode.node != null) { this.groupingTitle = folderNode.node.name; this.nestedFolders = diff --git a/apps/browser/src/popup/vault/vault-filter.component.ts b/apps/browser/src/popup/vault/vault-filter.component.ts index d068686e548..ddace24de5e 100644 --- a/apps/browser/src/popup/vault/vault-filter.component.ts +++ b/apps/browser/src/popup/vault/vault-filter.component.ts @@ -1,6 +1,7 @@ import { Location } from "@angular/common"; import { ChangeDetectorRef, Component, NgZone, OnDestroy, OnInit } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; +import { firstValueFrom } from "rxjs"; import { first } from "rxjs/operators"; import { VaultFilter } from "@bitwarden/angular/modules/vault-filter/models/vault-filter.model"; @@ -182,9 +183,11 @@ export class VaultFilterComponent implements OnInit, OnDestroy { } async loadFolders() { - const allFolders = await this.vaultFilterService.buildFolders(this.selectedOrganization); + const allFolders = await firstValueFrom( + this.vaultFilterService.buildNestedFolders(this.selectedOrganization) + ); this.folders = allFolders.fullList; - this.nestedFolders = await allFolders.nestedList; + this.nestedFolders = allFolders.nestedList; } async search(timeout: number = null) { diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts index 82a63bff96a..45df7aa52bf 100644 --- a/apps/cli/src/bw.ts +++ b/apps/cli/src/bw.ts @@ -14,6 +14,7 @@ import { GlobalState } from "@bitwarden/common/models/domain/globalState"; import { AppIdService } from "@bitwarden/common/services/appId.service"; import { AuditService } from "@bitwarden/common/services/audit.service"; import { AuthService } from "@bitwarden/common/services/auth.service"; +import { BroadcasterService } from "@bitwarden/common/services/broadcaster.service"; import { CipherService } from "@bitwarden/common/services/cipher.service"; import { CollectionService } from "@bitwarden/common/services/collection.service"; import { ContainerService } from "@bitwarden/common/services/container.service"; @@ -103,6 +104,7 @@ export class Main { organizationService: OrganizationService; providerService: ProviderService; twoFactorService: TwoFactorService; + broadcasterService: BroadcasterService; folderApiService: FolderApiService; constructor() { @@ -198,11 +200,14 @@ export class Main { this.stateService ); + this.broadcasterService = new BroadcasterService(); + this.folderService = new FolderService( this.cryptoService, this.i18nService, this.cipherService, - this.stateService + this.stateService, + this.broadcasterService ); this.folderApiService = new FolderApiService(this.folderService, this.apiService); diff --git a/apps/cli/src/commands/get.command.ts b/apps/cli/src/commands/get.command.ts index c597745fcb5..bdf71b1f08c 100644 --- a/apps/cli/src/commands/get.command.ts +++ b/apps/cli/src/commands/get.command.ts @@ -1,3 +1,5 @@ +import { firstValueFrom } from "rxjs"; + import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; @@ -358,7 +360,7 @@ export class GetCommand extends DownloadCommand { decFolder = await folder.decrypt(); } } else if (id.trim() !== "") { - let folders = await this.folderService.getAllDecrypted(); + let folders = await firstValueFrom(this.folderService.folderViews$); folders = CliUtils.searchFolders(folders, id); if (folders.length > 1) { return Response.multipleResults(folders.map((f) => f.id)); diff --git a/apps/cli/src/commands/list.command.ts b/apps/cli/src/commands/list.command.ts index e32bc3f7914..c4b4c592af9 100644 --- a/apps/cli/src/commands/list.command.ts +++ b/apps/cli/src/commands/list.command.ts @@ -1,3 +1,5 @@ +import { firstValueFrom } from "rxjs"; + import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; @@ -126,7 +128,7 @@ export class ListCommand { } private async listFolders(options: Options) { - let folders = await this.folderService.getAllDecrypted(); + let folders = await firstValueFrom(this.folderService.folderViews$); if (options.search != null && options.search.trim() !== "") { folders = CliUtils.searchFolders(folders, options.search); diff --git a/apps/desktop/src/app/modules/vault-filter/vault-filter.component.html b/apps/desktop/src/app/modules/vault-filter/vault-filter.component.html index 62158fd3322..f44fc8f9302 100644 --- a/apps/desktop/src/app/modules/vault-filter/vault-filter.component.html +++ b/apps/desktop/src/app/modules/vault-filter/vault-filter.component.html @@ -32,7 +32,7 @@ [hide]="hideFolders" [activeFilter]="activeFilter" [collapsedFilterNodes]="collapsedFilterNodes" - [folderNodes]="folders" + [folderNodes]="folders$ | async" (onNodeCollapseStateChange)="toggleFilterNodeCollapseState($event)" (onFilterChange)="applyFilter($event)" (onAddFolder)="addFolder()" diff --git a/apps/desktop/src/app/vault/add-edit.component.html b/apps/desktop/src/app/vault/add-edit.component.html index 6f78e0cebab..05c9e130e08 100644 --- a/apps/desktop/src/app/vault/add-edit.component.html +++ b/apps/desktop/src/app/vault/add-edit.component.html @@ -455,7 +455,7 @@
    diff --git a/apps/web/src/app/modules/vault-filter/vault-filter.component.html b/apps/web/src/app/modules/vault-filter/vault-filter.component.html index bbe75c61e66..af77967e645 100644 --- a/apps/web/src/app/modules/vault-filter/vault-filter.component.html +++ b/apps/web/src/app/modules/vault-filter/vault-filter.component.html @@ -57,7 +57,7 @@ [hide]="hideFolders" [activeFilter]="activeFilter" [collapsedFilterNodes]="collapsedFilterNodes" - [folderNodes]="folders" + [folderNodes]="folders$ | async" (onNodeCollapseStateChange)="toggleFilterNodeCollapseState($event)" (onFilterChange)="applyFilter($event)" (onAddFolder)="addFolder()" diff --git a/apps/web/src/app/settings/change-password.component.ts b/apps/web/src/app/settings/change-password.component.ts index 073314510fa..d36a1eb1cb3 100644 --- a/apps/web/src/app/settings/change-password.component.ts +++ b/apps/web/src/app/settings/change-password.component.ts @@ -1,5 +1,6 @@ import { Component } from "@angular/core"; import { Router } from "@angular/router"; +import { firstValueFrom } from "rxjs"; import { ChangePasswordComponent as BaseChangePasswordComponent } from "@bitwarden/angular/components/change-password.component"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; @@ -192,7 +193,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { request.key = encKey[1].encryptedString; request.masterPasswordHash = masterPasswordHash; - const folders = await this.folderService.getAllDecrypted(); + const folders = await firstValueFrom(this.folderService.folderViews$); for (let i = 0; i < folders.length; i++) { if (folders[i].id == null) { continue; diff --git a/apps/web/src/app/settings/update-key.component.ts b/apps/web/src/app/settings/update-key.component.ts index d771d57a79e..b995ce42bf9 100644 --- a/apps/web/src/app/settings/update-key.component.ts +++ b/apps/web/src/app/settings/update-key.component.ts @@ -1,4 +1,5 @@ import { Component } from "@angular/core"; +import { firstValueFrom } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; @@ -81,7 +82,7 @@ export class UpdateKeyComponent { await this.syncService.fullSync(true); - const folders = await this.folderService.getAllDecrypted(); + const folders = await firstValueFrom(this.folderService.folderViews$); for (let i = 0; i < folders.length; i++) { if (folders[i].id == null) { continue; diff --git a/apps/web/src/app/vault/add-edit.component.html b/apps/web/src/app/vault/add-edit.component.html index e21b1ae10a3..54b707c9f6e 100644 --- a/apps/web/src/app/vault/add-edit.component.html +++ b/apps/web/src/app/vault/add-edit.component.html @@ -60,7 +60,7 @@ class="form-control" [disabled]="cipher.isDeleted || viewOnly" > - +
    diff --git a/apps/web/src/app/vault/bulk-move.component.html b/apps/web/src/app/vault/bulk-move.component.html index 866cc49c2cf..552b2efa512 100644 --- a/apps/web/src/app/vault/bulk-move.component.html +++ b/apps/web/src/app/vault/bulk-move.component.html @@ -19,7 +19,7 @@
    diff --git a/apps/web/src/app/vault/bulk-move.component.ts b/apps/web/src/app/vault/bulk-move.component.ts index c4c674a9cce..29e017b9356 100644 --- a/apps/web/src/app/vault/bulk-move.component.ts +++ b/apps/web/src/app/vault/bulk-move.component.ts @@ -1,4 +1,5 @@ import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; +import { firstValueFrom, Observable } from "rxjs"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; @@ -15,7 +16,7 @@ export class BulkMoveComponent implements OnInit { @Output() onMoved = new EventEmitter(); folderId: string = null; - folders: FolderView[] = []; + folders$: Observable; formPromise: Promise; constructor( @@ -26,8 +27,8 @@ export class BulkMoveComponent implements OnInit { ) {} async ngOnInit() { - this.folders = await this.folderService.getAllDecrypted(); - this.folderId = this.folders[0].id; + this.folders$ = this.folderService.folderViews$; + this.folderId = (await firstValueFrom(this.folders$))[0].id; } async submit() { diff --git a/libs/angular/src/components/add-edit.component.ts b/libs/angular/src/components/add-edit.component.ts index aeac25aade2..bac45023a9f 100644 --- a/libs/angular/src/components/add-edit.component.ts +++ b/libs/angular/src/components/add-edit.component.ts @@ -1,4 +1,5 @@ import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; +import { Observable } from "rxjs"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; @@ -51,7 +52,7 @@ export class AddEditComponent implements OnInit { editMode = false; cipher: CipherView; - folders: FolderView[]; + folders$: Observable; collections: CollectionView[] = []; title: string; formPromise: Promise; @@ -243,7 +244,7 @@ export class AddEditComponent implements OnInit { } } - this.folders = await this.folderService.getAllDecrypted(); + this.folders$ = this.folderService.folderViews$; if (this.editMode && this.previousCipherId !== this.cipherId) { this.eventService.collect(EventType.Cipher_ClientViewed, this.cipherId); diff --git a/libs/angular/src/modules/vault-filter/vault-filter.component.ts b/libs/angular/src/modules/vault-filter/vault-filter.component.ts index 2e77e2fd878..84396472efc 100644 --- a/libs/angular/src/modules/vault-filter/vault-filter.component.ts +++ b/libs/angular/src/modules/vault-filter/vault-filter.component.ts @@ -1,4 +1,5 @@ import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; +import { firstValueFrom, Observable } from "rxjs"; import { Organization } from "@bitwarden/common/models/domain/organization"; import { ITreeNodeObject } from "@bitwarden/common/models/domain/treeNode"; @@ -28,7 +29,7 @@ export class VaultFilterComponent implements OnInit { activePersonalOwnershipPolicy: boolean; activeSingleOrganizationPolicy: boolean; collections: DynamicTreeNode; - folders: DynamicTreeNode; + folders$: Observable>; constructor(protected vaultFilterService: VaultFilterService) {} @@ -45,7 +46,7 @@ export class VaultFilterComponent implements OnInit { this.activeSingleOrganizationPolicy = await this.vaultFilterService.checkForSingleOrganizationPolicy(); } - this.folders = await this.vaultFilterService.buildFolders(); + this.folders$ = await this.vaultFilterService.buildNestedFolders(); this.collections = await this.initCollections(); this.isLoaded = true; } @@ -67,13 +68,13 @@ export class VaultFilterComponent implements OnInit { async applyFilter(filter: VaultFilter) { if (filter.refreshCollectionsAndFolders) { await this.reloadCollectionsAndFolders(filter); - filter = this.pruneInvalidatedFilterSelections(filter); + filter = await this.pruneInvalidatedFilterSelections(filter); } this.onFilterChange.emit(filter); } async reloadCollectionsAndFolders(filter: VaultFilter) { - this.folders = await this.vaultFilterService.buildFolders(filter.selectedOrganizationId); + this.folders$ = await this.vaultFilterService.buildNestedFolders(filter.selectedOrganizationId); this.collections = filter.myVaultOnly ? null : await this.vaultFilterService.buildCollections(filter.selectedOrganizationId); @@ -95,14 +96,17 @@ export class VaultFilterComponent implements OnInit { this.onEditFolder.emit(folder); } - protected pruneInvalidatedFilterSelections(filter: VaultFilter): VaultFilter { - filter = this.pruneInvalidFolderSelection(filter); + protected async pruneInvalidatedFilterSelections(filter: VaultFilter): Promise { + filter = await this.pruneInvalidFolderSelection(filter); filter = this.pruneInvalidCollectionSelection(filter); return filter; } - protected pruneInvalidFolderSelection(filter: VaultFilter): VaultFilter { - if (filter.selectedFolder && !this.folders?.hasId(filter.selectedFolderId)) { + protected async pruneInvalidFolderSelection(filter: VaultFilter): Promise { + if ( + filter.selectedFolder && + !(await firstValueFrom(this.folders$))?.hasId(filter.selectedFolderId) + ) { filter.selectedFolder = false; filter.selectedFolderId = null; } diff --git a/libs/angular/src/modules/vault-filter/vault-filter.service.ts b/libs/angular/src/modules/vault-filter/vault-filter.service.ts index 6223433c036..294774948db 100644 --- a/libs/angular/src/modules/vault-filter/vault-filter.service.ts +++ b/libs/angular/src/modules/vault-filter/vault-filter.service.ts @@ -1,4 +1,5 @@ import { Injectable } from "@angular/core"; +import { from, mergeMap, Observable } from "rxjs"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; @@ -7,12 +8,16 @@ import { OrganizationService } from "@bitwarden/common/abstractions/organization import { PolicyService } from "@bitwarden/common/abstractions/policy.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { PolicyType } from "@bitwarden/common/enums/policyType"; +import { ServiceUtils } from "@bitwarden/common/misc/serviceUtils"; import { Organization } from "@bitwarden/common/models/domain/organization"; +import { TreeNode } from "@bitwarden/common/models/domain/treeNode"; import { CollectionView } from "@bitwarden/common/models/view/collectionView"; import { FolderView } from "@bitwarden/common/models/view/folderView"; import { DynamicTreeNode } from "./models/dynamic-tree-node.model"; +const NestingDelimiter = "/"; + @Injectable() export class VaultFilterService { constructor( @@ -36,25 +41,30 @@ export class VaultFilterService { return await this.organizationService.getAll(); } - async buildFolders(organizationId?: string): Promise> { - const storedFolders = await this.folderService.getAllDecrypted(); - let folders: FolderView[]; - if (organizationId != null) { - const ciphers = await this.cipherService.getAllDecrypted(); - const orgCiphers = ciphers.filter((c) => c.organizationId == organizationId); - folders = storedFolders.filter( - (f) => - orgCiphers.filter((oc) => oc.folderId == f.id).length > 0 || - ciphers.filter((c) => c.folderId == f.id).length < 1 - ); - } else { - folders = storedFolders; - } - const nestedFolders = await this.folderService.getAllNested(folders); - return new DynamicTreeNode({ - fullList: folders, - nestedList: nestedFolders, - }); + buildNestedFolders(organizationId?: string): Observable> { + const transformation = async (storedFolders: FolderView[]) => { + let folders: FolderView[]; + if (organizationId != null) { + const ciphers = await this.cipherService.getAllDecrypted(); + const orgCiphers = ciphers.filter((c) => c.organizationId == organizationId); + folders = storedFolders.filter( + (f) => + orgCiphers.filter((oc) => oc.folderId == f.id).length > 0 || + ciphers.filter((c) => c.folderId == f.id).length < 1 + ); + } else { + folders = storedFolders; + } + const nestedFolders = await this.getAllFoldersNested(folders); + return new DynamicTreeNode({ + fullList: folders, + nestedList: nestedFolders, + }); + }; + + return this.folderService.folderViews$.pipe( + mergeMap((folders) => from(transformation(folders))) + ); } async buildCollections(organizationId?: string): Promise> { @@ -79,4 +89,21 @@ export class VaultFilterService { async checkForPersonalOwnershipPolicy(): Promise { return await this.policyService.policyAppliesToUser(PolicyType.PersonalOwnership); } + + protected async getAllFoldersNested(folders?: FolderView[]): Promise[]> { + const nodes: TreeNode[] = []; + folders.forEach((f) => { + const folderCopy = new FolderView(); + folderCopy.id = f.id; + folderCopy.revisionDate = f.revisionDate; + const parts = f.name != null ? f.name.replace(/^\/+|\/+$/g, "").split(NestingDelimiter) : []; + ServiceUtils.nestedTraverse(nodes, 0, parts, folderCopy, null, NestingDelimiter); + }); + return nodes; + } + + async getFolderNested(id: string): Promise> { + const folders = await this.getAllFoldersNested(); + return ServiceUtils.getTreeNodeObject(folders, id) as TreeNode; + } } diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index e90acd075e7..1aa5ebaa542 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -223,6 +223,7 @@ export const LOG_MAC_FAILURES = new InjectionToken("LOG_MAC_FAILURES"); I18nServiceAbstraction, CipherServiceAbstraction, StateServiceAbstraction, + BroadcasterServiceAbstraction, ], }, { diff --git a/libs/common/spec/services/export.service.spec.ts b/libs/common/spec/services/export.service.spec.ts index 089073cb37a..bad26ab351e 100644 --- a/libs/common/spec/services/export.service.spec.ts +++ b/libs/common/spec/services/export.service.spec.ts @@ -1,4 +1,5 @@ import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute"; +import { BehaviorSubject } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; @@ -97,8 +98,8 @@ describe("ExportService", () => { folderService = Substitute.for(); cryptoService = Substitute.for(); - folderService.getAllDecrypted().resolves([]); - folderService.getAll().resolves([]); + folderService.folderViews$.returns(new BehaviorSubject([])); + folderService.folders$.returns(new BehaviorSubject([])); exportService = new ExportService( folderService, diff --git a/libs/common/spec/services/folder.service.spec.ts b/libs/common/spec/services/folder.service.spec.ts new file mode 100644 index 00000000000..e4f269b5361 --- /dev/null +++ b/libs/common/spec/services/folder.service.spec.ts @@ -0,0 +1,195 @@ +import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute"; +import { BehaviorSubject, firstValueFrom } from "rxjs"; + +import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service"; +import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; +import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; +import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; +import { FolderData } from "@bitwarden/common/models/data/folderData"; +import { EncString } from "@bitwarden/common/models/domain/encString"; +import { FolderView } from "@bitwarden/common/models/view/folderView"; +import { ContainerService } from "@bitwarden/common/services/container.service"; +import { FolderService } from "@bitwarden/common/services/folder/folder.service"; +import { StateService } from "@bitwarden/common/services/state.service"; + +describe("Folder Service", () => { + let folderService: FolderService; + + let cryptoService: SubstituteOf; + let i18nService: SubstituteOf; + let cipherService: SubstituteOf; + let stateService: SubstituteOf; + let broadcasterService: SubstituteOf; + let activeAccount: BehaviorSubject; + + beforeEach(() => { + cryptoService = Substitute.for(); + i18nService = Substitute.for(); + cipherService = Substitute.for(); + stateService = Substitute.for(); + broadcasterService = Substitute.for(); + activeAccount = new BehaviorSubject("123"); + + stateService.getEncryptedFolders().resolves({ + "1": folderData("1", "test"), + }); + stateService.activeAccount.returns(activeAccount); + (window as any).bitwardenContainerService = new ContainerService(cryptoService); + + folderService = new FolderService( + cryptoService, + i18nService, + cipherService, + stateService, + broadcasterService + ); + }); + + it("encrypt", async () => { + const model = new FolderView(); + model.id = "2"; + model.name = "Test Folder"; + + cryptoService.encrypt(Arg.any()).resolves(new EncString("ENC")); + cryptoService.decryptToUtf8(Arg.any()).resolves("DEC"); + + const result = await folderService.encrypt(model); + + expect(result).toEqual({ + id: "2", + name: { + encryptedString: "ENC", + encryptionType: 0, + }, + }); + }); + + describe("get", () => { + it("exists", async () => { + const result = await folderService.get("1"); + + expect(result).toEqual({ + id: "1", + name: { + decryptedValue: [], + encryptedString: "test", + encryptionType: 0, + }, + revisionDate: null, + }); + }); + + it("not exists", async () => { + const result = await folderService.get("2"); + + expect(result).toBe(undefined); + }); + }); + + it("upsert", async () => { + await folderService.upsert(folderData("2", "test 2")); + + expect(await firstValueFrom(folderService.folders$)).toEqual([ + { + id: "1", + name: { + decryptedValue: [], + encryptedString: "test", + encryptionType: 0, + }, + revisionDate: null, + }, + { + id: "2", + name: { + decryptedValue: [], + encryptedString: "test 2", + encryptionType: 0, + }, + revisionDate: null, + }, + ]); + + expect(await firstValueFrom(folderService.folderViews$)).toEqual([ + { id: "1", name: [], revisionDate: null }, + { id: "2", name: [], revisionDate: null }, + { id: null, name: [], revisionDate: null }, + ]); + }); + + it("replace", async () => { + await folderService.replace({ "2": folderData("2", "test 2") }); + + expect(await firstValueFrom(folderService.folders$)).toEqual([ + { + id: "2", + name: { + decryptedValue: [], + encryptedString: "test 2", + encryptionType: 0, + }, + revisionDate: null, + }, + ]); + + expect(await firstValueFrom(folderService.folderViews$)).toEqual([ + { id: "2", name: [], revisionDate: null }, + { id: null, name: [], revisionDate: null }, + ]); + }); + + it("delete", async () => { + await folderService.delete("1"); + + expect((await firstValueFrom(folderService.folders$)).length).toBe(0); + + expect(await firstValueFrom(folderService.folderViews$)).toEqual([ + { id: null, name: [], revisionDate: null }, + ]); + }); + + it("clearCache", async () => { + await folderService.clearCache(); + + expect((await firstValueFrom(folderService.folders$)).length).toBe(1); + expect((await firstValueFrom(folderService.folderViews$)).length).toBe(0); + }); + + describe("clear", () => { + it("null userId", async () => { + await folderService.clear(); + + stateService.received(1).setEncryptedFolders(Arg.any(), Arg.any()); + + expect((await firstValueFrom(folderService.folders$)).length).toBe(0); + expect((await firstValueFrom(folderService.folderViews$)).length).toBe(0); + }); + + it("matching userId", async () => { + stateService.getUserId().resolves("1"); + await folderService.clear("1"); + + stateService.received(1).setEncryptedFolders(Arg.any(), Arg.any()); + + expect((await firstValueFrom(folderService.folders$)).length).toBe(0); + expect((await firstValueFrom(folderService.folderViews$)).length).toBe(0); + }); + + it("missmatching userId", async () => { + await folderService.clear("12"); + + stateService.received(1).setEncryptedFolders(Arg.any(), Arg.any()); + + expect((await firstValueFrom(folderService.folders$)).length).toBe(1); + expect((await firstValueFrom(folderService.folderViews$)).length).toBe(2); + }); + }); + + function folderData(id: string, name: string) { + const data = new FolderData({} as any); + data.id = id; + data.name = name; + + return data; + } +}); diff --git a/libs/common/src/abstractions/folder/folder.service.abstraction.ts b/libs/common/src/abstractions/folder/folder.service.abstraction.ts index e7655bbd815..8110fa01ac5 100644 --- a/libs/common/src/abstractions/folder/folder.service.abstraction.ts +++ b/libs/common/src/abstractions/folder/folder.service.abstraction.ts @@ -1,22 +1,22 @@ +import { Observable } from "rxjs"; + import { FolderData } from "../../models/data/folderData"; import { Folder } from "../../models/domain/folder"; import { SymmetricCryptoKey } from "../../models/domain/symmetricCryptoKey"; -import { TreeNode } from "../../models/domain/treeNode"; import { FolderView } from "../../models/view/folderView"; export abstract class FolderService { - clearCache: (userId?: string) => Promise; + folders$: Observable; + folderViews$: Observable; + + clearCache: () => Promise; encrypt: (model: FolderView, key?: SymmetricCryptoKey) => Promise; get: (id: string) => Promise; - getAll: () => Promise; - getAllDecrypted: () => Promise; - getAllNested: (folders?: FolderView[]) => Promise[]>; - getNested: (id: string) => Promise>; } export abstract class InternalFolderService extends FolderService { - upsert: (folder: FolderData | FolderData[]) => Promise; - replace: (folders: { [id: string]: FolderData }) => Promise; + upsert: (folder: FolderData | FolderData[]) => Promise; + replace: (folders: { [id: string]: FolderData }) => Promise; clear: (userId: string) => Promise; delete: (id: string | string[]) => Promise; } diff --git a/libs/common/src/abstractions/state.service.ts b/libs/common/src/abstractions/state.service.ts index ec24884e3c4..5d3a7880a51 100644 --- a/libs/common/src/abstractions/state.service.ts +++ b/libs/common/src/abstractions/state.service.ts @@ -21,7 +21,6 @@ import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey"; import { WindowState } from "../models/domain/windowState"; import { CipherView } from "../models/view/cipherView"; import { CollectionView } from "../models/view/collectionView"; -import { FolderView } from "../models/view/folderView"; import { SendView } from "../models/view/sendView"; export abstract class StateService { @@ -88,8 +87,6 @@ export abstract class StateService { value: SymmetricCryptoKey, options?: StorageOptions ) => Promise; - getDecryptedFolders: (options?: StorageOptions) => Promise; - setDecryptedFolders: (value: FolderView[], options?: StorageOptions) => Promise; getDecryptedOrganizationKeys: ( options?: StorageOptions ) => Promise>; @@ -183,7 +180,13 @@ export abstract class StateService { ) => Promise; getEncryptedCryptoSymmetricKey: (options?: StorageOptions) => Promise; setEncryptedCryptoSymmetricKey: (value: string, options?: StorageOptions) => Promise; + /** + * @deprecated Do not call this directly, use FolderService + */ getEncryptedFolders: (options?: StorageOptions) => Promise<{ [id: string]: FolderData }>; + /** + * @deprecated Do not call this directly, use FolderService + */ setEncryptedFolders: ( value: { [id: string]: FolderData }, options?: StorageOptions diff --git a/libs/common/src/models/domain/account.ts b/libs/common/src/models/domain/account.ts index 7d2077960fd..525acf1527e 100644 --- a/libs/common/src/models/domain/account.ts +++ b/libs/common/src/models/domain/account.ts @@ -11,7 +11,6 @@ import { ProviderData } from "../data/providerData"; import { SendData } from "../data/sendData"; import { CipherView } from "../view/cipherView"; import { CollectionView } from "../view/collectionView"; -import { FolderView } from "../view/folderView"; import { SendView } from "../view/sendView"; import { EncString } from "./encString"; @@ -31,15 +30,19 @@ export class DataEncryptionPair { decrypted?: TDecrypted[]; } +// This is a temporary structure to handle migrated `DataEncryptionPair` to +// avoid needing a data migration at this stage. It should be replaced with +// proper data migrations when `DataEncryptionPair` is deprecated. +export class TemporaryDataEncryption { + encrypted?: { [id: string]: TEncrypted }; +} + export class AccountData { ciphers?: DataEncryptionPair = new DataEncryptionPair< CipherData, CipherView >(); - folders?: DataEncryptionPair = new DataEncryptionPair< - FolderData, - FolderView - >(); + folders? = new TemporaryDataEncryption(); localData?: any; sends?: DataEncryptionPair = new DataEncryptionPair(); collections?: DataEncryptionPair = new DataEncryptionPair< diff --git a/libs/common/src/services/export.service.ts b/libs/common/src/services/export.service.ts index 06b4221ba0d..11695936196 100644 --- a/libs/common/src/services/export.service.ts +++ b/libs/common/src/services/export.service.ts @@ -1,4 +1,5 @@ import * as papa from "papaparse"; +import { firstValueFrom } from "rxjs"; import { ApiService } from "../abstractions/api.service"; import { CipherService } from "../abstractions/cipher.service"; @@ -115,7 +116,7 @@ export class ExportService implements ExportServiceAbstraction { const promises = []; promises.push( - this.folderService.getAllDecrypted().then((folders) => { + firstValueFrom(this.folderService.folderViews$).then((folders) => { decFolders = folders; }) ); @@ -191,7 +192,7 @@ export class ExportService implements ExportServiceAbstraction { const promises = []; promises.push( - this.folderService.getAll().then((f) => { + firstValueFrom(this.folderService.folders$).then((f) => { folders = f; }) ); diff --git a/libs/common/src/services/folder/folder.service.ts b/libs/common/src/services/folder/folder.service.ts index 77d8cfc0a93..f2b7d37550d 100644 --- a/libs/common/src/services/folder/folder.service.ts +++ b/libs/common/src/services/folder/folder.service.ts @@ -1,31 +1,70 @@ +import { BehaviorSubject } from "rxjs"; + +import { BroadcasterService } from "../../abstractions/broadcaster.service"; import { CipherService } from "../../abstractions/cipher.service"; import { CryptoService } from "../../abstractions/crypto.service"; import { FolderService as FolderServiceAbstraction } from "../../abstractions/folder/folder.service.abstraction"; import { I18nService } from "../../abstractions/i18n.service"; import { StateService } from "../../abstractions/state.service"; -import { ServiceUtils } from "../../misc/serviceUtils"; import { Utils } from "../../misc/utils"; import { CipherData } from "../../models/data/cipherData"; import { FolderData } from "../../models/data/folderData"; import { Folder } from "../../models/domain/folder"; import { SymmetricCryptoKey } from "../../models/domain/symmetricCryptoKey"; -import { TreeNode } from "../../models/domain/treeNode"; import { FolderView } from "../../models/view/folderView"; -const NestingDelimiter = "/"; +const BroadcasterSubscriptionId = "FolderService"; export class FolderService implements FolderServiceAbstraction { + private _folders: BehaviorSubject = new BehaviorSubject([]); + private _folderViews: BehaviorSubject = new BehaviorSubject([]); + + folders$ = this._folders.asObservable(); + folderViews$ = this._folderViews.asObservable(); + constructor( private cryptoService: CryptoService, private i18nService: I18nService, private cipherService: CipherService, - private stateService: StateService - ) {} + private stateService: StateService, + private broadcasterService: BroadcasterService + ) { + this.stateService.activeAccount.subscribe(async (activeAccount) => { + if ((Utils.global as any).bitwardenContainerService == null) { + return; + } - async clearCache(userId?: string): Promise { - await this.stateService.setDecryptedFolders(null, { userId: userId }); + if (activeAccount == null) { + this._folders.next([]); + this._folderViews.next([]); + return; + } + + const data = await this.stateService.getEncryptedFolders(); + + await this.updateObservables(data); + }); + + // TODO: Broadcasterservice should be removed or replaced with observables + this.broadcasterService.subscribe(BroadcasterSubscriptionId, async (message: any) => { + switch (message.command) { + case "unlocked": { + const data = await this.stateService.getEncryptedFolders(); + + await this.updateObservables(data); + break; + } + default: + break; + } + }); } + async clearCache(): Promise { + this._folderViews.next([]); + } + + // TODO: This should be moved to EncryptService or something async encrypt(model: FolderView, key?: SymmetricCryptoKey): Promise { const folder = new Folder(); folder.id = model.id; @@ -34,75 +73,12 @@ export class FolderService implements FolderServiceAbstraction { } async get(id: string): Promise { - const folders = await this.stateService.getEncryptedFolders(); - // eslint-disable-next-line - if (folders == null || !folders.hasOwnProperty(id)) { - return null; - } + const folders = this._folders.getValue(); - return new Folder(folders[id]); + return folders.find((folder) => folder.id === id); } - async getAll(): Promise { - const folders = await this.stateService.getEncryptedFolders(); - const response: Folder[] = []; - for (const id in folders) { - // eslint-disable-next-line - if (folders.hasOwnProperty(id)) { - response.push(new Folder(folders[id])); - } - } - return response; - } - - async getAllDecrypted(): Promise { - const decryptedFolders = await this.stateService.getDecryptedFolders(); - if (decryptedFolders != null) { - return decryptedFolders; - } - - const hasKey = await this.cryptoService.hasKey(); - if (!hasKey) { - throw new Error("No key."); - } - - const decFolders: FolderView[] = []; - const promises: Promise[] = []; - const folders = await this.getAll(); - folders.forEach((folder) => { - promises.push(folder.decrypt().then((f) => decFolders.push(f))); - }); - - await Promise.all(promises); - decFolders.sort(Utils.getSortFunction(this.i18nService, "name")); - - const noneFolder = new FolderView(); - noneFolder.name = this.i18nService.t("noneFolder"); - decFolders.push(noneFolder); - - await this.stateService.setDecryptedFolders(decFolders); - return decFolders; - } - - async getAllNested(folders?: FolderView[]): Promise[]> { - folders = folders ?? (await this.getAllDecrypted()); - const nodes: TreeNode[] = []; - folders.forEach((f) => { - const folderCopy = new FolderView(); - folderCopy.id = f.id; - folderCopy.revisionDate = f.revisionDate; - const parts = f.name != null ? f.name.replace(/^\/+|\/+$/g, "").split(NestingDelimiter) : []; - ServiceUtils.nestedTraverse(nodes, 0, parts, folderCopy, null, NestingDelimiter); - }); - return nodes; - } - - async getNested(id: string): Promise> { - const folders = await this.getAllNested(); - return ServiceUtils.getTreeNodeObject(folders, id) as TreeNode; - } - - async upsert(folder: FolderData | FolderData[]): Promise { + async upsert(folder: FolderData | FolderData[]): Promise { let folders = await this.stateService.getEncryptedFolders(); if (folders == null) { folders = {}; @@ -117,17 +93,20 @@ export class FolderService implements FolderServiceAbstraction { }); } - await this.stateService.setDecryptedFolders(null); + await this.updateObservables(folders); await this.stateService.setEncryptedFolders(folders); } - async replace(folders: { [id: string]: FolderData }): Promise { - await this.stateService.setDecryptedFolders(null); + async replace(folders: { [id: string]: FolderData }): Promise { + await this.updateObservables(folders); await this.stateService.setEncryptedFolders(folders); } async clear(userId?: string): Promise { - await this.stateService.setDecryptedFolders(null, { userId: userId }); + if (userId == null || userId == (await this.stateService.getUserId())) { + this._folders.next([]); + this._folderViews.next([]); + } await this.stateService.setEncryptedFolders(null, { userId: userId }); } @@ -148,7 +127,7 @@ export class FolderService implements FolderServiceAbstraction { }); } - await this.stateService.setDecryptedFolders(null); + await this.updateObservables(folders); await this.stateService.setEncryptedFolders(folders); // Items in a deleted folder are re-assigned to "No Folder" @@ -166,4 +145,20 @@ export class FolderService implements FolderServiceAbstraction { } } } + + private async updateObservables(foldersMap: { [id: string]: FolderData }) { + const folders = Object.values(foldersMap || {}).map((f) => new Folder(f)); + + const decryptFolderPromises = folders.map((f) => f.decrypt()); + const decryptedFolders = await Promise.all(decryptFolderPromises); + + decryptedFolders.sort(Utils.getSortFunction(this.i18nService, "name")); + + const noneFolder = new FolderView(); + noneFolder.name = this.i18nService.t("noneFolder"); + decryptedFolders.push(noneFolder); + + this._folders.next(folders); + this._folderViews.next(decryptedFolders); + } } diff --git a/libs/common/src/services/state.service.ts b/libs/common/src/services/state.service.ts index fcb4a785950..d4901810f34 100644 --- a/libs/common/src/services/state.service.ts +++ b/libs/common/src/services/state.service.ts @@ -31,7 +31,6 @@ import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey"; import { WindowState } from "../models/domain/windowState"; import { CipherView } from "../models/view/cipherView"; import { CollectionView } from "../models/view/collectionView"; -import { FolderView } from "../models/view/folderView"; import { SendView } from "../models/view/sendView"; const keys = { @@ -658,24 +657,6 @@ export class StateService< ); } - @withPrototypeForArrayMembers(FolderView) - async getDecryptedFolders(options?: StorageOptions): Promise { - return ( - await this.getAccount(this.reconcileOptions(options, await this.defaultInMemoryOptions())) - )?.data?.folders?.decrypted; - } - - async setDecryptedFolders(value: FolderView[], options?: StorageOptions): Promise { - const account = await this.getAccount( - this.reconcileOptions(options, await this.defaultInMemoryOptions()) - ); - account.data.folders.decrypted = value; - await this.saveAccount( - account, - this.reconcileOptions(options, await this.defaultInMemoryOptions()) - ); - } - @withPrototypeForMap(SymmetricCryptoKey, SymmetricCryptoKey.initFromJson) async getDecryptedOrganizationKeys( options?: StorageOptions diff --git a/libs/common/src/services/vaultTimeout.service.ts b/libs/common/src/services/vaultTimeout.service.ts index dcb5db62d24..d087ab4277c 100644 --- a/libs/common/src/services/vaultTimeout.service.ts +++ b/libs/common/src/services/vaultTimeout.service.ts @@ -80,6 +80,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { if (userId == null || userId === (await this.stateService.getUserId())) { this.searchService.clearIndex(); + await this.folderService.clearCache(); } await this.stateService.setEverBeenUnlocked(true, { userId: userId }); @@ -91,7 +92,6 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { await this.cryptoService.clearKeyPair(true, userId); await this.cryptoService.clearEncKey(true, userId); - await this.folderService.clearCache(userId); await this.cipherService.clearCache(userId); await this.collectionService.clearCache(userId); From 5e84c630a80321f21c65d3cb5e8ea5411d11a667 Mon Sep 17 00:00:00 2001 From: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Date: Wed, 13 Jul 2022 07:08:07 +1000 Subject: [PATCH 40/86] [EC-135] Delay decryption of provider-encrypted org keys (#2902) --- .../services/stateMigration.service.spec.ts | 50 ++++++++++++++++- libs/common/src/abstractions/state.service.ts | 7 ++- libs/common/src/enums/stateVersion.ts | 3 +- .../data/encryptedOrganizationKeyData.ts | 14 +++++ libs/common/src/models/domain/account.ts | 8 ++- .../models/domain/encryptedOrganizationKey.ts | 56 +++++++++++++++++++ libs/common/src/services/crypto.service.ts | 50 ++++++++++------- libs/common/src/services/state.service.ts | 7 ++- .../src/services/stateMigration.service.ts | 34 +++++++++++ 9 files changed, 199 insertions(+), 30 deletions(-) create mode 100644 libs/common/src/models/data/encryptedOrganizationKeyData.ts create mode 100644 libs/common/src/models/domain/encryptedOrganizationKey.ts diff --git a/libs/common/spec/services/stateMigration.service.spec.ts b/libs/common/spec/services/stateMigration.service.spec.ts index 46fb13d70a1..7ac12f51e30 100644 --- a/libs/common/spec/services/stateMigration.service.spec.ts +++ b/libs/common/spec/services/stateMigration.service.spec.ts @@ -9,6 +9,9 @@ import { StateMigrationService } from "@bitwarden/common/services/stateMigration const userId = "USER_ID"; +// Note: each test calls the private migration method for that migration, +// so that we don't accidentally run all following migrations as well + describe("State Migration Service", () => { let storageService: SubstituteOf; let secureStorageService: SubstituteOf; @@ -66,13 +69,13 @@ describe("State Migration Service", () => { storageService.get(userId, Arg.any()).resolves(accountVersion3); - await stateMigrationService.migrate(); + await (stateMigrationService as any).migrateStateFrom3To4(); storageService.received(1).save(userId, expectedAccountVersion4, Arg.any()); }); it("updates StateVersion number", async () => { - await stateMigrationService.migrate(); + await (stateMigrationService as any).migrateStateFrom3To4(); storageService.received(1).save( "global", @@ -81,4 +84,47 @@ describe("State Migration Service", () => { ); }); }); + + describe("StateVersion 4 to 5 migration", () => { + it("migrates organization keys to new format", async () => { + const accountVersion4 = new Account({ + keys: { + organizationKeys: { + encrypted: { + orgOneId: "orgOneEncKey", + orgTwoId: "orgTwoEncKey", + orgThreeId: "orgThreeEncKey", + }, + }, + }, + } as any); + + const expectedAccount = new Account({ + keys: { + organizationKeys: { + encrypted: { + orgOneId: { + type: "organization", + key: "orgOneEncKey", + }, + orgTwoId: { + type: "organization", + key: "orgTwoEncKey", + }, + orgThreeId: { + type: "organization", + key: "orgThreeEncKey", + }, + }, + }, + }, + }); + + const migratedAccount = await (stateMigrationService as any).migrateAccountFrom4To5( + accountVersion4 + ); + + expect(migratedAccount).toEqual(expectedAccount); + }); + }); }); diff --git a/libs/common/src/abstractions/state.service.ts b/libs/common/src/abstractions/state.service.ts index 5d3a7880a51..3b6758ae347 100644 --- a/libs/common/src/abstractions/state.service.ts +++ b/libs/common/src/abstractions/state.service.ts @@ -5,6 +5,7 @@ import { ThemeType } from "../enums/themeType"; import { UriMatchType } from "../enums/uriMatchType"; import { CipherData } from "../models/data/cipherData"; import { CollectionData } from "../models/data/collectionData"; +import { EncryptedOrganizationKeyData } from "../models/data/encryptedOrganizationKeyData"; import { EventData } from "../models/data/eventData"; import { FolderData } from "../models/data/folderData"; import { OrganizationData } from "../models/data/organizationData"; @@ -191,9 +192,11 @@ export abstract class StateService { value: { [id: string]: FolderData }, options?: StorageOptions ) => Promise; - getEncryptedOrganizationKeys: (options?: StorageOptions) => Promise; + getEncryptedOrganizationKeys: ( + options?: StorageOptions + ) => Promise<{ [orgId: string]: EncryptedOrganizationKeyData }>; setEncryptedOrganizationKeys: ( - value: Map, + value: { [orgId: string]: EncryptedOrganizationKeyData }, options?: StorageOptions ) => Promise; getEncryptedPasswordGenerationHistory: ( diff --git a/libs/common/src/enums/stateVersion.ts b/libs/common/src/enums/stateVersion.ts index 5aeb02e5409..cc36f53f57f 100644 --- a/libs/common/src/enums/stateVersion.ts +++ b/libs/common/src/enums/stateVersion.ts @@ -3,5 +3,6 @@ export enum StateVersion { Two = 2, // Move to a typed State object Three = 3, // Fix migration of users' premium status Four = 4, // Fix 'Never Lock' option by removing stale data - Latest = Four, + Five = 5, // Migrate to new storage of encrypted organization keys + Latest = Five, } diff --git a/libs/common/src/models/data/encryptedOrganizationKeyData.ts b/libs/common/src/models/data/encryptedOrganizationKeyData.ts new file mode 100644 index 00000000000..8ecbeefb814 --- /dev/null +++ b/libs/common/src/models/data/encryptedOrganizationKeyData.ts @@ -0,0 +1,14 @@ +export type EncryptedOrganizationKeyData = + | OrganizationEncryptedOrganizationKeyData + | ProviderEncryptedOrganizationKeyData; + +type OrganizationEncryptedOrganizationKeyData = { + type: "organization"; + key: string; +}; + +type ProviderEncryptedOrganizationKeyData = { + type: "provider"; + key: string; + providerId: string; +}; diff --git a/libs/common/src/models/domain/account.ts b/libs/common/src/models/domain/account.ts index 525acf1527e..ff4b60345d8 100644 --- a/libs/common/src/models/domain/account.ts +++ b/libs/common/src/models/domain/account.ts @@ -3,6 +3,7 @@ import { KdfType } from "../../enums/kdfType"; import { UriMatchType } from "../../enums/uriMatchType"; import { CipherData } from "../data/cipherData"; import { CollectionData } from "../data/collectionData"; +import { EncryptedOrganizationKeyData } from "../data/encryptedOrganizationKeyData"; import { EventData } from "../data/eventData"; import { FolderData } from "../data/folderData"; import { OrganizationData } from "../data/organizationData"; @@ -69,8 +70,11 @@ export class AccountKeys { string, SymmetricCryptoKey >(); - organizationKeys?: EncryptionPair> = new EncryptionPair< - any, + organizationKeys?: EncryptionPair< + { [orgId: string]: EncryptedOrganizationKeyData }, + Map + > = new EncryptionPair< + { [orgId: string]: EncryptedOrganizationKeyData }, Map >(); providerKeys?: EncryptionPair> = new EncryptionPair< diff --git a/libs/common/src/models/domain/encryptedOrganizationKey.ts b/libs/common/src/models/domain/encryptedOrganizationKey.ts new file mode 100644 index 00000000000..25a49aab148 --- /dev/null +++ b/libs/common/src/models/domain/encryptedOrganizationKey.ts @@ -0,0 +1,56 @@ +import { CryptoService } from "../../abstractions/crypto.service"; +import { EncryptedOrganizationKeyData } from "../../models/data/encryptedOrganizationKeyData"; + +import { EncString } from "./encString"; +import { SymmetricCryptoKey } from "./symmetricCryptoKey"; + +export abstract class BaseEncryptedOrganizationKey { + decrypt: (cryptoService: CryptoService) => Promise; + + static fromData(data: EncryptedOrganizationKeyData) { + switch (data.type) { + case "organization": + return new EncryptedOrganizationKey(data.key); + + case "provider": + return new ProviderEncryptedOrganizationKey(data.key, data.providerId); + + default: + return null; + } + } +} + +export class EncryptedOrganizationKey implements BaseEncryptedOrganizationKey { + constructor(private key: string) {} + + async decrypt(cryptoService: CryptoService) { + const decValue = await cryptoService.rsaDecrypt(this.key); + return new SymmetricCryptoKey(decValue); + } + + toData(): EncryptedOrganizationKeyData { + return { + type: "organization", + key: this.key, + }; + } +} + +export class ProviderEncryptedOrganizationKey implements BaseEncryptedOrganizationKey { + constructor(private key: string, private providerId: string) {} + + async decrypt(cryptoService: CryptoService) { + const providerKey = await cryptoService.getProviderKey(this.providerId); + const decValue = await cryptoService.decryptToBytes(new EncString(this.key), providerKey); + return new SymmetricCryptoKey(decValue); + } + + toData(): EncryptedOrganizationKeyData { + return { + type: "provider", + key: this.key, + providerId: this.providerId, + }; + } +} diff --git a/libs/common/src/services/crypto.service.ts b/libs/common/src/services/crypto.service.ts index d4f9bd1de17..0d625295e42 100644 --- a/libs/common/src/services/crypto.service.ts +++ b/libs/common/src/services/crypto.service.ts @@ -13,9 +13,11 @@ import { KeySuffixOptions } from "../enums/keySuffixOptions"; import { sequentialize } from "../misc/sequentialize"; import { Utils } from "../misc/utils"; import { EEFLongWordList } from "../misc/wordlist"; +import { EncryptedOrganizationKeyData } from "../models/data/encryptedOrganizationKeyData"; import { EncArrayBuffer } from "../models/domain/encArrayBuffer"; import { EncString } from "../models/domain/encString"; import { EncryptedObject } from "../models/domain/encryptedObject"; +import { BaseEncryptedOrganizationKey } from "../models/domain/encryptedOrganizationKey"; import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey"; import { ProfileOrganizationResponse } from "../models/response/profileOrganizationResponse"; import { ProfileProviderOrganizationResponse } from "../models/response/profileProviderOrganizationResponse"; @@ -58,23 +60,28 @@ export class CryptoService implements CryptoServiceAbstraction { } async setOrgKeys( - orgs: ProfileOrganizationResponse[], - providerOrgs: ProfileProviderOrganizationResponse[] + orgs: ProfileOrganizationResponse[] = [], + providerOrgs: ProfileProviderOrganizationResponse[] = [] ): Promise { - const orgKeys: any = {}; + const encOrgKeyData: { [orgId: string]: EncryptedOrganizationKeyData } = {}; + orgs.forEach((org) => { - orgKeys[org.id] = org.key; + encOrgKeyData[org.id] = { + type: "organization", + key: org.key, + }; }); - for (const providerOrg of providerOrgs) { - // Convert provider encrypted keys to user encrypted. - const providerKey = await this.getProviderKey(providerOrg.providerId); - const decValue = await this.decryptToBytes(new EncString(providerOrg.key), providerKey); - orgKeys[providerOrg.id] = (await this.rsaEncrypt(decValue)).encryptedString; - } + providerOrgs.forEach((org) => { + encOrgKeyData[org.id] = { + type: "provider", + providerId: org.providerId, + key: org.key, + }; + }); await this.stateService.setDecryptedOrganizationKeys(null); - return await this.stateService.setEncryptedOrganizationKeys(orgKeys); + return await this.stateService.setEncryptedOrganizationKeys(encOrgKeyData); } async setProviderKeys(providers: ProfileProviderResponse[]): Promise { @@ -211,35 +218,36 @@ export class CryptoService implements CryptoServiceAbstraction { @sequentialize(() => "getOrgKeys") async getOrgKeys(): Promise> { - const orgKeys: Map = new Map(); + const result: Map = new Map(); const decryptedOrganizationKeys = await this.stateService.getDecryptedOrganizationKeys(); if (decryptedOrganizationKeys != null && decryptedOrganizationKeys.size > 0) { return decryptedOrganizationKeys; } - const encOrgKeys = await this.stateService.getEncryptedOrganizationKeys(); - if (encOrgKeys == null) { + const encOrgKeyData = await this.stateService.getEncryptedOrganizationKeys(); + if (encOrgKeyData == null) { return null; } let setKey = false; - for (const orgId in encOrgKeys) { - // eslint-disable-next-line - if (!encOrgKeys.hasOwnProperty(orgId)) { + for (const orgId of Object.keys(encOrgKeyData)) { + if (result.has(orgId)) { continue; } - const decValue = await this.rsaDecrypt(encOrgKeys[orgId]); - orgKeys.set(orgId, new SymmetricCryptoKey(decValue)); + const encOrgKey = BaseEncryptedOrganizationKey.fromData(encOrgKeyData[orgId]); + const decOrgKey = await encOrgKey.decrypt(this); + result.set(orgId, decOrgKey); + setKey = true; } if (setKey) { - await this.stateService.setDecryptedOrganizationKeys(orgKeys); + await this.stateService.setDecryptedOrganizationKeys(result); } - return orgKeys; + return result; } async getOrgKey(orgId: string): Promise { diff --git a/libs/common/src/services/state.service.ts b/libs/common/src/services/state.service.ts index d4901810f34..332e4829345 100644 --- a/libs/common/src/services/state.service.ts +++ b/libs/common/src/services/state.service.ts @@ -13,6 +13,7 @@ import { StateFactory } from "../factories/stateFactory"; import { Utils } from "../misc/utils"; import { CipherData } from "../models/data/cipherData"; import { CollectionData } from "../models/data/collectionData"; +import { EncryptedOrganizationKeyData } from "../models/data/encryptedOrganizationKeyData"; import { EventData } from "../models/data/eventData"; import { FolderData } from "../models/data/folderData"; import { OrganizationData } from "../models/data/organizationData"; @@ -1344,14 +1345,16 @@ export class StateService< ); } - async getEncryptedOrganizationKeys(options?: StorageOptions): Promise { + async getEncryptedOrganizationKeys( + options?: StorageOptions + ): Promise<{ [orgId: string]: EncryptedOrganizationKeyData }> { return ( await this.getAccount(this.reconcileOptions(options, await this.defaultOnDiskOptions())) )?.keys?.organizationKeys.encrypted; } async setEncryptedOrganizationKeys( - value: Map, + value: { [orgId: string]: EncryptedOrganizationKeyData }, options?: StorageOptions ): Promise { const account = await this.getAccount( diff --git a/libs/common/src/services/stateMigration.service.ts b/libs/common/src/services/stateMigration.service.ts index 0fc38aa2976..0d723e98473 100644 --- a/libs/common/src/services/stateMigration.service.ts +++ b/libs/common/src/services/stateMigration.service.ts @@ -155,6 +155,15 @@ export class StateMigrationService< case StateVersion.Three: await this.migrateStateFrom3To4(); break; + case StateVersion.Four: { + const authenticatedAccounts = await this.getAuthenticatedAccounts(); + for (const account of authenticatedAccounts) { + const migratedAccount = await this.migrateAccountFrom4To5(account); + await this.set(account.profile.userId, migratedAccount); + } + await this.setCurrentStateVersion(StateVersion.Five); + break; + } } currentStateVersion += 1; @@ -488,6 +497,20 @@ export class StateMigrationService< await this.set(keys.global, globals); } + protected async migrateAccountFrom4To5(account: TAccount): Promise { + const encryptedOrgKeys = account.keys?.organizationKeys?.encrypted; + if (encryptedOrgKeys != null) { + for (const [orgId, encKey] of Object.entries(encryptedOrgKeys)) { + encryptedOrgKeys[orgId] = { + type: "organization", + key: encKey as unknown as string, // Account v4 does not reflect the current account model so we have to cast + }; + } + } + + return account; + } + protected get options(): StorageOptions { return { htmlStorageLocation: HtmlStorageLocation.Local }; } @@ -510,4 +533,15 @@ export class StateMigrationService< protected async getCurrentStateVersion(): Promise { return (await this.getGlobals())?.stateVersion ?? StateVersion.One; } + + protected async setCurrentStateVersion(newVersion: StateVersion): Promise { + const globals = await this.getGlobals(); + globals.stateVersion = newVersion; + await this.set(keys.global, globals); + } + + protected async getAuthenticatedAccounts(): Promise { + const authenticatedUserIds = await this.get(keys.authenticatedAccounts); + return Promise.all(authenticatedUserIds.map((id) => this.get(id))); + } } From 71b237a7ebfa2cdcc4cb5c62977771a16b9e3213 Mon Sep 17 00:00:00 2001 From: Jake Fink Date: Wed, 13 Jul 2022 09:20:46 -0400 Subject: [PATCH 41/86] use a Set when validating emails to prevent duplicates (#3090) --- .../web/src/app/organizations/manage/user-add-edit.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/app/organizations/manage/user-add-edit.component.ts b/apps/web/src/app/organizations/manage/user-add-edit.component.ts index 7d4626384b0..ce597db7b57 100644 --- a/apps/web/src/app/organizations/manage/user-add-edit.component.ts +++ b/apps/web/src/app/organizations/manage/user-add-edit.component.ts @@ -187,7 +187,7 @@ export class UserAddEditComponent implements OnInit { ); } else { const request = new OrganizationUserInviteRequest(); - request.emails = this.emails.trim().split(/\s*,\s*/); + request.emails = [...new Set(this.emails.trim().split(/\s*,\s*/))]; request.accessAll = this.access === "all"; request.type = this.type; request.permissions = this.setRequestPermissions( From 6f55ca38e9b1c6b210cf21dc0efe62c7bdc09e4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ch=C4=99ci=C5=84ski?= Date: Wed, 13 Jul 2022 15:45:06 +0200 Subject: [PATCH 42/86] Remove latest tag on release (#3044) --- .github/workflows/release-web.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.github/workflows/release-web.yml b/.github/workflows/release-web.yml index 33b711306b1..9fedc30e529 100644 --- a/.github/workflows/release-web.yml +++ b/.github/workflows/release-web.yml @@ -88,7 +88,6 @@ jobs: docker tag bitwarden/web:latest bitwarden/web:$_RELEASE_VERSION else docker tag bitwarden/web:$_BRANCH_NAME bitwarden/web:$_RELEASE_VERSION - docker tag bitwarden/web:$_BRANCH_NAME bitwarden/web:latest fi - name: Docker Push version and latest image @@ -98,7 +97,6 @@ jobs: DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }} run: | docker push bitwarden/web:$_RELEASE_VERSION - docker push bitwarden/web:latest - name: Log out of Docker and disable Docker Notary run: | @@ -120,16 +118,12 @@ jobs: run: | if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then docker tag bitwarden/web:latest $REGISTRY/web:$_RELEASE_VERSION - docker tag bitwarden/web:latest $REGISTRY/web:latest docker tag bitwarden/web:latest $REGISTRY/web-sh:$_RELEASE_VERSION - docker tag bitwarden/web:latest $REGISTRY/web-sh:latest else docker tag bitwarden/web:$_BRANCH_NAME $REGISTRY/web:$_RELEASE_VERSION - docker tag bitwarden/web:$_BRANCH_NAME $REGISTRY/web:latest docker tag bitwarden/web:$_BRANCH_NAME $REGISTRY/web-sh:$_RELEASE_VERSION - docker tag bitwarden/web:$_BRANCH_NAME $REGISTRY/web-sh:latest fi - name: Push version and latest image @@ -138,10 +132,8 @@ jobs: REGISTRY: bitwardenqa.azurecr.io run: | docker push $REGISTRY/web:$_RELEASE_VERSION - docker push $REGISTRY/web:latest docker push $REGISTRY/web-sh:$_RELEASE_VERSION - docker push $REGISTRY/web-sh:latest - name: Log out of Docker run: docker logout From 0a06ae0ec5734b02c3296cb4a2540a27c969f7c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ch=C4=99ci=C5=84ski?= Date: Wed, 13 Jul 2022 15:45:52 +0200 Subject: [PATCH 43/86] Move the QA Web Vault to CloudFlare Pages (#3030) * Release to QA branch * Fix branch name * Change release to automatically push new version * Fix name of GH bot * Add check if there is sth to commit * Fix comments * Fix comments #2 * Keep k8s deployment * Fix newlines --- .github/workflows/release-qa-web.yml | 51 ++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/.github/workflows/release-qa-web.yml b/.github/workflows/release-qa-web.yml index 8f8dfa31d59..d72783ec48a 100644 --- a/.github/workflows/release-qa-web.yml +++ b/.github/workflows/release-qa-web.yml @@ -67,3 +67,54 @@ jobs: kubectl set image -n $_QA_K8S_NAMESPACE deployment/web web=bitwardenqa.azurecr.io/web:$IMAGE_TAG --record kubectl rollout restart -n $_QA_K8S_NAMESPACE deployment/web kubectl rollout status deployment/web -n $_QA_K8S_NAMESPACE + + cfpages-deploy: + name: Deploy Web Vault to QA CloudFlare Pages branch + runs-on: ubuntu-20.04 + steps: + - name: Checkout Repo + uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 + + - name: Download latest cloud asset + uses: bitwarden/gh-actions/download-artifacts@c1fa8e09871a860862d6bbe36184b06d2c7e35a8 + with: + workflow: build-web.yml + path: apps/web + workflow_conclusion: success + branch: ${{ github.ref_name }} + artifacts: web-*-cloud-COMMERCIAL.zip + + # This should result in a build directory in the current working directory + - name: Unzip build asset + working-directory: apps/web + run: unzip web-*-cloud-COMMERCIAL.zip + + - name: Checkout Repo + uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 + with: + ref: cf-pages-qa + path: deployment + + - name: Setup git config + run: | + git config --global user.name "GitHub Action Bot" + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --global url."https://github.com/".insteadOf ssh://git@github.com/ + git config --global url."https://".insteadOf ssh:// + + - name: Deploy CloudFlare Pages + run: | + rm -rf ./* + cp -R ../apps/web/build/* . + working-directory: deployment + + - name: Push new ver to cf-pages-qa + run: | + if [ -n "$(git status --porcelain)" ]; then + git add . + git commit -m "Deploy ${{ github.ref_name }} to QA Cloudflare pages" + git push -u origin cf-pages-qa + else + echo "No changes to commit!"; + fi + working-directory: deployment From 6a26223f93c3233f7aa96644176edb72c4e4cdc2 Mon Sep 17 00:00:00 2001 From: Gbubemi Smith Date: Wed, 13 Jul 2022 15:14:03 +0100 Subject: [PATCH 44/86] Fixed self host defect (#3094) --- libs/angular/src/components/register.component.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/libs/angular/src/components/register.component.ts b/libs/angular/src/components/register.component.ts index b07891371bd..967cb0e440c 100644 --- a/libs/angular/src/components/register.component.ts +++ b/libs/angular/src/components/register.component.ts @@ -1,5 +1,5 @@ import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; -import { FormBuilder, Validators } from "@angular/forms"; +import { AbstractControl, FormBuilder, ValidatorFn, Validators } from "@angular/forms"; import { Router } from "@angular/router"; import { InputsFieldMatch } from "@bitwarden/angular/validators/inputsFieldMatch.validator"; @@ -50,7 +50,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn ), ], ], - acceptPolicies: [false, [Validators.requiredTrue]], + acceptPolicies: [false, [this.acceptPoliciesValidation()]], }, { validator: InputsFieldMatch.validateFormInputsMatch( @@ -275,4 +275,13 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn const name = error.errorName.charAt(0).toUpperCase() + error.errorName.slice(1); return `${error.controlName}${name}`; } + + //validation would be ignored on selfhosted + private acceptPoliciesValidation(): ValidatorFn { + return (control: AbstractControl) => { + const ctrlValue = control.value; + + return !ctrlValue && this.showTerms ? { required: true } : null; + }; + } } From 0465168919e975bbfec540a1d133faa7b3300db3 Mon Sep 17 00:00:00 2001 From: Robyn MacCallum Date: Wed, 13 Jul 2022 12:22:58 -0400 Subject: [PATCH 45/86] [SG-439] Add feature flags to web (#3092) * Add feature flags to web * Remove extra file from dev --- apps/web/config/base.json | 3 ++- apps/web/config/cloud.json | 3 +++ apps/web/config/development.json | 3 +++ apps/web/config/qa.json | 3 +++ apps/web/config/selfhosted.json | 3 +++ apps/web/src/app/oss-routing.module.ts | 17 ++++++++++++++--- apps/web/src/utils/flags.ts | 19 +++++++++++++++++++ apps/web/webpack.config.js | 1 + 8 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 apps/web/src/utils/flags.ts diff --git a/apps/web/config/base.json b/apps/web/config/base.json index b6a41c203e0..cab6fbe950f 100644 --- a/apps/web/config/base.json +++ b/apps/web/config/base.json @@ -9,5 +9,6 @@ "dev": { "port": 8080, "allowedHosts": "auto" - } + }, + "flags": {} } diff --git a/apps/web/config/cloud.json b/apps/web/config/cloud.json index 51f29a05f9d..ae1a7c2675a 100644 --- a/apps/web/config/cloud.json +++ b/apps/web/config/cloud.json @@ -13,5 +13,8 @@ "proxyApi": "https://api.bitwarden.com", "proxyIdentity": "https://identity.bitwarden.com", "proxyEvents": "https://events.bitwarden.com" + }, + "flags": { + "showTrial": false } } diff --git a/apps/web/config/development.json b/apps/web/config/development.json index 7554af381d9..7f89752955f 100644 --- a/apps/web/config/development.json +++ b/apps/web/config/development.json @@ -7,5 +7,8 @@ "proxyIdentity": "http://localhost:33656", "proxyEvents": "http://localhost:46273", "proxyNotifications": "http://localhost:61840" + }, + "flags": { + "showTrial": true } } diff --git a/apps/web/config/qa.json b/apps/web/config/qa.json index 189b94d2a35..badd53cbb0a 100644 --- a/apps/web/config/qa.json +++ b/apps/web/config/qa.json @@ -7,5 +7,8 @@ "proxyApi": "https://api.qa.bitwarden.pw", "proxyIdentity": "https://identity.qa.bitwarden.pw", "proxyEvents": "https://events.qa.bitwarden.pw" + }, + "flags": { + "showTrial": true } } diff --git a/apps/web/config/selfhosted.json b/apps/web/config/selfhosted.json index 208a355a85e..3ba61fda596 100644 --- a/apps/web/config/selfhosted.json +++ b/apps/web/config/selfhosted.json @@ -5,5 +5,8 @@ "proxyEvents": "http://localhost:46274", "proxyNotifications": "http://localhost:61841", "port": 8081 + }, + "flags": { + "showTrial": false } } diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts index a98cbad1d2b..76501a16f49 100644 --- a/apps/web/src/app/oss-routing.module.ts +++ b/apps/web/src/app/oss-routing.module.ts @@ -1,10 +1,12 @@ import { NgModule } from "@angular/core"; -import { RouterModule, Routes } from "@angular/router"; +import { Route, RouterModule, Routes } from "@angular/router"; import { AuthGuard } from "@bitwarden/angular/guards/auth.guard"; import { LockGuard } from "@bitwarden/angular/guards/lock.guard"; import { UnauthGuard } from "@bitwarden/angular/guards/unauth.guard"; +import { flagEnabled, FlagName } from "../utils/flags"; + import { AcceptEmergencyComponent } from "./accounts/accept-emergency.component"; import { AcceptOrganizationComponent } from "./accounts/accept-organization.component"; import { HintComponent } from "./accounts/hint.component"; @@ -65,12 +67,12 @@ const routes: Routes = [ canActivate: [UnauthGuard], data: { titleId: "createAccount" }, }, - { + buildFlaggedRoute("showTrial", { path: "trial", component: TrialInitiationComponent, canActivate: [UnauthGuard], data: { titleId: "startTrial" }, - }, + }), { path: "sso", component: SsoComponent, @@ -258,3 +260,12 @@ const routes: Routes = [ exports: [RouterModule], }) export class OssRoutingModule {} + +export function buildFlaggedRoute(flagName: FlagName, route: Route): Route { + return flagEnabled(flagName) + ? route + : { + path: route.path, + redirectTo: "/", + }; +} diff --git a/apps/web/src/utils/flags.ts b/apps/web/src/utils/flags.ts new file mode 100644 index 00000000000..d6d9d0fe0be --- /dev/null +++ b/apps/web/src/utils/flags.ts @@ -0,0 +1,19 @@ +export type Flags = { + showTrial?: boolean; +}; + +export type FlagName = keyof Flags; + +export function flagEnabled(flag: FlagName): boolean { + return flags()[flag] == null || flags()[flag]; +} + +function flags(): Flags { + const envFlags = process.env.FLAGS as string | Flags; + + if (typeof envFlags === "string") { + return JSON.parse(envFlags) as Flags; + } else { + return envFlags as Flags; + } +} diff --git a/apps/web/webpack.config.js b/apps/web/webpack.config.js index 4aae92a2ebd..65caccc1cb4 100644 --- a/apps/web/webpack.config.js +++ b/apps/web/webpack.config.js @@ -151,6 +151,7 @@ const plugins = [ STRIPE_KEY: envConfig["stripeKey"] ?? "", BRAINTREE_KEY: envConfig["braintreeKey"] ?? "", PAYPAL_CONFIG: envConfig["paypal"] ?? {}, + FLAGS: envConfig["flags"] ?? {}, }), new webpack.ProvidePlugin({ process: "process/browser", From f233b0cab785eb153e1915221e5213b539ace97a Mon Sep 17 00:00:00 2001 From: Robyn MacCallum Date: Wed, 13 Jul 2022 13:13:14 -0400 Subject: [PATCH 46/86] [SG 435 & SG-436] Reusable org Component bug fixes (#3098) * Disable submit button of formGroup is invalid * Fix F4E bug * Remove duplicate validation --- .../app/settings/organization-plans.component.html | 13 +++---------- .../app/settings/organization-plans.component.ts | 12 +++++++++--- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/apps/web/src/app/settings/organization-plans.component.html b/apps/web/src/app/settings/organization-plans.component.html index 827554ea533..6368f2e5a14 100644 --- a/apps/web/src/app/settings/organization-plans.component.html +++ b/apps/web/src/app/settings/organization-plans.component.html @@ -131,8 +131,6 @@ type="number" name="additionalSeats" formControlName="additionalSeats" - min="1" - max="100000" placeholder="{{ 'userSeatsDesc' | i18n }}" required /> @@ -150,8 +148,6 @@ type="number" name="additionalSeats" formControlName="additionalSeats" - min="0" - max="100000" placeholder="{{ 'userSeatsDesc' | i18n }}" /> {{ @@ -169,8 +165,6 @@ type="number" name="additionalStorageGb" formControlName="additionalStorage" - min="0" - max="99" step="1" placeholder="{{ 'additionalStorageGbDesc' | i18n }}" /> @@ -323,10 +317,9 @@ {{ "singleOrgBlockCreateMessage" | i18n }}
    - + {{ + "submit" | i18n + }} diff --git a/apps/web/src/app/settings/organization-plans.component.ts b/apps/web/src/app/settings/organization-plans.component.ts index c894e3a2da0..a541f37ec20 100644 --- a/apps/web/src/app/settings/organization-plans.component.ts +++ b/apps/web/src/app/settings/organization-plans.component.ts @@ -52,8 +52,8 @@ export class OrganizationPlansComponent implements OnInit { discount = 0; formGroup = this.formBuilder.group({ - name: ["", [Validators.required]], - billingEmail: ["", [Validators.required, Validators.email]], + name: [""], + billingEmail: ["", [Validators.email]], businessOwned: [false], premiumAccessAddon: [false], additionalStorage: [0, [Validators.min(0), Validators.max(99)]], @@ -96,11 +96,16 @@ export class OrganizationPlansComponent implements OnInit { this.changedOwnedBusiness(); } - if (!this.createOrganization) { + if (!this.createOrganization || this.acceptingSponsorship) { this.formGroup.controls.product.setValue(ProductType.Families); this.changedProduct(); } + if (this.createOrganization) { + this.formGroup.controls.name.addValidators(Validators.required); + this.formGroup.controls.billingEmail.addValidators(Validators.required); + } + this.loading = false; } @@ -255,6 +260,7 @@ export class OrganizationPlansComponent implements OnInit { } this.formGroup.controls.product.setValue(ProductType.Teams); this.formGroup.controls.plan.setValue(PlanType.TeamsAnnually); + this.changedProduct(); } changedCountry() { From 3093c32f760148d93d1dea4dd24ec9caf8f3ddfb Mon Sep 17 00:00:00 2001 From: Brandon Maharaj <107377945+BrandonM-Bitwarden@users.noreply.github.com> Date: Thu, 14 Jul 2022 09:35:22 -0400 Subject: [PATCH 47/86] [SG-329] Disabled Org display (#3050) * chore: added strings for disabled org messages * chore: added icon display * chore: added prevent filter check * chore: code changes for desktop * chore: browser --- apps/browser/src/_locales/en/messages.json | 6 +++++ .../popup/vault/vault-select.component.html | 6 +++++ .../src/popup/vault/vault-select.component.ts | 20 ++++++++++++---- .../organization-filter.component.html | 6 +++++ .../organization-filter.component.ts | 23 +++++++++++++++++++ apps/desktop/src/locales/en/messages.json | 6 +++++ .../organization-filter.component.html | 6 +++++ .../organization-filter.component.ts | 23 +++++++++++++++++++ apps/web/src/locales/en/messages.json | 3 +++ 9 files changed, 94 insertions(+), 5 deletions(-) diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 20298701d41..8211f8eeb69 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -1967,5 +1967,11 @@ }, "ssoKeyConnectorError": { "message": "Key Connector error: make sure Key Connector is available and working correctly." + }, + "organizationIsDisabled": { + "message": "Organization is disabled." + }, + "disabledOrganizationFilterError" : { + "message" : "Items in disabled Organizations cannot be accessed. Contact your Organization owner for assistance." } } diff --git a/apps/browser/src/popup/vault/vault-select.component.html b/apps/browser/src/popup/vault/vault-select.component.html index 813fbccf148..69a526c8961 100644 --- a/apps/browser/src/popup/vault/vault-select.component.html +++ b/apps/browser/src/popup/vault/vault-select.component.html @@ -59,6 +59,12 @@ aria-hidden="true" >  {{ organization.name | ellipsis: 21:true }} +
    diff --git a/apps/browser/src/popup/vault/vault-select.component.ts b/apps/browser/src/popup/vault/vault-select.component.ts index e653cf4f492..4ed1dead32c 100644 --- a/apps/browser/src/popup/vault/vault-select.component.ts +++ b/apps/browser/src/popup/vault/vault-select.component.ts @@ -17,6 +17,7 @@ import { merge } from "rxjs"; import { VaultFilter } from "@bitwarden/angular/modules/vault-filter/models/vault-filter.model"; import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; +import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { Organization } from "@bitwarden/common/models/domain/organization"; import { VaultFilterService } from "../../services/vaultFilter.service"; @@ -82,7 +83,8 @@ export class VaultSelectComponent implements OnInit { private ngZone: NgZone, private broadcasterService: BroadcasterService, private overlay: Overlay, - private viewContainerRef: ViewContainerRef + private viewContainerRef: ViewContainerRef, + private platformUtilsService: PlatformUtilsService ) {} async ngOnInit() { @@ -171,10 +173,18 @@ export class VaultSelectComponent implements OnInit { } selectOrganization(organization: Organization) { - this.vaultFilterDisplay = organization.name; - this.vaultFilterService.setVaultFilter(organization.id); - this.onVaultSelectionChanged.emit(); - this.close(); + if (!organization.enabled) { + this.platformUtilsService.showToast( + "error", + null, + this.i18nService.t("disabledOrganizationFilterError") + ); + } else { + this.vaultFilterDisplay = organization.name; + this.vaultFilterService.setVaultFilter(organization.id); + this.onVaultSelectionChanged.emit(); + this.close(); + } } selectAllVaults() { this.vaultFilterDisplay = this.i18nService.t(this.vaultFilterService.allVaults); diff --git a/apps/desktop/src/app/modules/vault-filter/components/organization-filter.component.html b/apps/desktop/src/app/modules/vault-filter/components/organization-filter.component.html index 686e29b4f35..7a8071e5427 100644 --- a/apps/desktop/src/app/modules/vault-filter/components/organization-filter.component.html +++ b/apps/desktop/src/app/modules/vault-filter/components/organization-filter.component.html @@ -92,6 +92,12 @@ >  {{ organization.name }} +
  • diff --git a/apps/desktop/src/app/modules/vault-filter/components/organization-filter.component.ts b/apps/desktop/src/app/modules/vault-filter/components/organization-filter.component.ts index 6131cf739d2..f52d4bef6cb 100644 --- a/apps/desktop/src/app/modules/vault-filter/components/organization-filter.component.ts +++ b/apps/desktop/src/app/modules/vault-filter/components/organization-filter.component.ts @@ -2,6 +2,9 @@ import { Component } from "@angular/core"; import { OrganizationFilterComponent as BaseOrganizationFilterComponent } from "@bitwarden/angular/modules/vault-filter/components/organization-filter.component"; import { DisplayMode } from "@bitwarden/angular/modules/vault-filter/models/display-mode"; +import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; +import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; +import { Organization } from "@bitwarden/common/models/domain/organization"; @Component({ selector: "app-organization-filter", @@ -16,4 +19,24 @@ export class OrganizationFilterComponent extends BaseOrganizationFilterComponent hiddenDisplayModes.indexOf(this.displayMode) === -1 ); } + + constructor( + private i18nService: I18nService, + private platformUtilsService: PlatformUtilsService + ) { + super(); + } + + async applyOrganizationFilter(organization: Organization) { + if (organization.enabled) { + //proceed with default behaviour for enabled organizations + super.applyOrganizationFilter(organization); + } else { + this.platformUtilsService.showToast( + "error", + null, + this.i18nService.t("disabledOrganizationFilterError") + ); + } + } } diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index 64c1b443d48..7d12b136e64 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -1964,6 +1964,12 @@ "apiKey": { "message": "API Key" }, + "organizationIsDisabled": { + "message": "Organization is disabled." + }, + "disabledOrganizationFilterError" : { + "message" : "Items in disabled Organizations cannot be accessed. Contact your Organization owner for assistance." + }, "neverLockWarning": { "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." } diff --git a/apps/web/src/app/modules/vault-filter/components/organization-filter.component.html b/apps/web/src/app/modules/vault-filter/components/organization-filter.component.html index 0c4bf90eb1e..7ea5c0c92c5 100644 --- a/apps/web/src/app/modules/vault-filter/components/organization-filter.component.html +++ b/apps/web/src/app/modules/vault-filter/components/organization-filter.component.html @@ -129,6 +129,12 @@ + + + + {{ "scimApiKey" | i18n }} + + + + + + {{ "scimApiKeyHelperText" | i18n }} + + + + {{ "save" | i18n }} + + diff --git a/bitwarden_license/bit-web/src/app/organizations/manage/scim.component.ts b/bitwarden_license/bit-web/src/app/organizations/manage/scim.component.ts new file mode 100644 index 00000000000..26c93af18a1 --- /dev/null +++ b/bitwarden_license/bit-web/src/app/organizations/manage/scim.component.ts @@ -0,0 +1,161 @@ +import { Component, OnInit } from "@angular/core"; +import { FormBuilder, FormControl } from "@angular/forms"; +import { ActivatedRoute } from "@angular/router"; + +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; +import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; +import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; +import { OrganizationApiKeyType } from "@bitwarden/common/enums/organizationApiKeyType"; +import { OrganizationConnectionType } from "@bitwarden/common/enums/organizationConnectionType"; +import { ScimConfigApi } from "@bitwarden/common/models/api/scimConfigApi"; +import { OrganizationApiKeyRequest } from "@bitwarden/common/models/request/organizationApiKeyRequest"; +import { OrganizationConnectionRequest } from "@bitwarden/common/models/request/organizationConnectionRequest"; +import { ScimConfigRequest } from "@bitwarden/common/models/request/scimConfigRequest"; +import { OrganizationConnectionResponse } from "@bitwarden/common/models/response/organizationConnectionResponse"; + +@Component({ + selector: "app-org-manage-scim", + templateUrl: "scim.component.html", +}) +export class ScimComponent implements OnInit { + loading = true; + organizationId: string; + existingConnectionId: string; + formPromise: Promise; + rotatePromise: Promise; + enabled = new FormControl(false); + showScimSettings = false; + + formData = this.formBuilder.group({ + endpointUrl: new FormControl({ value: "", disabled: true }), + clientSecret: new FormControl({ value: "", disabled: true }), + }); + + constructor( + private formBuilder: FormBuilder, + private route: ActivatedRoute, + private apiService: ApiService, + private platformUtilsService: PlatformUtilsService, + private i18nService: I18nService, + private environmentService: EnvironmentService + ) {} + + async ngOnInit() { + this.route.parent.parent.params.subscribe(async (params) => { + this.organizationId = params.organizationId; + await this.load(); + }); + } + + async load() { + const connection = await this.apiService.getOrganizationConnection( + this.organizationId, + OrganizationConnectionType.Scim, + ScimConfigApi + ); + await this.setConnectionFormValues(connection); + } + + async loadApiKey() { + const apiKeyRequest = new OrganizationApiKeyRequest(); + apiKeyRequest.type = OrganizationApiKeyType.Scim; + apiKeyRequest.masterPasswordHash = "N/A"; + const apiKeyResponse = await this.apiService.postOrganizationApiKey( + this.organizationId, + apiKeyRequest + ); + this.formData.setValue({ + endpointUrl: this.getScimEndpointUrl(), + clientSecret: apiKeyResponse.apiKey, + }); + } + + async copyScimUrl() { + this.platformUtilsService.copyToClipboard(this.getScimEndpointUrl()); + } + + async rotateScimKey() { + const confirmed = await this.platformUtilsService.showDialog( + this.i18nService.t("rotateScimKeyWarning"), + this.i18nService.t("rotateScimKey"), + this.i18nService.t("rotateKey"), + this.i18nService.t("cancel"), + "warning" + ); + if (!confirmed) { + return false; + } + + const request = new OrganizationApiKeyRequest(); + request.type = OrganizationApiKeyType.Scim; + request.masterPasswordHash = "N/A"; + + this.rotatePromise = this.apiService.postOrganizationRotateApiKey(this.organizationId, request); + + try { + const response = await this.rotatePromise; + this.formData.setValue({ + endpointUrl: this.getScimEndpointUrl(), + clientSecret: response.apiKey, + }); + this.platformUtilsService.showToast("success", null, this.i18nService.t("scimApiKeyRotated")); + } catch { + // Logged by appApiAction, do nothing + } + + this.rotatePromise = null; + } + + async copyScimKey() { + this.platformUtilsService.copyToClipboard(this.formData.get("clientSecret").value); + } + + async submit() { + try { + const request = new OrganizationConnectionRequest( + this.organizationId, + OrganizationConnectionType.Scim, + true, + new ScimConfigRequest(this.enabled.value) + ); + if (this.existingConnectionId == null) { + this.formPromise = this.apiService.createOrganizationConnection(request, ScimConfigApi); + } else { + this.formPromise = this.apiService.updateOrganizationConnection( + request, + ScimConfigApi, + this.existingConnectionId + ); + } + const response = (await this.formPromise) as OrganizationConnectionResponse; + await this.setConnectionFormValues(response); + this.platformUtilsService.showToast("success", null, this.i18nService.t("scimSettingsSaved")); + } catch (e) { + // Logged by appApiAction, do nothing + } + + this.formPromise = null; + } + + getScimEndpointUrl() { + return this.environmentService.getScimUrl() + "/" + this.organizationId; + } + + private async setConnectionFormValues(connection: OrganizationConnectionResponse) { + this.existingConnectionId = connection?.id; + if (connection !== null && connection.config?.enabled) { + this.showScimSettings = true; + this.enabled.setValue(true); + this.formData.setValue({ + endpointUrl: this.getScimEndpointUrl(), + clientSecret: "", + }); + await this.loadApiKey(); + } else { + this.showScimSettings = false; + this.enabled.setValue(false); + } + this.loading = false; + } +} diff --git a/bitwarden_license/bit-web/src/app/organizations/organizations-routing.module.ts b/bitwarden_license/bit-web/src/app/organizations/organizations-routing.module.ts index 0052f0d67b2..1bfd51b7d30 100644 --- a/bitwarden_license/bit-web/src/app/organizations/organizations-routing.module.ts +++ b/bitwarden_license/bit-web/src/app/organizations/organizations-routing.module.ts @@ -9,6 +9,7 @@ import { OrganizationLayoutComponent } from "src/app/organizations/layouts/organ import { ManageComponent } from "src/app/organizations/manage/manage.component"; import { NavigationPermissionsService } from "src/app/organizations/services/navigation-permissions.service"; +import { ScimComponent } from "./manage/scim.component"; import { SsoComponent } from "./manage/sso.component"; const routes: Routes = [ @@ -33,6 +34,14 @@ const routes: Routes = [ permissions: [Permissions.ManageSso], }, }, + { + path: "scim", + component: ScimComponent, + canActivate: [PermissionsGuard], + data: { + permissions: [Permissions.ManageScim], + }, + }, ], }, ], diff --git a/bitwarden_license/bit-web/src/app/organizations/organizations.module.ts b/bitwarden_license/bit-web/src/app/organizations/organizations.module.ts index 0833e2ef9d5..1e9876b2877 100644 --- a/bitwarden_license/bit-web/src/app/organizations/organizations.module.ts +++ b/bitwarden_license/bit-web/src/app/organizations/organizations.module.ts @@ -2,12 +2,13 @@ import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; -import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { SharedModule } from "src/app/modules/shared.module"; import { InputCheckboxComponent } from "./components/input-checkbox.component"; import { InputTextReadOnlyComponent } from "./components/input-text-readonly.component"; import { InputTextComponent } from "./components/input-text.component"; import { SelectComponent } from "./components/select.component"; +import { ScimComponent } from "./manage/scim.component"; import { SsoComponent } from "./manage/sso.component"; import { OrganizationsRoutingModule } from "./organizations-routing.module"; @@ -18,7 +19,7 @@ import { OrganizationsRoutingModule } from "./organizations-routing.module"; CommonModule, FormsModule, ReactiveFormsModule, - JslibModule, + SharedModule, OrganizationsRoutingModule, ], declarations: [ @@ -27,6 +28,7 @@ import { OrganizationsRoutingModule } from "./organizations-routing.module"; InputTextReadOnlyComponent, SelectComponent, SsoComponent, + ScimComponent, ], }) export class OrganizationsModule {} diff --git a/libs/common/src/abstractions/api.service.ts b/libs/common/src/abstractions/api.service.ts index 24517be5228..365e3cd43dc 100644 --- a/libs/common/src/abstractions/api.service.ts +++ b/libs/common/src/abstractions/api.service.ts @@ -1,3 +1,4 @@ +import { OrganizationApiKeyType } from "../enums/organizationApiKeyType"; import { OrganizationConnectionType } from "../enums/organizationConnectionType"; import { PolicyType } from "../enums/policyType"; import { SetKeyConnectorKeyRequest } from "../models/request/account/setKeyConnectorKeyRequest"; @@ -573,7 +574,8 @@ export abstract class ApiService { request: OrganizationApiKeyRequest ) => Promise; getOrganizationApiKeyInformation: ( - id: string + id: string, + type?: OrganizationApiKeyType ) => Promise>; postOrganizationRotateApiKey: ( id: string, diff --git a/libs/common/src/abstractions/environment.service.ts b/libs/common/src/abstractions/environment.service.ts index 8398b4c634e..84bceaa1972 100644 --- a/libs/common/src/abstractions/environment.service.ts +++ b/libs/common/src/abstractions/environment.service.ts @@ -9,6 +9,7 @@ export type Urls = { notifications?: string; events?: string; keyConnector?: string; + scim?: string; }; export type PayPalConfig = { @@ -28,6 +29,7 @@ export abstract class EnvironmentService { getIdentityUrl: () => string; getEventsUrl: () => string; getKeyConnectorUrl: () => string; + getScimUrl: () => string; setUrlsFromStorage: () => Promise; setUrls: (urls: Urls) => Promise; getUrls: () => Urls; diff --git a/libs/common/src/enums/organizationApiKeyType.ts b/libs/common/src/enums/organizationApiKeyType.ts index 27479a8de02..44ba7f8391d 100644 --- a/libs/common/src/enums/organizationApiKeyType.ts +++ b/libs/common/src/enums/organizationApiKeyType.ts @@ -1,4 +1,5 @@ export enum OrganizationApiKeyType { Default = 0, BillingSync = 1, + Scim = 2, } diff --git a/libs/common/src/enums/organizationConnectionType.ts b/libs/common/src/enums/organizationConnectionType.ts index 1291874370a..d2f9700a6a0 100644 --- a/libs/common/src/enums/organizationConnectionType.ts +++ b/libs/common/src/enums/organizationConnectionType.ts @@ -1,3 +1,4 @@ export enum OrganizationConnectionType { CloudBillingSync = 1, + Scim = 2, } diff --git a/libs/common/src/enums/permissions.ts b/libs/common/src/enums/permissions.ts index bb0021506a9..46ee9066203 100644 --- a/libs/common/src/enums/permissions.ts +++ b/libs/common/src/enums/permissions.ts @@ -25,4 +25,5 @@ export enum Permissions { DeleteAssignedCollections, ManageSso, ManageBilling, + ManageScim, } diff --git a/libs/common/src/enums/scimProviderType.ts b/libs/common/src/enums/scimProviderType.ts new file mode 100644 index 00000000000..43c518fdfbf --- /dev/null +++ b/libs/common/src/enums/scimProviderType.ts @@ -0,0 +1,9 @@ +export enum ScimProviderType { + Default = 0, + AzureAd = 1, + Okta = 2, + OneLogin = 3, + JumpCloud = 4, + GoogleWorkspace = 5, + Rippling = 6, +} diff --git a/libs/common/src/models/api/permissionsApi.ts b/libs/common/src/models/api/permissionsApi.ts index bac79bd3cf1..c35cb69cb54 100644 --- a/libs/common/src/models/api/permissionsApi.ts +++ b/libs/common/src/models/api/permissionsApi.ts @@ -25,6 +25,7 @@ export class PermissionsApi extends BaseResponse { managePolicies: boolean; manageUsers: boolean; manageResetPassword: boolean; + manageScim: boolean; constructor(data: any = null) { super(data); @@ -51,5 +52,6 @@ export class PermissionsApi extends BaseResponse { this.managePolicies = this.getResponseProperty("ManagePolicies"); this.manageUsers = this.getResponseProperty("ManageUsers"); this.manageResetPassword = this.getResponseProperty("ManageResetPassword"); + this.manageScim = this.getResponseProperty("ManageScim"); } } diff --git a/libs/common/src/models/api/scimConfigApi.ts b/libs/common/src/models/api/scimConfigApi.ts new file mode 100644 index 00000000000..2269ac59691 --- /dev/null +++ b/libs/common/src/models/api/scimConfigApi.ts @@ -0,0 +1,17 @@ +import { ScimProviderType } from "@bitwarden/common/enums/scimProviderType"; + +import { BaseResponse } from "../response/baseResponse"; + +export class ScimConfigApi extends BaseResponse { + enabled: boolean; + scimProvider: ScimProviderType; + + constructor(data: any) { + super(data); + if (data == null) { + return; + } + this.enabled = this.getResponseProperty("Enabled"); + this.scimProvider = this.getResponseProperty("ScimProvider"); + } +} diff --git a/libs/common/src/models/data/organizationData.ts b/libs/common/src/models/data/organizationData.ts index d093821fc31..5d5e5229594 100644 --- a/libs/common/src/models/data/organizationData.ts +++ b/libs/common/src/models/data/organizationData.ts @@ -19,6 +19,7 @@ export class OrganizationData { useApi: boolean; useSso: boolean; useKeyConnector: boolean; + useScim: boolean; useResetPassword: boolean; selfHost: boolean; usersGetPremium: boolean; @@ -58,6 +59,7 @@ export class OrganizationData { this.useApi = response.useApi; this.useSso = response.useSso; this.useKeyConnector = response.useKeyConnector; + this.useScim = response.useScim; this.useResetPassword = response.useResetPassword; this.selfHost = response.selfHost; this.usersGetPremium = response.usersGetPremium; diff --git a/libs/common/src/models/domain/organization.ts b/libs/common/src/models/domain/organization.ts index ba1c8e1a173..c15d936234f 100644 --- a/libs/common/src/models/domain/organization.ts +++ b/libs/common/src/models/domain/organization.ts @@ -20,6 +20,7 @@ export class Organization { useApi: boolean; useSso: boolean; useKeyConnector: boolean; + useScim: boolean; useResetPassword: boolean; selfHost: boolean; usersGetPremium: boolean; @@ -63,6 +64,7 @@ export class Organization { this.useApi = obj.useApi; this.useSso = obj.useSso; this.useKeyConnector = obj.useKeyConnector; + this.useScim = obj.useScim; this.useResetPassword = obj.useResetPassword; this.selfHost = obj.selfHost; this.usersGetPremium = obj.usersGetPremium; @@ -173,6 +175,10 @@ export class Organization { return this.isAdmin || this.permissions.manageSso; } + get canManageScim() { + return this.isAdmin || this.permissions.manageScim; + } + get canManagePolicies() { return this.isAdmin || this.permissions.managePolicies; } @@ -207,6 +213,7 @@ export class Organization { (permissions.includes(Permissions.ManageUsers) && this.canManageUsers) || (permissions.includes(Permissions.ManageUsersPassword) && this.canManageUsersPassword) || (permissions.includes(Permissions.ManageSso) && this.canManageSso) || + (permissions.includes(Permissions.ManageScim) && this.canManageScim) || (permissions.includes(Permissions.ManageBilling) && this.canManageBilling); return specifiedPermissions && (this.enabled || this.isOwner); diff --git a/libs/common/src/models/request/organizationConnectionRequest.ts b/libs/common/src/models/request/organizationConnectionRequest.ts index 69964cb09e6..2506ac1d080 100644 --- a/libs/common/src/models/request/organizationConnectionRequest.ts +++ b/libs/common/src/models/request/organizationConnectionRequest.ts @@ -1,9 +1,10 @@ import { OrganizationConnectionType } from "../../enums/organizationConnectionType"; import { BillingSyncConfigRequest } from "./billingSyncConfigRequest"; +import { ScimConfigRequest } from "./scimConfigRequest"; /**API request config types for OrganizationConnectionRequest */ -export type OrganizationConnectionRequestConfigs = BillingSyncConfigRequest; +export type OrganizationConnectionRequestConfigs = BillingSyncConfigRequest | ScimConfigRequest; export class OrganizationConnectionRequest { constructor( diff --git a/libs/common/src/models/request/scimConfigRequest.ts b/libs/common/src/models/request/scimConfigRequest.ts new file mode 100644 index 00000000000..7549661cdd1 --- /dev/null +++ b/libs/common/src/models/request/scimConfigRequest.ts @@ -0,0 +1,5 @@ +import { ScimProviderType } from "@bitwarden/common/enums/scimProviderType"; + +export class ScimConfigRequest { + constructor(private enabled: boolean, private scimProvider: ScimProviderType = null) {} +} diff --git a/libs/common/src/models/response/organizationConnectionResponse.ts b/libs/common/src/models/response/organizationConnectionResponse.ts index a1e9a3de679..7f39d250f3b 100644 --- a/libs/common/src/models/response/organizationConnectionResponse.ts +++ b/libs/common/src/models/response/organizationConnectionResponse.ts @@ -1,10 +1,11 @@ import { OrganizationConnectionType } from "../../enums/organizationConnectionType"; import { BillingSyncConfigApi } from "../api/billingSyncConfigApi"; +import { ScimConfigApi } from "../api/scimConfigApi"; import { BaseResponse } from "./baseResponse"; /**API response config types for OrganizationConnectionResponse */ -export type OrganizationConnectionConfigApis = BillingSyncConfigApi; +export type OrganizationConnectionConfigApis = BillingSyncConfigApi | ScimConfigApi; export class OrganizationConnectionResponse< TConfig extends OrganizationConnectionConfigApis diff --git a/libs/common/src/models/response/profileOrganizationResponse.ts b/libs/common/src/models/response/profileOrganizationResponse.ts index 39b7644caaf..0287ae96c99 100644 --- a/libs/common/src/models/response/profileOrganizationResponse.ts +++ b/libs/common/src/models/response/profileOrganizationResponse.ts @@ -17,6 +17,7 @@ export class ProfileOrganizationResponse extends BaseResponse { useApi: boolean; useSso: boolean; useKeyConnector: boolean; + useScim: boolean; useResetPassword: boolean; selfHost: boolean; usersGetPremium: boolean; @@ -57,6 +58,7 @@ export class ProfileOrganizationResponse extends BaseResponse { this.useApi = this.getResponseProperty("UseApi"); this.useSso = this.getResponseProperty("UseSso"); this.useKeyConnector = this.getResponseProperty("UseKeyConnector") ?? false; + this.useScim = this.getResponseProperty("UseScim") ?? false; this.useResetPassword = this.getResponseProperty("UseResetPassword"); this.selfHost = this.getResponseProperty("SelfHost"); this.usersGetPremium = this.getResponseProperty("UsersGetPremium"); diff --git a/libs/common/src/services/api.service.ts b/libs/common/src/services/api.service.ts index ab41555d9c5..35b7d336d98 100644 --- a/libs/common/src/services/api.service.ts +++ b/libs/common/src/services/api.service.ts @@ -4,6 +4,7 @@ import { EnvironmentService } from "../abstractions/environment.service"; import { PlatformUtilsService } from "../abstractions/platformUtils.service"; import { TokenService } from "../abstractions/token.service"; import { DeviceType } from "../enums/deviceType"; +import { OrganizationApiKeyType } from "../enums/organizationApiKeyType"; import { OrganizationConnectionType } from "../enums/organizationConnectionType"; import { PolicyType } from "../enums/policyType"; import { Utils } from "../misc/utils"; @@ -1822,15 +1823,14 @@ export class ApiService implements ApiServiceAbstraction { } async getOrganizationApiKeyInformation( - id: string + id: string, + type: OrganizationApiKeyType = null ): Promise> { - const r = await this.send( - "GET", - "/organizations/" + id + "/api-key-information", - null, - true, - true - ); + const uri = + type === null + ? "/organizations/" + id + "/api-key-information" + : "/organizations/" + id + "/api-key-information/" + type; + const r = await this.send("GET", uri, null, true, true); return new ListResponse(r, OrganizationApiKeyInformationResponse); } diff --git a/libs/common/src/services/environment.service.ts b/libs/common/src/services/environment.service.ts index b13afd59acd..c22d7d85e62 100644 --- a/libs/common/src/services/environment.service.ts +++ b/libs/common/src/services/environment.service.ts @@ -19,6 +19,7 @@ export class EnvironmentService implements EnvironmentServiceAbstraction { private notificationsUrl: string; private eventsUrl: string; private keyConnectorUrl: string; + private scimUrl: string = null; constructor(private stateService: StateService) { this.stateService.activeAccount.subscribe(async () => { @@ -111,6 +112,16 @@ export class EnvironmentService implements EnvironmentServiceAbstraction { return this.keyConnectorUrl; } + getScimUrl() { + if (this.scimUrl != null) { + return this.scimUrl + "/v2"; + } + + return this.getWebVaultUrl() === "https://vault.bitwarden.com" + ? "https://scim.bitwarden.com/v2" + : this.getWebVaultUrl() + "/scim/v2"; + } + async setUrlsFromStorage(): Promise { const urls: any = await this.stateService.getEnvironmentUrls(); const envUrls = new EnvironmentUrls(); @@ -123,6 +134,7 @@ export class EnvironmentService implements EnvironmentServiceAbstraction { this.notificationsUrl = urls.notifications; this.eventsUrl = envUrls.events = urls.events; this.keyConnectorUrl = urls.keyConnector; + // scimUrl is not saved to storage } async setUrls(urls: Urls): Promise { @@ -135,6 +147,9 @@ export class EnvironmentService implements EnvironmentServiceAbstraction { urls.events = this.formatUrl(urls.events); urls.keyConnector = this.formatUrl(urls.keyConnector); + // scimUrl cannot be cleared + urls.scim = this.formatUrl(urls.scim) ?? this.scimUrl; + await this.stateService.setEnvironmentUrls({ base: urls.base, api: urls.api, @@ -144,6 +159,7 @@ export class EnvironmentService implements EnvironmentServiceAbstraction { notifications: urls.notifications, events: urls.events, keyConnector: urls.keyConnector, + // scimUrl is not saved to storage }); this.baseUrl = urls.base; @@ -154,6 +170,7 @@ export class EnvironmentService implements EnvironmentServiceAbstraction { this.notificationsUrl = urls.notifications; this.eventsUrl = urls.events; this.keyConnectorUrl = urls.keyConnector; + this.scimUrl = urls.scim; this.urlsSubject.next(urls); @@ -170,6 +187,7 @@ export class EnvironmentService implements EnvironmentServiceAbstraction { notifications: this.notificationsUrl, events: this.eventsUrl, keyConnector: this.keyConnectorUrl, + scim: this.scimUrl, }; } From ef68d5ed6597a963696e64744c197cae208dd775 Mon Sep 17 00:00:00 2001 From: Robyn MacCallum Date: Fri, 15 Jul 2022 10:55:14 -0400 Subject: [PATCH 60/86] Fix additional storage binding for annual total (#3111) --- apps/web/src/app/settings/organization-plans.component.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/web/src/app/settings/organization-plans.component.html b/apps/web/src/app/settings/organization-plans.component.html index 6368f2e5a14..a282aaf05e6 100644 --- a/apps/web/src/app/settings/organization-plans.component.html +++ b/apps/web/src/app/settings/organization-plans.component.html @@ -234,7 +234,8 @@ }} - {{ "additionalStorageGb" | i18n }}: {{ additionalStorage || 0 }} × + {{ "additionalStorageGb" | i18n }}: + {{ formGroup.controls["additionalStorage"].value || 0 }} × {{ selectablePlan.additionalStoragePricePerGb / 12 | currency: "$" }} × 12 {{ "monthAbbr" | i18n }} = {{ additionalStorageTotal(selectablePlan) | currency: "$" }} /{{ "year" | i18n }} From d1141247e59f147f6c336b3afe93dbd0e44bad11 Mon Sep 17 00:00:00 2001 From: Robyn MacCallum Date: Fri, 15 Jul 2022 12:00:15 -0400 Subject: [PATCH 61/86] Turn off trial route in qa for testing (#3099) --- apps/web/config/qa.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/config/qa.json b/apps/web/config/qa.json index 4371ea1ff98..0c8f0d3ccb9 100644 --- a/apps/web/config/qa.json +++ b/apps/web/config/qa.json @@ -10,6 +10,6 @@ "proxyEvents": "https://events.qa.bitwarden.pw" }, "flags": { - "showTrial": true + "showTrial": false } } From 6a30f37ba96499997b67e375a5ece053ffb5461e Mon Sep 17 00:00:00 2001 From: Robyn MacCallum Date: Fri, 15 Jul 2022 13:41:38 -0400 Subject: [PATCH 62/86] Update qa.json (#3122) --- apps/web/config/qa.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/config/qa.json b/apps/web/config/qa.json index 0c8f0d3ccb9..4371ea1ff98 100644 --- a/apps/web/config/qa.json +++ b/apps/web/config/qa.json @@ -10,6 +10,6 @@ "proxyEvents": "https://events.qa.bitwarden.pw" }, "flags": { - "showTrial": false + "showTrial": true } } From eb1cd9ff2ad719b0a3f6fce8c81022ea545c6b14 Mon Sep 17 00:00:00 2001 From: Addison Beck Date: Fri, 15 Jul 2022 13:54:11 -0400 Subject: [PATCH 63/86] [fix] File downloads in Safari (#3121) --- apps/browser/src/services/browserFileDownloadService.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/browser/src/services/browserFileDownloadService.ts b/apps/browser/src/services/browserFileDownloadService.ts index 29ff661923f..8f3ddb96acb 100644 --- a/apps/browser/src/services/browserFileDownloadService.ts +++ b/apps/browser/src/services/browserFileDownloadService.ts @@ -17,9 +17,7 @@ export class BrowserFileDownloadService implements FileDownloadService { if (builder.blobOptions.type === "text/plain" && typeof request.blobData === "string") { data = request.blobData; } else { - builder.blob.arrayBuffer().then((buf) => { - data = Utils.fromBufferToB64(buf); - }); + data = Utils.fromBufferToB64(request.blobData as ArrayBuffer); } SafariApp.sendMessageToApp( "downloadFile", From 5284072ff10eb6456cc2461541a1cf8133e28b23 Mon Sep 17 00:00:00 2001 From: Jake Fink Date: Fri, 15 Jul 2022 13:56:21 -0400 Subject: [PATCH 64/86] [PS-181] update electron (#3071) * update electron * downgrade electron-builder * update electron target in electron-builder * accept compatible versions in electron-builder * remove ^ from electron version * keep electron-builder at exact version --- apps/desktop/electron-builder.json | 2 +- package-lock.json | 289 +++++++++++++++++++++-------- package.json | 8 +- 3 files changed, 213 insertions(+), 86 deletions(-) diff --git a/apps/desktop/electron-builder.json b/apps/desktop/electron-builder.json index 1feb33069a5..b6211e8cdac 100644 --- a/apps/desktop/electron-builder.json +++ b/apps/desktop/electron-builder.json @@ -14,7 +14,7 @@ "afterSign": "scripts/after-sign.js", "asarUnpack": ["**/*.node"], "files": ["**/*", "!**/node_modules/@bitwarden/desktop-native/**/*"], - "electronVersion": "16.2.7", + "electronVersion": "19.0.8", "generateUpdatesFilesForAllChannels": true, "publish": { "provider": "generic", diff --git a/package-lock.json b/package-lock.json index 3325a4292e0..3e99454453c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -121,14 +121,14 @@ "cross-env": "^7.0.3", "css-loader": "^6.5.1", "del": "^6.0.0", - "electron": "16.2.7", - "electron-builder": "22.11.10", - "electron-log": "^4.4.7", + "electron": "^19.0.8", + "electron-builder": "^22.11.10", + "electron-log": "^4.4.8", "electron-notarize": "^1.2.1", "electron-rebuild": "^3.2.7", "electron-reload": "^2.0.0-alpha.1", - "electron-store": "^8.0.1", - "electron-updater": "^5.0.1", + "electron-store": "^8.0.2", + "electron-updater": "^5.0.5", "eslint": "^8.14.0", "eslint-config-prettier": "^8.5.0", "eslint-import-resolver-typescript": "^2.7.1", @@ -186,7 +186,7 @@ }, "apps/cli": { "name": "@bitwarden/cli", - "version": "1.22.1", + "version": "2022.6.2", "license": "GPL-3.0-only", "dependencies": { "@koa/multer": "^3.0.0", @@ -15740,6 +15740,19 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/app-builder-lib/node_modules/builder-util-runtime": { + "version": "8.7.9", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.9.tgz", + "integrity": "sha512-HCOkbKncb6eZSjnw1XnGgiXs7CQzORZit8zPK8IMHpU5GnZi6htS6KQdSMXU4ekDprfW3JLTRBHK9uxU2x++/g==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/app-builder-lib/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -17732,6 +17745,42 @@ } }, "node_modules/builder-util-runtime": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.0.2.tgz", + "integrity": "sha512-xF55W/8mgfT6+sMbX0TeiJkTusA5GMOzckM4rajN4KirFcUIuLTH8oEaTYmM86YwVCZaTwa/7GyFhauXaEICwA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/builder-util-runtime/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/builder-util/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/builder-util/node_modules/builder-util-runtime": { "version": "8.7.9", "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.9.tgz", "integrity": "sha512-HCOkbKncb6eZSjnw1XnGgiXs7CQzORZit8zPK8IMHpU5GnZi6htS6KQdSMXU4ekDprfW3JLTRBHK9uxU2x++/g==", @@ -17744,12 +17793,6 @@ "node": ">=12.0.0" } }, - "node_modules/builder-util/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/builder-util/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -21183,6 +21226,19 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/dmg-builder/node_modules/builder-util-runtime": { + "version": "8.7.9", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.9.tgz", + "integrity": "sha512-HCOkbKncb6eZSjnw1XnGgiXs7CQzORZit8zPK8IMHpU5GnZi6htS6KQdSMXU4ekDprfW3JLTRBHK9uxU2x++/g==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/dmg-builder/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -21199,7 +21255,6 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", - "deprecated": "Disk image license agreements are deprecated by Apple and will probably be removed in a future macOS release. Discussion at: https://github.com/argv-minus-one/dmg-license/issues/11", "dev": true, "optional": true, "os": [ @@ -21602,14 +21657,14 @@ } }, "node_modules/electron": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/electron/-/electron-16.2.7.tgz", - "integrity": "sha512-aZKF3b00+rqW/HGs8lJM5DhPNj+mOfCuhLSiFXV6J9dQCIRhctJTmToOrwXfbCxvXK8as8eQTNl5uSfnHmH6tA==", + "version": "19.0.8", + "resolved": "https://registry.npmjs.org/electron/-/electron-19.0.8.tgz", + "integrity": "sha512-OWK3P/NbDFfBUv+wbYv1/OV4jehY5DQPT7n1maQJfN9hsnrWTMktXS/bmS05eSUAjNAzHmKPKfiKH2c1Yr7nGw==", "dev": true, "hasInstallScript": true, "dependencies": { - "@electron/get": "^1.13.0", - "@types/node": "^14.6.2", + "@electron/get": "^1.14.1", + "@types/node": "^16.11.26", "extract-zip": "^1.0.3" }, "bin": { @@ -21655,10 +21710,23 @@ "@types/yargs-parser": "*" } }, + "node_modules/electron-builder/node_modules/builder-util-runtime": { + "version": "8.7.9", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.9.tgz", + "integrity": "sha512-HCOkbKncb6eZSjnw1XnGgiXs7CQzORZit8zPK8IMHpU5GnZi6htS6KQdSMXU4ekDprfW3JLTRBHK9uxU2x++/g==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/electron-log": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/electron-log/-/electron-log-4.4.7.tgz", - "integrity": "sha512-uFZQdgevOp9Fn5lDOrJMU/bmmYxDLZitbIHJM7VXN+cpB59ZnPt1FQL4bOf/Dl2gaIMPYJEfXx38GvJma5iV6A==", + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/electron-log/-/electron-log-4.4.8.tgz", + "integrity": "sha512-QQ4GvrXO+HkgqqEOYbi+DHL7hj5JM+nHi/j+qrN9zeeXVKy8ZABgbu4CnG+BBqDZ2+tbeq9tUC4DZfIWFU5AZA==", "dev": true }, "node_modules/electron-notarize": { @@ -21752,6 +21820,19 @@ "mime": "^2.5.2" } }, + "node_modules/electron-publish/node_modules/builder-util-runtime": { + "version": "8.7.9", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.9.tgz", + "integrity": "sha512-HCOkbKncb6eZSjnw1XnGgiXs7CQzORZit8zPK8IMHpU5GnZi6htS6KQdSMXU4ekDprfW3JLTRBHK9uxU2x++/g==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/electron-rebuild": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/electron-rebuild/-/electron-rebuild-3.2.7.tgz", @@ -22016,19 +22097,20 @@ "dev": true }, "node_modules/electron-updater": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-5.0.1.tgz", - "integrity": "sha512-dNnXPCqYmergXy3jgg4UICuD50Orug9GQe/5xfHy+BE2Fy0icB0QE+y6iQWdCDf7yeONxwMBf4HgIkGG5pIaVg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-5.0.5.tgz", + "integrity": "sha512-YcKEI9zpU+c0sNXTpjw3UpzP8Pfuuwo70T42oLYm0hHc0dy41ih51oENlhxgooa2+uzzpXhoCOyrpG+w6CB0Pw==", "dev": true, "dependencies": { "@types/semver": "^7.3.6", - "builder-util-runtime": "9.0.0", + "builder-util-runtime": "9.0.2", "fs-extra": "^10.0.0", "js-yaml": "^4.1.0", "lazy-val": "^1.0.5", "lodash.escaperegexp": "^4.1.2", "lodash.isequal": "^4.5.0", - "semver": "^7.3.5" + "semver": "^7.3.5", + "typed-emitter": "^2.1.0" } }, "node_modules/electron-updater/node_modules/argparse": { @@ -22037,19 +22119,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/electron-updater/node_modules/builder-util-runtime": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.0.0.tgz", - "integrity": "sha512-SkpEtSmTkREDHRJnxKEv43aAYp8sYWY8fxYBhGLBLOBIRXeaIp6Kv3lBgSD7uR8jQtC7CA659sqJrpSV6zNvSA==", - "dev": true, - "dependencies": { - "debug": "^4.3.2", - "sax": "^1.2.4" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/electron-updater/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -22062,12 +22131,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/electron/node_modules/@types/node": { - "version": "14.18.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.21.tgz", - "integrity": "sha512-x5W9s+8P4XteaxT/jKF0PSb7XEvo5VmqEWgsMlyeY4ZlLK8I6aH6g5TPPyDlLAep+GYf4kefb7HFyc7PAO3m+Q==", - "dev": true - }, "node_modules/element-resize-detector": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/element-resize-detector/-/element-resize-detector-1.2.4.tgz", @@ -43512,6 +43575,15 @@ "node": ">= 0.6" } }, + "node_modules/typed-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz", + "integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==", + "dev": true, + "optionalDependencies": { + "rxjs": "*" + } + }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -51639,7 +51711,7 @@ "postcss": "^7.0.36", "postcss-loader": "^4.2.0", "raw-loader": "^4.0.2", - "react": "^18.0.0", + "react": "^16.14.0", "react-dom": "^16.14.0", "read-pkg-up": "^7.0.1", "regenerator-runtime": "^0.13.7", @@ -57874,6 +57946,16 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "builder-util-runtime": { + "version": "8.7.9", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.9.tgz", + "integrity": "sha512-HCOkbKncb6eZSjnw1XnGgiXs7CQzORZit8zPK8IMHpU5GnZi6htS6KQdSMXU4ekDprfW3JLTRBHK9uxU2x++/g==", + "dev": true, + "requires": { + "debug": "^4.3.2", + "sax": "^1.2.4" + } + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -59464,6 +59546,16 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "builder-util-runtime": { + "version": "8.7.9", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.9.tgz", + "integrity": "sha512-HCOkbKncb6eZSjnw1XnGgiXs7CQzORZit8zPK8IMHpU5GnZi6htS6KQdSMXU4ekDprfW3JLTRBHK9uxU2x++/g==", + "dev": true, + "requires": { + "debug": "^4.3.2", + "sax": "^1.2.4" + } + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -59476,13 +59568,24 @@ } }, "builder-util-runtime": { - "version": "8.7.9", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.9.tgz", - "integrity": "sha512-HCOkbKncb6eZSjnw1XnGgiXs7CQzORZit8zPK8IMHpU5GnZi6htS6KQdSMXU4ekDprfW3JLTRBHK9uxU2x++/g==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.0.2.tgz", + "integrity": "sha512-xF55W/8mgfT6+sMbX0TeiJkTusA5GMOzckM4rajN4KirFcUIuLTH8oEaTYmM86YwVCZaTwa/7GyFhauXaEICwA==", "dev": true, "requires": { - "debug": "^4.3.2", + "debug": "^4.3.4", "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + } } }, "builtin-status-codes": { @@ -62134,6 +62237,16 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "builder-util-runtime": { + "version": "8.7.9", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.9.tgz", + "integrity": "sha512-HCOkbKncb6eZSjnw1XnGgiXs7CQzORZit8zPK8IMHpU5GnZi6htS6KQdSMXU4ekDprfW3JLTRBHK9uxU2x++/g==", + "dev": true, + "requires": { + "debug": "^4.3.2", + "sax": "^1.2.4" + } + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -62479,22 +62592,14 @@ } }, "electron": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/electron/-/electron-16.2.7.tgz", - "integrity": "sha512-aZKF3b00+rqW/HGs8lJM5DhPNj+mOfCuhLSiFXV6J9dQCIRhctJTmToOrwXfbCxvXK8as8eQTNl5uSfnHmH6tA==", + "version": "19.0.8", + "resolved": "https://registry.npmjs.org/electron/-/electron-19.0.8.tgz", + "integrity": "sha512-OWK3P/NbDFfBUv+wbYv1/OV4jehY5DQPT7n1maQJfN9hsnrWTMktXS/bmS05eSUAjNAzHmKPKfiKH2c1Yr7nGw==", "dev": true, "requires": { - "@electron/get": "^1.13.0", - "@types/node": "^14.6.2", + "@electron/get": "^1.14.1", + "@types/node": "^16.11.26", "extract-zip": "^1.0.3" - }, - "dependencies": { - "@types/node": { - "version": "14.18.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.21.tgz", - "integrity": "sha512-x5W9s+8P4XteaxT/jKF0PSb7XEvo5VmqEWgsMlyeY4ZlLK8I6aH6g5TPPyDlLAep+GYf4kefb7HFyc7PAO3m+Q==", - "dev": true - } } }, "electron-builder": { @@ -62525,13 +62630,23 @@ "requires": { "@types/yargs-parser": "*" } + }, + "builder-util-runtime": { + "version": "8.7.9", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.9.tgz", + "integrity": "sha512-HCOkbKncb6eZSjnw1XnGgiXs7CQzORZit8zPK8IMHpU5GnZi6htS6KQdSMXU4ekDprfW3JLTRBHK9uxU2x++/g==", + "dev": true, + "requires": { + "debug": "^4.3.2", + "sax": "^1.2.4" + } } } }, "electron-log": { - "version": "4.4.7", - "resolved": "https://registry.npmjs.org/electron-log/-/electron-log-4.4.7.tgz", - "integrity": "sha512-uFZQdgevOp9Fn5lDOrJMU/bmmYxDLZitbIHJM7VXN+cpB59ZnPt1FQL4bOf/Dl2gaIMPYJEfXx38GvJma5iV6A==", + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/electron-log/-/electron-log-4.4.8.tgz", + "integrity": "sha512-QQ4GvrXO+HkgqqEOYbi+DHL7hj5JM+nHi/j+qrN9zeeXVKy8ZABgbu4CnG+BBqDZ2+tbeq9tUC4DZfIWFU5AZA==", "dev": true }, "electron-notarize": { @@ -62611,6 +62726,18 @@ "fs-extra": "^10.0.0", "lazy-val": "^1.0.5", "mime": "^2.5.2" + }, + "dependencies": { + "builder-util-runtime": { + "version": "8.7.9", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.9.tgz", + "integrity": "sha512-HCOkbKncb6eZSjnw1XnGgiXs7CQzORZit8zPK8IMHpU5GnZi6htS6KQdSMXU4ekDprfW3JLTRBHK9uxU2x++/g==", + "dev": true, + "requires": { + "debug": "^4.3.2", + "sax": "^1.2.4" + } + } } }, "electron-rebuild": { @@ -62802,19 +62929,20 @@ "dev": true }, "electron-updater": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-5.0.1.tgz", - "integrity": "sha512-dNnXPCqYmergXy3jgg4UICuD50Orug9GQe/5xfHy+BE2Fy0icB0QE+y6iQWdCDf7yeONxwMBf4HgIkGG5pIaVg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-5.0.5.tgz", + "integrity": "sha512-YcKEI9zpU+c0sNXTpjw3UpzP8Pfuuwo70T42oLYm0hHc0dy41ih51oENlhxgooa2+uzzpXhoCOyrpG+w6CB0Pw==", "dev": true, "requires": { "@types/semver": "^7.3.6", - "builder-util-runtime": "9.0.0", + "builder-util-runtime": "9.0.2", "fs-extra": "^10.0.0", "js-yaml": "^4.1.0", "lazy-val": "^1.0.5", "lodash.escaperegexp": "^4.1.2", "lodash.isequal": "^4.5.0", - "semver": "^7.3.5" + "semver": "^7.3.5", + "typed-emitter": "^2.1.0" }, "dependencies": { "argparse": { @@ -62823,16 +62951,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "builder-util-runtime": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.0.0.tgz", - "integrity": "sha512-SkpEtSmTkREDHRJnxKEv43aAYp8sYWY8fxYBhGLBLOBIRXeaIp6Kv3lBgSD7uR8jQtC7CA659sqJrpSV6zNvSA==", - "dev": true, - "requires": { - "debug": "^4.3.2", - "sax": "^1.2.4" - } - }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -79569,6 +79687,15 @@ "mime-types": "~2.1.24" } }, + "typed-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz", + "integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==", + "dev": true, + "requires": { + "rxjs": "*" + } + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", diff --git a/package.json b/package.json index ac70e52938b..10e1d9f76ca 100644 --- a/package.json +++ b/package.json @@ -82,14 +82,14 @@ "cross-env": "^7.0.3", "css-loader": "^6.5.1", "del": "^6.0.0", - "electron": "16.2.7", + "electron": "19.0.8", "electron-builder": "22.11.10", - "electron-log": "^4.4.7", + "electron-log": "^4.4.8", "electron-notarize": "^1.2.1", "electron-rebuild": "^3.2.7", "electron-reload": "^2.0.0-alpha.1", - "electron-store": "^8.0.1", - "electron-updater": "^5.0.1", + "electron-store": "^8.0.2", + "electron-updater": "^5.0.5", "eslint": "^8.14.0", "eslint-config-prettier": "^8.5.0", "eslint-import-resolver-typescript": "^2.7.1", From cd5aef1757bf4d76ae521fab9e68c4be200d5779 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Mon, 18 Jul 2022 14:25:37 +0200 Subject: [PATCH 65/86] [Cl-10] Button group (#3031) * chore: setup initial bit-button-group using bitButton as template * feat: working radio group with preliminary styling * chore: cleanup * feat: implement proper basic styling * feat: implement focus handling and keyboard navigation * feat: implement size support * feat: add labeling support * feat: add input for button selection * feat: implement output handler on radio button interaction * feat: implement internal input/output seletion handling * feat: add external input support * feat: add external output support * chore: simplify storybook example a bit * fix: module imports * refactor: simplify both components * feat: remove size * chore: rename button-group to toggle-group * chore: rename toggle-group-element to toggle-group-button * chore: update story example * fix: compatibility with web vault * fix: imports in tests after rename * fix: remove unnecessary inject decorator * fix: clarify field names and html tags * feat: add badge centering fix * feat: set pointer cursor on label * chore: comment on special css rules * chore: remove focusable option from button * Update libs/components/src/toggle-group/toggle-group-button.component.ts Co-authored-by: Oscar Hinton * chore: rename to `bit-toggle` * fix: remove unecessary aria label function Co-authored-by: Oscar Hinton --- libs/components/src/index.ts | 1 + libs/components/src/toggle-group/index.ts | 2 + .../toggle-group/toggle-group.component.html | 1 + .../toggle-group.component.spec.ts | 69 ++++++++++++++++ .../toggle-group/toggle-group.component.ts | 24 ++++++ .../src/toggle-group/toggle-group.module.ts | 14 ++++ .../src/toggle-group/toggle-group.stories.ts | 54 +++++++++++++ .../src/toggle-group/toggle.component.html | 11 +++ .../src/toggle-group/toggle.component.spec.ts | 71 ++++++++++++++++ .../src/toggle-group/toggle.component.ts | 80 +++++++++++++++++++ 10 files changed, 327 insertions(+) create mode 100644 libs/components/src/toggle-group/index.ts create mode 100644 libs/components/src/toggle-group/toggle-group.component.html create mode 100644 libs/components/src/toggle-group/toggle-group.component.spec.ts create mode 100644 libs/components/src/toggle-group/toggle-group.component.ts create mode 100644 libs/components/src/toggle-group/toggle-group.module.ts create mode 100644 libs/components/src/toggle-group/toggle-group.stories.ts create mode 100644 libs/components/src/toggle-group/toggle.component.html create mode 100644 libs/components/src/toggle-group/toggle.component.spec.ts create mode 100644 libs/components/src/toggle-group/toggle.component.ts diff --git a/libs/components/src/index.ts b/libs/components/src/index.ts index cb45e12228e..a6c9e54c57a 100644 --- a/libs/components/src/index.ts +++ b/libs/components/src/index.ts @@ -1,6 +1,7 @@ export * from "./badge"; export * from "./banner"; export * from "./button"; +export * from "./toggle-group"; export * from "./callout"; export * from "./form-field"; export * from "./menu"; diff --git a/libs/components/src/toggle-group/index.ts b/libs/components/src/toggle-group/index.ts new file mode 100644 index 00000000000..bb7dba253e1 --- /dev/null +++ b/libs/components/src/toggle-group/index.ts @@ -0,0 +1,2 @@ +export * from "./toggle-group.component"; +export * from "./toggle-group.module"; diff --git a/libs/components/src/toggle-group/toggle-group.component.html b/libs/components/src/toggle-group/toggle-group.component.html new file mode 100644 index 00000000000..6dbc7430638 --- /dev/null +++ b/libs/components/src/toggle-group/toggle-group.component.html @@ -0,0 +1 @@ + diff --git a/libs/components/src/toggle-group/toggle-group.component.spec.ts b/libs/components/src/toggle-group/toggle-group.component.spec.ts new file mode 100644 index 00000000000..3bce3472e81 --- /dev/null +++ b/libs/components/src/toggle-group/toggle-group.component.spec.ts @@ -0,0 +1,69 @@ +import { Component } from "@angular/core"; +import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing"; +import { By } from "@angular/platform-browser"; + +import { ToggleGroupModule } from "./toggle-group.module"; +import { ToggleComponent } from "./toggle.component"; + +describe("Button", () => { + let fixture: ComponentFixture; + let testAppComponent: TestApp; + let buttonElements: ToggleComponent[]; + let radioButtons: HTMLInputElement[]; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + imports: [ToggleGroupModule], + declarations: [TestApp], + }); + + TestBed.compileComponents(); + fixture = TestBed.createComponent(TestApp); + testAppComponent = fixture.debugElement.componentInstance; + buttonElements = fixture.debugElement + .queryAll(By.css("bit-toggle")) + .map((e) => e.componentInstance); + radioButtons = fixture.debugElement + .queryAll(By.css("input[type=radio]")) + .map((e) => e.nativeElement); + + fixture.detectChanges(); + })); + + it("should select second element when setting selected to second", () => { + testAppComponent.selected = "second"; + fixture.detectChanges(); + + expect(buttonElements[1].selected).toBe(true); + }); + + it("should not select second element when setting selected to third", () => { + testAppComponent.selected = "third"; + fixture.detectChanges(); + + expect(buttonElements[1].selected).toBe(false); + }); + + it("should emit new value when changing selection by clicking on radio button", () => { + testAppComponent.selected = "first"; + fixture.detectChanges(); + + radioButtons[1].click(); + + expect(testAppComponent.selected).toBe("second"); + }); +}); + +@Component({ + selector: "test-app", + template: ` + + First + Second + Third + + `, +}) +class TestApp { + selected?: string; +} diff --git a/libs/components/src/toggle-group/toggle-group.component.ts b/libs/components/src/toggle-group/toggle-group.component.ts new file mode 100644 index 00000000000..adaed4bdb01 --- /dev/null +++ b/libs/components/src/toggle-group/toggle-group.component.ts @@ -0,0 +1,24 @@ +import { Component, EventEmitter, HostBinding, Input, Output } from "@angular/core"; + +let nextId = 0; + +@Component({ + selector: "bit-toggle-group", + templateUrl: "./toggle-group.component.html", + preserveWhitespaces: false, +}) +export class ToggleGroupComponent { + private id = nextId++; + name = `bit-toggle-group-${this.id}`; + + @Input() selected?: unknown; + @Output() selectedChange = new EventEmitter(); + + @HostBinding("attr.role") role = "radiogroup"; + @HostBinding("class") classList = ["tw-flex"]; + + onInputInteraction(value: unknown) { + this.selected = value; + this.selectedChange.emit(value); + } +} diff --git a/libs/components/src/toggle-group/toggle-group.module.ts b/libs/components/src/toggle-group/toggle-group.module.ts new file mode 100644 index 00000000000..fe1ce0ec52f --- /dev/null +++ b/libs/components/src/toggle-group/toggle-group.module.ts @@ -0,0 +1,14 @@ +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; + +import { BadgeModule } from "../badge"; + +import { ToggleGroupComponent } from "./toggle-group.component"; +import { ToggleComponent } from "./toggle.component"; + +@NgModule({ + imports: [CommonModule, BadgeModule], + exports: [ToggleGroupComponent, ToggleComponent], + declarations: [ToggleGroupComponent, ToggleComponent], +}) +export class ToggleGroupModule {} diff --git a/libs/components/src/toggle-group/toggle-group.stories.ts b/libs/components/src/toggle-group/toggle-group.stories.ts new file mode 100644 index 00000000000..8cc06f8c32d --- /dev/null +++ b/libs/components/src/toggle-group/toggle-group.stories.ts @@ -0,0 +1,54 @@ +import { Meta, moduleMetadata, Story } from "@storybook/angular"; + +import { BadgeModule } from "../badge"; + +import { ToggleGroupComponent } from "./toggle-group.component"; +import { ToggleComponent } from "./toggle.component"; + +export default { + title: "Component Library/Toggle Group", + component: ToggleGroupComponent, + args: { + selected: "all", + }, + decorators: [ + moduleMetadata({ + declarations: [ToggleGroupComponent, ToggleComponent], + imports: [BadgeModule], + }), + ], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A17157", + }, + }, +} as Meta; + +const Template: Story = (args: ToggleGroupComponent) => ({ + props: args, + template: ` + + + All 3 + + + + Invited + + + + Accepted 2 + + + + Deactivated + + + `, +}); + +export const Default = Template.bind({}); +Default.args = { + selected: "all", +}; diff --git a/libs/components/src/toggle-group/toggle.component.html b/libs/components/src/toggle-group/toggle.component.html new file mode 100644 index 00000000000..471ed5f0c03 --- /dev/null +++ b/libs/components/src/toggle-group/toggle.component.html @@ -0,0 +1,11 @@ + + diff --git a/libs/components/src/toggle-group/toggle.component.spec.ts b/libs/components/src/toggle-group/toggle.component.spec.ts new file mode 100644 index 00000000000..37c2e2ac101 --- /dev/null +++ b/libs/components/src/toggle-group/toggle.component.spec.ts @@ -0,0 +1,71 @@ +import { Component } from "@angular/core"; +import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing"; +import { By } from "@angular/platform-browser"; + +import { ToggleGroupComponent } from "./toggle-group.component"; +import { ToggleGroupModule } from "./toggle-group.module"; + +describe("Button", () => { + let mockGroupComponent: MockedButtonGroupComponent; + let fixture: ComponentFixture; + let testAppComponent: TestApp; + let radioButton: HTMLInputElement; + + beforeEach(waitForAsync(() => { + mockGroupComponent = new MockedButtonGroupComponent(); + + TestBed.configureTestingModule({ + imports: [ToggleGroupModule], + declarations: [TestApp], + providers: [{ provide: ToggleGroupComponent, useValue: mockGroupComponent }], + }); + + TestBed.compileComponents(); + fixture = TestBed.createComponent(TestApp); + testAppComponent = fixture.debugElement.componentInstance; + radioButton = fixture.debugElement.query(By.css("input[type=radio]")).nativeElement; + })); + + it("should emit value when clicking on radio button", () => { + testAppComponent.value = "value"; + fixture.detectChanges(); + + radioButton.click(); + fixture.detectChanges(); + + expect(mockGroupComponent.onInputInteraction).toHaveBeenCalledWith("value"); + }); + + it("should check radio button when selected matches value", () => { + testAppComponent.value = "value"; + fixture.detectChanges(); + + mockGroupComponent.selected = "value"; + fixture.detectChanges(); + + expect(radioButton.checked).toBe(true); + }); + + it("should not check radio button when selected does not match value", () => { + testAppComponent.value = "value"; + fixture.detectChanges(); + + mockGroupComponent.selected = "nonMatchingValue"; + fixture.detectChanges(); + + expect(radioButton.checked).toBe(false); + }); +}); + +class MockedButtonGroupComponent implements Partial { + onInputInteraction = jest.fn(); + selected = null; +} + +@Component({ + selector: "test-app", + template: ` Element`, +}) +class TestApp { + value?: string; +} diff --git a/libs/components/src/toggle-group/toggle.component.ts b/libs/components/src/toggle-group/toggle.component.ts new file mode 100644 index 00000000000..557ab38b386 --- /dev/null +++ b/libs/components/src/toggle-group/toggle.component.ts @@ -0,0 +1,80 @@ +import { HostBinding, Component, Input } from "@angular/core"; + +import { ToggleGroupComponent } from "./toggle-group.component"; + +let nextId = 0; + +@Component({ + selector: "bit-toggle", + templateUrl: "./toggle.component.html", + preserveWhitespaces: false, +}) +export class ToggleComponent { + id = nextId++; + + @Input() value?: string; + + constructor(private groupComponent: ToggleGroupComponent) {} + + @HostBinding("tabIndex") tabIndex = "-1"; + @HostBinding("class") classList = ["tw-group"]; + + get name() { + return this.groupComponent.name; + } + + get selected() { + return this.groupComponent.selected === this.value; + } + + get inputClasses() { + return ["tw-peer", "tw-appearance-none", "tw-outline-none"]; + } + + get labelClasses() { + return [ + "!tw-font-semibold", + "tw-transition", + "tw-text-center", + "tw-border-text-muted", + "!tw-text-muted", + "tw-border-solid", + "tw-border-y", + "tw-border-r", + "tw-border-l-0", + "tw-cursor-pointer", + "group-first-of-type:tw-border-l", + "group-first-of-type:tw-rounded-l", + "group-last-of-type:tw-rounded-r", + + "peer-focus:tw-outline-none", + "peer-focus:tw-ring", + "peer-focus:tw-ring-offset-2", + "peer-focus:tw-ring-primary-500", + "peer-focus:tw-z-10", + "peer-focus:tw-bg-primary-500", + "peer-focus:tw-border-primary-500", + "peer-focus:!tw-text-contrast", + + "hover:tw-no-underline", + "hover:tw-bg-text-muted", + "hover:tw-border-text-muted", + "hover:!tw-text-contrast", + + "peer-checked:tw-bg-primary-500", + "peer-checked:tw-border-primary-500", + "peer-checked:!tw-text-contrast", + "tw-py-1.5", + "tw-px-3", + + // Fix for badge being pushed slightly lower when inside a button. + // Insipired by bootstrap, which does the same. + "[&>[bitBadge]]:tw-relative", + "[&>[bitBadge]]:-tw-top-[1px]", + ]; + } + + onInputInteraction() { + this.groupComponent.onInputInteraction(this.value); + } +} From fbff2e5f0079acd0f9edf1c47bd29d33a241835d Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Mon, 18 Jul 2022 14:39:12 +0200 Subject: [PATCH 66/86] [PS-1134] Folder fixes, including revamped auth logic (#3118) --- .../browser/src/background/main.background.ts | 6 +-- .../src/popup/services/services.module.ts | 5 -- apps/cli/src/bw.ts | 3 +- apps/cli/src/commands/get.command.ts | 4 +- apps/cli/src/commands/list.command.ts | 4 +- .../vault-filter/vault-filter.service.ts | 8 +-- .../src/services/jslib-services.module.ts | 1 - .../folder/folder.service.abstraction.ts | 4 ++ libs/common/src/abstractions/state.service.ts | 4 +- .../src/services/folder/folder.service.ts | 49 +++++++++---------- libs/common/src/services/state.service.ts | 26 +++++++++- 11 files changed, 65 insertions(+), 49 deletions(-) diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index e529e6a39e7..cfc66fe02bf 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -44,7 +44,6 @@ import { ApiService } from "@bitwarden/common/services/api.service"; import { AppIdService } from "@bitwarden/common/services/appId.service"; import { AuditService } from "@bitwarden/common/services/audit.service"; import { AuthService } from "@bitwarden/common/services/auth.service"; -import { BroadcasterService } from "@bitwarden/common/services/broadcaster.service"; import { CipherService } from "@bitwarden/common/services/cipher.service"; import { CollectionService } from "@bitwarden/common/services/collection.service"; import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service"; @@ -150,7 +149,6 @@ export default class MainBackground { vaultFilterService: VaultFilterService; usernameGenerationService: UsernameGenerationServiceAbstraction; encryptService: EncryptService; - broadcasterService: BroadcasterService; folderApiService: FolderApiServiceAbstraction; // Passed to the popup for Safari to workaround issues with theming, downloading, etc. @@ -272,13 +270,11 @@ export default class MainBackground { this.logService, this.stateService ); - this.broadcasterService = new BroadcasterService(); this.folderService = new FolderService( this.cryptoService, this.i18nService, this.cipherService, - this.stateService, - this.broadcasterService + this.stateService ); this.folderApiService = new FolderApiService(this.folderService, this.apiService); this.collectionService = new CollectionService( diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index e300521bb6c..3cbb0091597 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -13,7 +13,6 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AppIdService } from "@bitwarden/common/abstractions/appId.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/abstractions/auth.service"; -import { BroadcasterService as BroadcasterServiceAbstraction } from "@bitwarden/common/abstractions/broadcaster.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; @@ -114,10 +113,6 @@ function getBgService(service: keyof MainBackground) { : new BrowserMessagingService(); }, }, - { - provide: BroadcasterServiceAbstraction, - useFactory: getBgService("broadcasterService"), - }, { provide: TwoFactorService, useFactory: getBgService("twoFactorService"), diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts index 45df7aa52bf..fe0391772c5 100644 --- a/apps/cli/src/bw.ts +++ b/apps/cli/src/bw.ts @@ -206,8 +206,7 @@ export class Main { this.cryptoService, this.i18nService, this.cipherService, - this.stateService, - this.broadcasterService + this.stateService ); this.folderApiService = new FolderApiService(this.folderService, this.apiService); diff --git a/apps/cli/src/commands/get.command.ts b/apps/cli/src/commands/get.command.ts index bdf71b1f08c..7cfcd9fb6e3 100644 --- a/apps/cli/src/commands/get.command.ts +++ b/apps/cli/src/commands/get.command.ts @@ -1,5 +1,3 @@ -import { firstValueFrom } from "rxjs"; - import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; @@ -360,7 +358,7 @@ export class GetCommand extends DownloadCommand { decFolder = await folder.decrypt(); } } else if (id.trim() !== "") { - let folders = await firstValueFrom(this.folderService.folderViews$); + let folders = await this.folderService.getAllDecryptedFromState(); folders = CliUtils.searchFolders(folders, id); if (folders.length > 1) { return Response.multipleResults(folders.map((f) => f.id)); diff --git a/apps/cli/src/commands/list.command.ts b/apps/cli/src/commands/list.command.ts index c4b4c592af9..4e2d7cb02e0 100644 --- a/apps/cli/src/commands/list.command.ts +++ b/apps/cli/src/commands/list.command.ts @@ -1,5 +1,3 @@ -import { firstValueFrom } from "rxjs"; - import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; @@ -128,7 +126,7 @@ export class ListCommand { } private async listFolders(options: Options) { - let folders = await firstValueFrom(this.folderService.folderViews$); + let folders = await this.folderService.getAllDecryptedFromState(); if (options.search != null && options.search.trim() !== "") { folders = CliUtils.searchFolders(folders, options.search); diff --git a/libs/angular/src/modules/vault-filter/vault-filter.service.ts b/libs/angular/src/modules/vault-filter/vault-filter.service.ts index 294774948db..38757d042c8 100644 --- a/libs/angular/src/modules/vault-filter/vault-filter.service.ts +++ b/libs/angular/src/modules/vault-filter/vault-filter.service.ts @@ -1,5 +1,5 @@ import { Injectable } from "@angular/core"; -import { from, mergeMap, Observable } from "rxjs"; +import { firstValueFrom, from, mergeMap, Observable } from "rxjs"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; @@ -90,7 +90,7 @@ export class VaultFilterService { return await this.policyService.policyAppliesToUser(PolicyType.PersonalOwnership); } - protected async getAllFoldersNested(folders?: FolderView[]): Promise[]> { + protected async getAllFoldersNested(folders: FolderView[]): Promise[]> { const nodes: TreeNode[] = []; folders.forEach((f) => { const folderCopy = new FolderView(); @@ -103,7 +103,9 @@ export class VaultFilterService { } async getFolderNested(id: string): Promise> { - const folders = await this.getAllFoldersNested(); + const folders = await this.getAllFoldersNested( + await firstValueFrom(this.folderService.folderViews$) + ); return ServiceUtils.getTreeNodeObject(folders, id) as TreeNode; } } diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 1aa5ebaa542..e90acd075e7 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -223,7 +223,6 @@ export const LOG_MAC_FAILURES = new InjectionToken("LOG_MAC_FAILURES"); I18nServiceAbstraction, CipherServiceAbstraction, StateServiceAbstraction, - BroadcasterServiceAbstraction, ], }, { diff --git a/libs/common/src/abstractions/folder/folder.service.abstraction.ts b/libs/common/src/abstractions/folder/folder.service.abstraction.ts index 8110fa01ac5..42e0420f9b3 100644 --- a/libs/common/src/abstractions/folder/folder.service.abstraction.ts +++ b/libs/common/src/abstractions/folder/folder.service.abstraction.ts @@ -12,6 +12,10 @@ export abstract class FolderService { clearCache: () => Promise; encrypt: (model: FolderView, key?: SymmetricCryptoKey) => Promise; get: (id: string) => Promise; + /** + * @deprecated Only use in CLI! + */ + getAllDecryptedFromState: () => Promise; } export abstract class InternalFolderService extends FolderService { diff --git a/libs/common/src/abstractions/state.service.ts b/libs/common/src/abstractions/state.service.ts index 3b6758ae347..b88926635cb 100644 --- a/libs/common/src/abstractions/state.service.ts +++ b/libs/common/src/abstractions/state.service.ts @@ -1,4 +1,4 @@ -import { BehaviorSubject } from "rxjs"; +import { BehaviorSubject, Observable } from "rxjs"; import { KdfType } from "../enums/kdfType"; import { ThemeType } from "../enums/themeType"; @@ -28,6 +28,8 @@ export abstract class StateService { accounts: BehaviorSubject<{ [userId: string]: T }>; activeAccount: BehaviorSubject; + activeAccountUnlocked: Observable; + addAccount: (account: T) => Promise; setActiveUser: (userId: string) => Promise; clean: (options?: StorageOptions) => Promise; diff --git a/libs/common/src/services/folder/folder.service.ts b/libs/common/src/services/folder/folder.service.ts index f2b7d37550d..222ea44fb35 100644 --- a/libs/common/src/services/folder/folder.service.ts +++ b/libs/common/src/services/folder/folder.service.ts @@ -1,9 +1,8 @@ import { BehaviorSubject } from "rxjs"; -import { BroadcasterService } from "../../abstractions/broadcaster.service"; import { CipherService } from "../../abstractions/cipher.service"; import { CryptoService } from "../../abstractions/crypto.service"; -import { FolderService as FolderServiceAbstraction } from "../../abstractions/folder/folder.service.abstraction"; +import { InternalFolderService as InternalFolderServiceAbstraction } from "../../abstractions/folder/folder.service.abstraction"; import { I18nService } from "../../abstractions/i18n.service"; import { StateService } from "../../abstractions/state.service"; import { Utils } from "../../misc/utils"; @@ -13,9 +12,7 @@ import { Folder } from "../../models/domain/folder"; import { SymmetricCryptoKey } from "../../models/domain/symmetricCryptoKey"; import { FolderView } from "../../models/view/folderView"; -const BroadcasterSubscriptionId = "FolderService"; - -export class FolderService implements FolderServiceAbstraction { +export class FolderService implements InternalFolderServiceAbstraction { private _folders: BehaviorSubject = new BehaviorSubject([]); private _folderViews: BehaviorSubject = new BehaviorSubject([]); @@ -26,15 +23,14 @@ export class FolderService implements FolderServiceAbstraction { private cryptoService: CryptoService, private i18nService: I18nService, private cipherService: CipherService, - private stateService: StateService, - private broadcasterService: BroadcasterService + private stateService: StateService ) { - this.stateService.activeAccount.subscribe(async (activeAccount) => { + this.stateService.activeAccountUnlocked.subscribe(async (unlocked) => { if ((Utils.global as any).bitwardenContainerService == null) { return; } - if (activeAccount == null) { + if (!unlocked) { this._folders.next([]); this._folderViews.next([]); return; @@ -44,20 +40,6 @@ export class FolderService implements FolderServiceAbstraction { await this.updateObservables(data); }); - - // TODO: Broadcasterservice should be removed or replaced with observables - this.broadcasterService.subscribe(BroadcasterSubscriptionId, async (message: any) => { - switch (message.command) { - case "unlocked": { - const data = await this.stateService.getEncryptedFolders(); - - await this.updateObservables(data); - break; - } - default: - break; - } - }); } async clearCache(): Promise { @@ -78,6 +60,16 @@ export class FolderService implements FolderServiceAbstraction { return folders.find((folder) => folder.id === id); } + /** + * @deprecated Only use in CLI! + */ + async getAllDecryptedFromState(): Promise { + const data = await this.stateService.getEncryptedFolders(); + const folders = Object.values(data || {}).map((f) => new Folder(f)); + + return this.decryptFolders(folders); + } + async upsert(folder: FolderData | FolderData[]): Promise { let folders = await this.stateService.getEncryptedFolders(); if (folders == null) { @@ -149,6 +141,14 @@ export class FolderService implements FolderServiceAbstraction { private async updateObservables(foldersMap: { [id: string]: FolderData }) { const folders = Object.values(foldersMap || {}).map((f) => new Folder(f)); + this._folders.next(folders); + + if (await this.cryptoService.hasKey()) { + this._folderViews.next(await this.decryptFolders(folders)); + } + } + + private async decryptFolders(folders: Folder[]) { const decryptFolderPromises = folders.map((f) => f.decrypt()); const decryptedFolders = await Promise.all(decryptFolderPromises); @@ -158,7 +158,6 @@ export class FolderService implements FolderServiceAbstraction { noneFolder.name = this.i18nService.t("noneFolder"); decryptedFolders.push(noneFolder); - this._folders.next(folders); - this._folderViews.next(decryptedFolders); + return decryptedFolders; } } diff --git a/libs/common/src/services/state.service.ts b/libs/common/src/services/state.service.ts index 332e4829345..8fe91210f64 100644 --- a/libs/common/src/services/state.service.ts +++ b/libs/common/src/services/state.service.ts @@ -56,6 +56,7 @@ export class StateService< { accounts = new BehaviorSubject<{ [userId: string]: TAccount }>({}); activeAccount = new BehaviorSubject(null); + activeAccountUnlocked = new BehaviorSubject(false); private hasBeenInited = false; private isRecoveredSession = false; @@ -70,7 +71,21 @@ export class StateService< protected stateMigrationService: StateMigrationService, protected stateFactory: StateFactory, protected useAccountCache: boolean = true - ) {} + ) { + // If the account gets changed, verify the new account is unlocked + this.activeAccount.subscribe(async (userId) => { + if (userId == null && this.activeAccountUnlocked.getValue() == false) { + return; + } else if (userId == null) { + this.activeAccountUnlocked.next(false); + } + + // FIXME: This should be refactored into AuthService or a similar service, + // as checking for the existance of the crypto key is a low level + // implementation detail. + this.activeAccountUnlocked.next((await this.getCryptoMasterKey()) != null); + }); + } async init(): Promise { if (this.hasBeenInited) { @@ -499,6 +514,15 @@ export class StateService< account, this.reconcileOptions(options, await this.defaultInMemoryOptions()) ); + + if (options.userId == this.activeAccount.getValue()) { + const nextValue = value != null; + + // Avoid emitting if we are already unlocked + if (this.activeAccountUnlocked.getValue() != nextValue) { + this.activeAccountUnlocked.next(nextValue); + } + } } async getCryptoMasterKeyAuto(options?: StorageOptions): Promise { From 23bf69c733bec7828babf45b4a6bd1988d533bad Mon Sep 17 00:00:00 2001 From: Vince Grassia <593223+vgrassia@users.noreply.github.com> Date: Mon, 18 Jul 2022 09:06:15 -0400 Subject: [PATCH 67/86] Change branch push event (#3106) --- .github/workflows/build-desktop.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-desktop.yml b/.github/workflows/build-desktop.yml index b6ca6833f36..ee571b2592a 100644 --- a/.github/workflows/build-desktop.yml +++ b/.github/workflows/build-desktop.yml @@ -16,7 +16,7 @@ on: branches: - 'master' - 'rc' - - 'hotfix-rc/**' + - 'hotfix-rc' paths: - 'apps/desktop/**' - 'libs/**' From 5ef3aac5e2d8e565e7639d70e0cbd4994debc5db Mon Sep 17 00:00:00 2001 From: Vincent Salucci <26154748+vincentsalucci@users.noreply.github.com> Date: Mon, 18 Jul 2022 09:17:31 -0500 Subject: [PATCH 68/86] [CL-17] Tabs - Router (#2952) * [CL-17] Tabs - Routing * Updated titles * Revision changes * Replaced testing module to achieve active default state * Z-index for tab vs disabled * Revision changes * Updated z index on focus * Fixed background color of selected tab * Force text colors in-case bootstrap tries to override * Remove unecessary css rules, fix tabs moving when active Co-authored-by: Hinton --- libs/components/src/index.ts | 1 + libs/components/src/tabs/index.ts | 3 + .../src/tabs/tab-group.component.html | 6 ++ .../src/tabs/tab-group.component.ts | 7 ++ .../src/tabs/tab-item.component.html | 26 ++++++ .../components/src/tabs/tab-item.component.ts | 54 ++++++++++++ libs/components/src/tabs/tabs.module.ts | 13 +++ libs/components/src/tabs/tabs.stories.ts | 84 +++++++++++++++++++ libs/components/tailwind.config.base.js | 2 + 9 files changed, 196 insertions(+) create mode 100644 libs/components/src/tabs/index.ts create mode 100644 libs/components/src/tabs/tab-group.component.html create mode 100644 libs/components/src/tabs/tab-group.component.ts create mode 100644 libs/components/src/tabs/tab-item.component.html create mode 100644 libs/components/src/tabs/tab-item.component.ts create mode 100644 libs/components/src/tabs/tabs.module.ts create mode 100644 libs/components/src/tabs/tabs.stories.ts diff --git a/libs/components/src/index.ts b/libs/components/src/index.ts index a6c9e54c57a..5ccceae874c 100644 --- a/libs/components/src/index.ts +++ b/libs/components/src/index.ts @@ -6,4 +6,5 @@ export * from "./callout"; export * from "./form-field"; export * from "./menu"; export * from "./utils/i18n-mock.service"; +export * from "./tabs"; export * from "./submit-button"; diff --git a/libs/components/src/tabs/index.ts b/libs/components/src/tabs/index.ts new file mode 100644 index 00000000000..9b45ff1d43b --- /dev/null +++ b/libs/components/src/tabs/index.ts @@ -0,0 +1,3 @@ +export * from "./tabs.module"; +export * from "./tab-group.component"; +export * from "./tab-item.component"; diff --git a/libs/components/src/tabs/tab-group.component.html b/libs/components/src/tabs/tab-group.component.html new file mode 100644 index 00000000000..ad681b168f0 --- /dev/null +++ b/libs/components/src/tabs/tab-group.component.html @@ -0,0 +1,6 @@ +
    + +
    diff --git a/libs/components/src/tabs/tab-group.component.ts b/libs/components/src/tabs/tab-group.component.ts new file mode 100644 index 00000000000..856ab1f1e22 --- /dev/null +++ b/libs/components/src/tabs/tab-group.component.ts @@ -0,0 +1,7 @@ +import { Component } from "@angular/core"; + +@Component({ + selector: "bit-tab-group", + templateUrl: "./tab-group.component.html", +}) +export class TabGroupComponent {} diff --git a/libs/components/src/tabs/tab-item.component.html b/libs/components/src/tabs/tab-item.component.html new file mode 100644 index 00000000000..951cfb3be18 --- /dev/null +++ b/libs/components/src/tabs/tab-item.component.html @@ -0,0 +1,26 @@ + +
    + + + + + + + diff --git a/libs/components/src/tabs/tab-item.component.ts b/libs/components/src/tabs/tab-item.component.ts new file mode 100644 index 00000000000..cda332e26d5 --- /dev/null +++ b/libs/components/src/tabs/tab-item.component.ts @@ -0,0 +1,54 @@ +import { Component, Input } from "@angular/core"; + +@Component({ + selector: "bit-tab-item", + templateUrl: "./tab-item.component.html", +}) +export class TabItemComponent { + @Input() route: string; // ['/route'] + @Input() disabled = false; + + get baseClassList(): string[] { + return [ + "tw-block", + "tw-relative", + "tw-py-2", + "tw-px-4", + "tw-font-semibold", + "tw-transition", + "tw-rounded-t", + "tw-border-0", + "tw-border-x", + "tw-border-t-4", + "tw-border-transparent", + "tw-border-solid", + "!tw-text-main", + "hover:tw-underline", + "hover:!tw-text-main", + "focus:tw-z-10", + "focus:tw-outline-none", + "focus:tw-ring-2", + "focus:tw-ring-primary-700", + "disabled:tw-bg-secondary-100", + "disabled:!tw-text-muted", + "disabled:tw-no-underline", + "disabled:tw-cursor-not-allowed", + ]; + } + + get activeClassList(): string { + return [ + "tw--mb-px", + "tw-border-x-secondary-300", + "tw-border-t-primary-500", + "tw-border-b", + "tw-border-b-background", + "tw-bg-background", + "!tw-text-primary-500", + "hover:tw-border-t-primary-700", + "hover:!tw-text-primary-700", + "focus:tw-border-t-primary-700", + "focus:!tw-text-primary-700", + ].join(" "); + } +} diff --git a/libs/components/src/tabs/tabs.module.ts b/libs/components/src/tabs/tabs.module.ts new file mode 100644 index 00000000000..016bde504a5 --- /dev/null +++ b/libs/components/src/tabs/tabs.module.ts @@ -0,0 +1,13 @@ +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { RouterModule } from "@angular/router"; + +import { TabGroupComponent } from "./tab-group.component"; +import { TabItemComponent } from "./tab-item.component"; + +@NgModule({ + imports: [CommonModule, RouterModule], + exports: [TabGroupComponent, TabItemComponent], + declarations: [TabGroupComponent, TabItemComponent], +}) +export class TabsModule {} diff --git a/libs/components/src/tabs/tabs.stories.ts b/libs/components/src/tabs/tabs.stories.ts new file mode 100644 index 00000000000..15ee57fa7d5 --- /dev/null +++ b/libs/components/src/tabs/tabs.stories.ts @@ -0,0 +1,84 @@ +import { CommonModule } from "@angular/common"; +import { Component } from "@angular/core"; +import { RouterModule } from "@angular/router"; +import { Meta, moduleMetadata, Story } from "@storybook/angular"; + +import { TabGroupComponent } from "./tab-group.component"; +import { TabItemComponent } from "./tab-item.component"; + +@Component({ + selector: "bit-tab-active-dummy", + template: "Router - Active selected", +}) +class ActiveDummyComponent {} + +@Component({ + selector: "bit-tab-item-2-dummy", + template: "Router - Item 2 selected", +}) +class ItemTwoDummyComponent {} + +@Component({ + selector: "bit-tab-item-3-dummy", + template: "Router - Item 3 selected", +}) +class ItemThreeDummyComponent {} + +@Component({ + selector: "bit-tab-disabled-dummy", + template: "Router - Disabled selected", +}) +class DisabledDummyComponent {} + +export default { + title: "Component Library/Tabs", + component: TabGroupComponent, + decorators: [ + moduleMetadata({ + declarations: [ + TabGroupComponent, + TabItemComponent, + ActiveDummyComponent, + ItemTwoDummyComponent, + ItemThreeDummyComponent, + DisabledDummyComponent, + ], + imports: [ + CommonModule, + RouterModule.forRoot( + [ + { path: "", redirectTo: "active", pathMatch: "full" }, + { path: "active", component: ActiveDummyComponent }, + { path: "item-2", component: ItemTwoDummyComponent }, + { path: "item-3", component: ItemThreeDummyComponent }, + { path: "disabled", component: DisabledDummyComponent }, + ], + { useHash: true } + ), + ], + }), + ], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A17922", + }, + }, +} as Meta; + +const TabGroupTemplate: Story = (args: TabGroupComponent) => ({ + props: args, + template: ` + + Active + Item 2 + Item 3 + Disabled + +
    + +
    + `, +}); + +export const TabGroup = TabGroupTemplate.bind({}); diff --git a/libs/components/tailwind.config.base.js b/libs/components/tailwind.config.base.js index fd0caec7490..31ff19cb501 100644 --- a/libs/components/tailwind.config.base.js +++ b/libs/components/tailwind.config.base.js @@ -60,6 +60,8 @@ module.exports = { info: "var(--color-info-500)", primary: { 300: "var(--color-primary-300)", + 500: "var(--color-primary-500)", + 700: "var(--color-primary-700)", }, }, ringOffsetColor: ({ theme }) => ({ From abed118ef0b5e38902d49c680a699a927d6272c1 Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Mon, 18 Jul 2022 19:08:41 +0200 Subject: [PATCH 69/86] Fix input group disabled button styling (#3130) --- .../src/form-field/form-field.stories.ts | 21 +++++++++++++++++++ .../src/form-field/prefix.directive.ts | 2 ++ 2 files changed, 23 insertions(+) diff --git a/libs/components/src/form-field/form-field.stories.ts b/libs/components/src/form-field/form-field.stories.ts index 96cacb97645..d1d00c59175 100644 --- a/libs/components/src/form-field/form-field.stories.ts +++ b/libs/components/src/form-field/form-field.stories.ts @@ -180,6 +180,27 @@ const ButtonGroupTemplate: Story = (args: BitFormFieldCom export const ButtonInputGroup = ButtonGroupTemplate.bind({}); ButtonInputGroup.args = {}; +const DisabledButtonInputGroupTemplate: Story = ( + args: BitFormFieldComponent +) => ({ + props: args, + template: ` + + Label + + + + + `, +}); + +export const DisabledButtonInputGroup = DisabledButtonInputGroupTemplate.bind({}); +DisabledButtonInputGroup.args = {}; + const SelectTemplate: Story = (args: BitFormFieldComponent) => ({ props: args, template: ` diff --git a/libs/components/src/form-field/prefix.directive.ts b/libs/components/src/form-field/prefix.directive.ts index 010dbc056e5..edf600d4e7f 100644 --- a/libs/components/src/form-field/prefix.directive.ts +++ b/libs/components/src/form-field/prefix.directive.ts @@ -10,6 +10,8 @@ export const PrefixClasses = [ "tw-border-secondary-500", "tw-text-muted", "tw-rounded-none", + "disabled:!tw-text-muted", + "disabled:tw-border-secondary-500", ]; @Directive({ From 4d5df858e93febdc67aebd71abff5cb66836f005 Mon Sep 17 00:00:00 2001 From: Brandon Maharaj <107377945+BrandonM-Bitwarden@users.noreply.github.com> Date: Mon, 18 Jul 2022 17:47:53 -0400 Subject: [PATCH 70/86] chore: added new ui fields (#2991) --- .../src/app/settings/change-password.component.html | 11 +++++++++++ .../web/src/app/settings/change-password.component.ts | 4 ++++ apps/web/src/app/settings/profile.component.html | 10 ---------- apps/web/src/app/settings/profile.component.ts | 2 -- libs/common/src/models/request/passwordRequest.ts | 1 + 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/apps/web/src/app/settings/change-password.component.html b/apps/web/src/app/settings/change-password.component.html index 90df85042e6..3171d8e0ea8 100644 --- a/apps/web/src/app/settings/change-password.component.html +++ b/apps/web/src/app/settings/change-password.component.html @@ -64,6 +64,17 @@ +
    + + +
    -
    - - -
    diff --git a/apps/web/src/app/settings/profile.component.ts b/apps/web/src/app/settings/profile.component.ts index f93cc340ad6..fc7a56632ea 100644 --- a/apps/web/src/app/settings/profile.component.ts +++ b/apps/web/src/app/settings/profile.component.ts @@ -18,7 +18,6 @@ export class ProfileComponent implements OnInit { loading = true; profile: ProfileResponse; fingerprint: string; - hidePasswordHint = false; formPromise: Promise; @@ -41,7 +40,6 @@ export class ProfileComponent implements OnInit { if (fingerprint != null) { this.fingerprint = fingerprint.join("-"); } - this.hidePasswordHint = await this.keyConnectorService.getUsesKeyConnector(); } async submit() { diff --git a/libs/common/src/models/request/passwordRequest.ts b/libs/common/src/models/request/passwordRequest.ts index 9f7df7df373..eb3498a27f5 100644 --- a/libs/common/src/models/request/passwordRequest.ts +++ b/libs/common/src/models/request/passwordRequest.ts @@ -2,5 +2,6 @@ import { SecretVerificationRequest } from "./secretVerificationRequest"; export class PasswordRequest extends SecretVerificationRequest { newMasterPasswordHash: string; + masterPasswordHint: string; key: string; } From a302f08a7ccf983ebb781c578dd1fbd1b4f3ba27 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Tue, 19 Jul 2022 08:29:58 +0200 Subject: [PATCH 71/86] [EC-267] Remove unassigned from lists it is not suppsed to be in (#3102) * fix: remove unassigned from lists * fix: remove unnecessary filter --- .../organization-vault/organization-vault.component.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/src/app/modules/vault/modules/organization-vault/organization-vault.component.ts b/apps/web/src/app/modules/vault/modules/organization-vault/organization-vault.component.ts index aaf37e97e4c..1aee9a0a0a3 100644 --- a/apps/web/src/app/modules/vault/modules/organization-vault/organization-vault.component.ts +++ b/apps/web/src/app/modules/vault/modules/organization-vault/organization-vault.component.ts @@ -211,7 +211,7 @@ export class OrganizationVaultComponent implements OnInit, OnDestroy { if (this.organization.canEditAnyCollection) { comp.collectionIds = cipher.collectionIds; comp.collections = this.vaultFilterComponent.collections.fullList.filter( - (c) => !c.readOnly + (c) => !c.readOnly && c.id != null ); } comp.organization = this.organization; @@ -230,7 +230,7 @@ export class OrganizationVaultComponent implements OnInit, OnDestroy { component.type = this.type; if (this.organization.canEditAnyCollection) { component.collections = this.vaultFilterComponent.collections.fullList.filter( - (c) => !c.readOnly + (c) => !c.readOnly && c.id != null ); } if (this.collectionId != null) { @@ -285,7 +285,7 @@ export class OrganizationVaultComponent implements OnInit, OnDestroy { component.organizationId = this.organization.id; if (this.organization.canEditAnyCollection) { component.collections = this.vaultFilterComponent.collections.fullList.filter( - (c) => !c.readOnly + (c) => !c.readOnly && c.id != null ); } // Regardless of Admin state, the collection Ids need to passed manually as they are not assigned value From 0a4b8b15bc49e336ac668b2e80484a31194e5e5a Mon Sep 17 00:00:00 2001 From: Vitaly Baev Date: Tue, 19 Jul 2022 13:20:37 +0300 Subject: [PATCH 72/86] [PS-1122] Adds Mir payment system (#3079) * Adds Mir payment system * Fixes Mir regex pattern and formatting * Changes Mir logos to Russian ones * Localize Mir in select --- apps/browser/src/_locales/en/messages.json | 3 +++ apps/desktop/src/locales/en/messages.json | 5 ++++- apps/web/src/locales/en/messages.json | 3 +++ libs/angular/src/components/add-edit.component.ts | 1 + libs/angular/src/components/icon.component.ts | 1 + libs/angular/src/images/cards/mir-dark.png | Bin 0 -> 505 bytes libs/angular/src/images/cards/mir-light.png | Bin 0 -> 644 bytes libs/angular/src/pipes/credit-card-number.pipe.ts | 6 ++++++ libs/angular/src/scss/icons.scss | 2 ++ libs/common/src/importers/baseImporter.ts | 6 ++++++ 10 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 libs/angular/src/images/cards/mir-dark.png create mode 100644 libs/angular/src/images/cards/mir-light.png diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 8211f8eeb69..4592e295b8f 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -1973,5 +1973,8 @@ }, "disabledOrganizationFilterError" : { "message" : "Items in disabled Organizations cannot be accessed. Contact your Organization owner for assistance." + }, + "cardBrandMir": { + "message": "Mir" } } diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index 7d12b136e64..c86c37522ea 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -1972,5 +1972,8 @@ }, "neverLockWarning": { "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." - } + }, + "cardBrandMir": { + "message": "Mir" + } } diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 48d6f7fdf31..3a44482eb1e 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -5267,5 +5267,8 @@ }, "on": { "message": "On" + }, + "cardBrandMir": { + "message": "Mir" } } diff --git a/libs/angular/src/components/add-edit.component.ts b/libs/angular/src/components/add-edit.component.ts index bac45023a9f..da7862cc017 100644 --- a/libs/angular/src/components/add-edit.component.ts +++ b/libs/angular/src/components/add-edit.component.ts @@ -110,6 +110,7 @@ export class AddEditComponent implements OnInit { { name: "Maestro", value: "Maestro" }, { name: "UnionPay", value: "UnionPay" }, { name: "RuPay", value: "RuPay" }, + { name: i18nService.t("cardBrandMir"), value: "Mir" }, { name: i18nService.t("other"), value: "Other" }, ]; this.cardExpMonthOptions = [ diff --git a/libs/angular/src/components/icon.component.ts b/libs/angular/src/components/icon.component.ts index e715c57ec8d..0696649e1f9 100644 --- a/libs/angular/src/components/icon.component.ts +++ b/libs/angular/src/components/icon.component.ts @@ -20,6 +20,7 @@ const cardIcons: Record = { Maestro: "card-maestro", UnionPay: "card-union-pay", RuPay: "card-ru-pay", + Mir: "card-mir", }; @Component({ diff --git a/libs/angular/src/images/cards/mir-dark.png b/libs/angular/src/images/cards/mir-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..e158470db06b450ca10dc6f339aa2ba832609397 GIT binary patch literal 505 zcmV> z001vDJuomhFfc$bGd(XfJTEjoE;KzbH99XdJuNalFEl;>|NmoWZp+NhmzthQPFAtA zw&msLeSn6FjgnScV)F9yq^GKIbb35NN<2YH*xA~bnV#6$+rGcT$qYuS0000CbW%=J zKmgw$5bw{wfH0q6YC4H#0003zNklu!S}7zSXdR&D!&BA#m7?f&m_AG9m5 zB`ll#S<0LEDN!Ern7}wMn;KhE9ShDm_P)bNilVE!_^+N4+qKyeuKNEp^VbX#!3L8jMCAs>(s~6AcTO6|epaaOALkchb z56}WSK7^EbKxlnQ#vu(XU!eX8U9<-+aY!h==sx~pZrX=J8{t&_}`0MU|00000NkvXXu0mjfqjk}r literal 0 HcmV?d00001 diff --git a/libs/angular/src/images/cards/mir-light.png b/libs/angular/src/images/cards/mir-light.png new file mode 100644 index 0000000000000000000000000000000000000000..e49974152055802e5765ac170948031ed2b4aa4c GIT binary patch literal 644 zcmV-~0(BHUAOP6|SsgO&U zdc)n)Erw*J%e}BQUmy^G ze}MiGVE_ODYDq*vR9M69*J*EpFc`q`a)^5#pooLXP6xZxdF;NA@Bgj#v__#@(q*eJ zw%C8-0}biVzAz>*#)1tGjdFb^YB^|}(;|qRGBTLa zLbQ;DEM%d-3Gqav+!taNv@WJ}Glk0@wI$O)X(;LdH4A01DJI!Gn?JfbKRGBG=mgZ1}E^Dvm4bo?UgIGmIm59y?-?Ay+ eHDkPXz}N@yNTwLm_9*rM0000 = { { cardLength: 19, blocks: [6, 13] }, ], Amex: [{ cardLength: 15, blocks: [4, 6, 5] }], + Mir: [ + { cardLength: 16, blocks: [4, 4, 4, 4] }, + { cardLength: 17, blocks: [5, 4, 4, 4] }, + { cardLength: 18, blocks: [6, 4, 4, 4] }, + { cardLength: 19, blocks: [7, 4, 4, 4] }, + ], Other: [{ cardLength: 16, blocks: [4, 4, 4, 4] }], }; diff --git a/libs/angular/src/scss/icons.scss b/libs/angular/src/scss/icons.scss index 58c860ff7ed..eaf061912d3 100644 --- a/libs/angular/src/scss/icons.scss +++ b/libs/angular/src/scss/icons.scss @@ -9,6 +9,7 @@ $card-icons: ( "mastercard": $card-icons-base + "mastercard-light.png", "union-pay": $card-icons-base + "union_pay-light.png", "ru-pay": $card-icons-base + "ru_pay-light.png", + "mir": $card-icons-base + "mir-light.png", ); $card-icons-dark: ( @@ -21,6 +22,7 @@ $card-icons-dark: ( "mastercard": $card-icons-base + "mastercard-dark.png", "union-pay": $card-icons-base + "union_pay-dark.png", "ru-pay": $card-icons-base + "ru_pay-dark.png", + "mir": $card-icons-base + "mir-dark.png", ); .credit-card-icon { diff --git a/libs/common/src/importers/baseImporter.ts b/libs/common/src/importers/baseImporter.ts index 122b34724d8..0e1192a652b 100644 --- a/libs/common/src/importers/baseImporter.ts +++ b/libs/common/src/importers/baseImporter.ts @@ -301,6 +301,12 @@ export abstract class BaseImporter { return "Visa"; } + // Mir + re = new RegExp("^220[0-4]"); + if (cardNum.match(re) != null) { + return "Mir"; + } + return null; } From acbd789c2b16523453c9136deb48e2a1f7ad8c57 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Tue, 19 Jul 2022 14:51:08 +0200 Subject: [PATCH 73/86] [PS-683] Fix missed defaults and sentence cases (#3095) * chore: remove superfluous default * fix: translations * feat: dont update auto biometric but hide the option * feat: hide auto biometrics if biometrics are disabled * refactor: make updateBiometric easier to read and add bug note * chore: add comment about bug getting resolved * refactor: merge two if-cases --- .../popup/settings/settings.component.html | 6 +++- .../src/popup/settings/settings.component.ts | 4 +-- .../src/app/accounts/settings.component.html | 7 ++-- .../src/app/accounts/settings.component.ts | 36 ++++++++++--------- apps/desktop/src/locales/en/messages.json | 4 +-- 5 files changed, 30 insertions(+), 27 deletions(-) diff --git a/apps/browser/src/popup/settings/settings.component.html b/apps/browser/src/popup/settings/settings.component.html index 62d6bde5689..c7f4bb5042d 100644 --- a/apps/browser/src/popup/settings/settings.component.html +++ b/apps/browser/src/popup/settings/settings.component.html @@ -59,7 +59,11 @@ [(ngModel)]="biometric" />
    -
    +
    {{ biometricText | i18n }}
    -
    +