diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 203c7ae7607..2665f345568 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,7 +8,7 @@ apps/desktop/desktop_native @bitwarden/team-platform-dev apps/desktop/desktop_native/objc/src/native/autofill @bitwarden/team-autofill-dev apps/desktop/desktop_native/core/src/autofill @bitwarden/team-autofill-dev -## No ownership fo Cargo.lock and Cargo.toml to allow dependency updates +## No ownership for Cargo.lock and Cargo.toml to allow dependency updates apps/desktop/desktop_native/Cargo.lock apps/desktop/desktop_native/Cargo.toml @@ -96,6 +96,12 @@ libs/logging @bitwarden/team-platform-dev libs/storage-test-utils @bitwarden/team-platform-dev libs/messaging @bitwarden/team-platform-dev libs/messaging-internal @bitwarden/team-platform-dev +libs/serialization @bitwarden/team-platform-dev +libs/guid @bitwarden/team-platform-dev +libs/client-type @bitwarden/team-platform-dev +libs/core-test-utils @bitwarden/team-platform-dev +libs/state @bitwarden/team-platform-dev +libs/state-test-utils @bitwarden/team-platform-dev # Web utils used across app and connectors apps/web/src/utils/ @bitwarden/team-platform-dev # Web core and shared files diff --git a/.github/workflows/build-browser.yml b/.github/workflows/build-browser.yml index bd7d70e8543..be140b9a20e 100644 --- a/.github/workflows/build-browser.yml +++ b/.github/workflows/build-browser.yml @@ -269,19 +269,19 @@ jobs: # Declare variable as indexed array declare -a FILES - # Search for source files that are greater than 4M + # Search for source files that are greater than 5M TARGET_DIR='./browser-source/apps/browser' while IFS=' ' read -r RESULT; do FILES+=("$RESULT") - done < <(find $TARGET_DIR -size +4M) + done < <(find $TARGET_DIR -size +5M) # Validate results and provide messaging if [[ ${#FILES[@]} -ne 0 ]]; then - echo "File(s) exceeds size limit: 4MB" + echo "File(s) exceeds size limit: 5MB" for FILE in ${FILES[@]}; do echo "- $(du --si $FILE)" done - echo "ERROR Firefox rejects extension uploads that contain files larger than 4MB" + echo "ERROR Firefox rejects extension uploads that contain files larger than 5MB" # Invoke failure exit 1 fi diff --git a/.github/workflows/build-web.yml b/.github/workflows/build-web.yml index b4163d161cf..f00ae07fba3 100644 --- a/.github/workflows/build-web.yml +++ b/.github/workflows/build-web.yml @@ -280,7 +280,7 @@ jobs: IMAGE_NAME: ${{ steps.image-name.outputs.name }} run: | mkdir build - docker run --rm --volume $(pwd)/build:/temp --entrypoint bash \ + docker run --rm --volume $(pwd)/build:/temp --entrypoint sh \ $IMAGE_NAME -c "cp -r ./ /temp" zip -r web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip build diff --git a/.github/workflows/deploy-web.yml b/.github/workflows/deploy-web.yml index e21f7ae1e79..d3788dc77b9 100644 --- a/.github/workflows/deploy-web.yml +++ b/.github/workflows/deploy-web.yml @@ -69,7 +69,6 @@ jobs: azure_login_client_key_name: ${{ steps.config.outputs.azure_login_client_key_name }} azure_login_subscription_id_key_name: ${{ steps.config.outputs.azure_login_subscription_id_key_name }} retrieve_secrets_keyvault: ${{ steps.config.outputs.retrieve_secrets_keyvault }} - sync_utility: ${{ steps.config.outputs.sync_utility }} sync_delete_destination_files: ${{ steps.config.outputs.sync_delete_destination_files }} slack_channel_name: ${{ steps.config.outputs.slack_channel_name }} steps: @@ -127,8 +126,6 @@ jobs: echo "slack_channel_name=alerts-deploy-dev" >> $GITHUB_OUTPUT ;; esac - # Set the sync utility to use for deployment to the environment (az-sync or azcopy) - echo "sync_utility=azcopy" >> $GITHUB_OUTPUT - name: Environment Protection env: @@ -337,32 +334,6 @@ jobs: description: 'Deployment from branch/tag: ${{ inputs.branch-or-tag }}' ref: ${{ needs.artifact-check.outputs.artifact_build_commit }} - - name: Login to Azure - uses: bitwarden/gh-actions/azure-login@main - with: - subscription_id: ${{ secrets[needs.setup.outputs.azure_login_subscription_id_key_name] }} - tenant_id: ${{ secrets.AZURE_TENANT_ID }} - client_id: ${{ secrets[needs.setup.outputs.azure_login_client_key_name] }} - - - name: Retrieve Storage Account connection string for az sync - if: ${{ needs.setup.outputs.sync_utility == 'az-sync' }} - id: retrieve-secrets-az-sync - uses: bitwarden/gh-actions/get-keyvault-secrets@main - with: - keyvault: ${{ needs.setup.outputs.retrieve_secrets_keyvault }} - secrets: "sa-bitwarden-web-vault-dev-key-temp" - - - name: Retrieve Storage Account name and SPN credentials for azcopy - if: ${{ needs.setup.outputs.sync_utility == 'azcopy' }} - id: retrieve-secrets-azcopy - uses: bitwarden/gh-actions/get-keyvault-secrets@main - with: - keyvault: ${{ needs.setup.outputs.retrieve_secrets_keyvault }} - secrets: "sa-bitwarden-web-vault-name,sp-bitwarden-web-vault-password,sp-bitwarden-web-vault-appid,sp-bitwarden-web-vault-tenant" - - - name: Log out from Azure - uses: bitwarden/gh-actions/azure-logout@main - - name: 'Download latest cloud asset using GitHub Run ID: ${{ inputs.build-web-run-id }}' if: ${{ inputs.build-web-run-id }} uses: bitwarden/gh-actions/download-artifacts@main @@ -389,28 +360,32 @@ jobs: working-directory: apps/web run: unzip ${{ env._ENVIRONMENT_ARTIFACT }} - - name: Sync to Azure Storage Account using az storage blob sync - if: ${{ needs.setup.outputs.sync_utility == 'az-sync' }} - working-directory: apps/web - run: | - az storage blob sync \ - --source "./build" \ - --container '$web' \ - --connection-string "${{ steps.retrieve-secrets-az-sync.outputs.sa-bitwarden-web-vault-dev-key-temp }}" \ - --delete-destination=${{ inputs.force-delete-destination }} + - name: Login to Azure + uses: bitwarden/gh-actions/azure-login@main + with: + subscription_id: ${{ secrets[needs.setup.outputs.azure_login_subscription_id_key_name] }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets[needs.setup.outputs.azure_login_client_key_name] }} + + - name: Retrieve Storage Account name + id: retrieve-secrets-azcopy + uses: bitwarden/gh-actions/get-keyvault-secrets@main + with: + keyvault: ${{ needs.setup.outputs.retrieve_secrets_keyvault }} + secrets: "sa-bitwarden-web-vault-name" - name: Sync to Azure Storage Account using azcopy - if: ${{ needs.setup.outputs.sync_utility == 'azcopy' }} working-directory: apps/web env: - AZCOPY_AUTO_LOGIN_TYPE: SPN - AZCOPY_SPA_APPLICATION_ID: ${{ steps.retrieve-secrets-azcopy.outputs.sp-bitwarden-web-vault-appid }} - AZCOPY_SPA_CLIENT_SECRET: ${{ steps.retrieve-secrets-azcopy.outputs.sp-bitwarden-web-vault-password }} - AZCOPY_TENANT_ID: ${{ steps.retrieve-secrets-azcopy.outputs.sp-bitwarden-web-vault-tenant }} + AZCOPY_AUTO_LOGIN_TYPE: AZCLI + AZCOPY_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} run: | azcopy sync ./build 'https://${{ steps.retrieve-secrets-azcopy.outputs.sa-bitwarden-web-vault-name }}.blob.core.windows.net/$web/' \ --delete-destination=${{ inputs.force-delete-destination }} --compare-hash="MD5" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Debug sync logs if: ${{ inputs.debug }} run: cat /home/runner/.azcopy/*.log diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml index c96dae51c0e..57774fa9991 100644 --- a/.github/workflows/scan.yml +++ b/.github/workflows/scan.yml @@ -50,4 +50,7 @@ jobs: permissions: contents: read pull-requests: write - id-token: write \ No newline at end of file + id-token: write + with: + sonar-test-inclusions: "**/*.spec.ts" + sonar-exclusions: "**/*.spec.ts" diff --git a/apps/browser/package.json b/apps/browser/package.json index c0e8058a1bc..8cf643135a2 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -14,16 +14,13 @@ "build:watch:firefox": "npm run build:firefox -- --watch", "build:watch:opera": "npm run build:opera -- --watch", "build:watch:safari": "npm run build:safari -- --watch", + "build:watch:firefox:mv3": "cross-env MANIFEST_VERSION=3 npm run build:firefox -- --watch", + "build:watch:safari:mv3": "cross-env MANIFEST_VERSION=3 npm run build:safari -- --watch", "build:prod:chrome": "cross-env NODE_ENV=production npm run build:chrome", "build:prod:edge": "cross-env NODE_ENV=production npm run build:edge", "build:prod:firefox": "cross-env NODE_ENV=production npm run build:firefox", "build:prod:opera": "cross-env NODE_ENV=production npm run build:opera", "build:prod:safari": "cross-env NODE_ENV=production npm run build:safari", - "build:nonprod:chrome": "cross-env npm run build:chrome", - "build:nonprod:edge": "cross-env npm run build:edge", - "build:nonprod:firefox": "cross-env npm run build:firefox", - "build:nonprod:opera": "cross-env npm run build:opera", - "build:nonprod:safari": "cross-env npm run build:safari", "dist:chrome": "npm run build:prod:chrome && mkdir -p dist && ./scripts/compress.sh dist-chrome.zip", "dist:edge": "npm run build:prod:edge && mkdir -p dist && ./scripts/compress.sh dist-edge.zip", "dist:firefox": "npm run build:prod:firefox && mkdir -p dist && ./scripts/compress.sh dist-firefox.zip", @@ -32,15 +29,6 @@ "dist:firefox:mv3": "cross-env MANIFEST_VERSION=3 npm run dist:firefox", "dist:opera:mv3": "cross-env MANIFEST_VERSION=3 npm run dist:opera", "dist:safari:mv3": "cross-env MANIFEST_VERSION=3 npm run dist:safari", - "dist:chrome:nonprod": "npm run build:nonprod:chrome && mkdir -p dist && ./scripts/compress.sh dist-chrome.zip", - "dist:edge:nonprod": "npm run build:nonprod:edge && mkdir -p dist && ./scripts/compress.sh dist-edge.zip", - "dist:firefox:nonprod": "npm run build:nonprod:firefox && mkdir -p dist && ./scripts/compress.sh dist-firefox.zip", - "dist:opera:nonprod": "npm run build:nonprod:opera && mkdir -p dist && ./scripts/compress.sh dist-opera.zip", - "dist:safari:nonprod": "npm run build:nonprod:safari && ./scripts/package-safari.ps1", - "dist:edge:mv3:nonprod": "cross-env MANIFEST_VERSION=3 npm run dist:edge:nonprod", - "dist:firefox:mv3:nonprod": "cross-env MANIFEST_VERSION=3 npm run dist:firefox:nonprod", - "dist:opera:mv3:nonprod": "cross-env MANIFEST_VERSION=3 npm run dist:opera:nonprod", - "dist:safari:mv3:nonprod": "cross-env MANIFEST_VERSION=3 npm run dist:safari:nonprod", "test": "jest", "test:watch": "jest --watch", "test:watch:all": "jest --watchAll", diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index d7aef05ab92..65ee9cab458 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "البحث في الخزانة" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "تعديل" }, diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index 5e7bf056980..16b74ffe175 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Seyfdə axtar" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Düzəliş et" }, diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index a49899eaee0..d7a1db3adc8 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Пошук у сховішчы" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Рэдагаваць" }, diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index 672e029a662..79e13cdb677 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Търсене в трезора" }, + "resetSearch": { + "message": "Нулиране на търсенето" + }, "edit": { "message": "Редактиране" }, diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json index 4e30612b9a6..a3c029fb963 100644 --- a/apps/browser/src/_locales/bn/messages.json +++ b/apps/browser/src/_locales/bn/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "ভল্ট খুঁজুন" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "সম্পাদনা" }, diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json index be64d0bade5..8a94ba3e9e9 100644 --- a/apps/browser/src/_locales/bs/messages.json +++ b/apps/browser/src/_locales/bs/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Search vault" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Edit" }, diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index f6c40da1096..42fb9c24003 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Cerca en la caixa forta" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Edita" }, diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json index 4e0096a1520..3f8dd2e2b48 100644 --- a/apps/browser/src/_locales/cs/messages.json +++ b/apps/browser/src/_locales/cs/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Vyhledat v trezoru" }, + "resetSearch": { + "message": "Resetovat hledání" + }, "edit": { "message": "Upravit" }, diff --git a/apps/browser/src/_locales/cy/messages.json b/apps/browser/src/_locales/cy/messages.json index 1235b49dd2c..307373da9aa 100644 --- a/apps/browser/src/_locales/cy/messages.json +++ b/apps/browser/src/_locales/cy/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Chwilio'r gell" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Golygu" }, diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index bc34810f97f..4b6da81a994 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Søg i boks" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Redigér" }, diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index 2e3d9369c41..9ef82a6d5ae 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Tresor durchsuchen" }, + "resetSearch": { + "message": "Suche zurücksetzen" + }, "edit": { "message": "Bearbeiten" }, diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index 014d17b74c8..fa4f3ac0f3c 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Αναζήτηση στο vault" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Επεξεργασία" }, diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index a1b41b44bfd..ad933c24875 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -3657,25 +3657,6 @@ "thisRequestIsNoLongerValid": { "message": "This request is no longer valid." }, - "areYouTryingToAccessYourAccount": { - "message": "Are you trying to access your account?" - }, - "logInConfirmedForEmailOnDevice": { - "message": "Login confirmed for $EMAIL$ on $DEVICE$", - "placeholders": { - "email": { - "content": "$1", - "example": "name@example.com" - }, - "device": { - "content": "$2", - "example": "iOS" - } - } - }, - "youDeniedALogInAttemptFromAnotherDevice": { - "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." - }, "loginRequestHasAlreadyExpired": { "message": "Login request has already expired." }, diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json index a17a48e95b8..a70fbd85123 100644 --- a/apps/browser/src/_locales/en_GB/messages.json +++ b/apps/browser/src/_locales/en_GB/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Search vault" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Edit" }, diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json index 9f383c2f0e3..39de06249fc 100644 --- a/apps/browser/src/_locales/en_IN/messages.json +++ b/apps/browser/src/_locales/en_IN/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Search vault" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Edit" }, diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index 35a28528f49..3b681054abc 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Buscar en caja fuerte" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Editar" }, diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json index daadcbf00e9..8b61aa70a60 100644 --- a/apps/browser/src/_locales/et/messages.json +++ b/apps/browser/src/_locales/et/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Otsi hoidlast" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Muuda" }, diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index e5f836fcaae..73bd992dacb 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Bilatu kutxa gotorrean" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Editatu" }, diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index e551e96f74a..18afcb775f9 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "جستجوی گاوصندوق" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "ویرایش" }, diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index 22f2046bae3..894b50b5273 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Etsi holvista" }, + "resetSearch": { + "message": "Nollaa haku" + }, "edit": { "message": "Muokkaa" }, @@ -887,7 +890,7 @@ "message": "Viimeistele kirjautuminen seuraamalla seuraavia vaiheita." }, "followTheStepsBelowToFinishLoggingInWithSecurityKey": { - "message": "Follow the steps below to finish logging in with your security key." + "message": "Seuraa alla olevia ohjeita, jotta pääset kirjautumaan suojausavaimellasi." }, "restartRegistration": { "message": "Aloita rekisteröityminen alusta" @@ -1063,7 +1066,7 @@ "message": "Tallenna" }, "notificationViewAria": { - "message": "View $ITEMNAME$, opens in new window", + "message": "Näytä $ITEMNAME$. Avautuu uudessa ikkunassa", "placeholders": { "itemName": { "content": "$1" @@ -1093,15 +1096,15 @@ } }, "notificationLoginSaveConfirmation": { - "message": "saved to Bitwarden.", + "message": "tallennettu Bitwardeniin.", "description": "Shown to user after item is saved." }, "notificationLoginUpdatedConfirmation": { - "message": "updated in Bitwarden.", + "message": "päivitetty Bitwardeniin.", "description": "Shown to user after item is updated." }, "selectItemAriaLabel": { - "message": "Select $ITEMTYPE$, $ITEMNAME$", + "message": "Valitse $ITEMTYPE$, $ITEMNAME$", "description": "Used by screen readers. $1 is the item type (like vault or folder), $2 is the selected item name.", "placeholders": { "itemType": { @@ -1121,7 +1124,7 @@ "description": "Button text for updating an existing login entry." }, "unlockToSave": { - "message": "Unlock to save this login", + "message": "Avaa tallentaaksesi tämä kirjautumistieto", "description": "User prompt to take action in order to save the login they just entered." }, "saveLogin": { @@ -1174,10 +1177,10 @@ "description": "Detailed error message shown when saving login details fails." }, "changePasswordWarning": { - "message": "After changing your password, you will need to log in with your new password. Active sessions on other devices will be logged out within one hour." + "message": "Kun olet vaihtanut salasanaasi, sinun täytyy kirjautua sisään uudella salasanalla. Aktiiviset istunnot muilla laitteilla kirjataan ulos tunnin kuluessa." }, "accountRecoveryUpdateMasterPasswordSubtitle": { - "message": "Change your master password to complete account recovery." + "message": "Vaihda pääsalasanasi, jotta voit jatkaa tilin palautusta." }, "enableChangedPasswordNotification": { "message": "Kysy päivitetäänkö kirjautumistieto" @@ -1372,7 +1375,7 @@ "message": "Ominaisuus ei ole käytettävissä" }, "legacyEncryptionUnsupported": { - "message": "Legacy encryption is no longer supported. Please contact support to recover your account." + "message": "Vanhaa salausta ei enää tueta. Ota yhteyttä tukeen palauttaaksesi tilisi." }, "premiumMembership": { "message": "Premium-jäsenyys" @@ -1606,10 +1609,10 @@ "message": "Automaattitäytön ehdotukset" }, "autofillSpotlightTitle": { - "message": "Easily find autofill suggestions" + "message": "Löydä helposti automaattisen täytön ehdotukset" }, "autofillSpotlightDesc": { - "message": "Turn off your browser's autofill settings, so they don't conflict with Bitwarden." + "message": "Poista käytöstä selaimesi oletuksena asetetut automaattisen täytön asetukset, joten ne eivät aiheuta ongelmia Bitwardenin kanssa." }, "turnOffBrowserAutofill": { "message": "Poista automaattitäyttö käytöstä selaimessa $BROWSER$", @@ -1830,7 +1833,7 @@ "message": "Turvakoodi (CVC/CVV)" }, "cardNumber": { - "message": "card number" + "message": "kortin numero" }, "ex": { "message": "esim." @@ -1932,7 +1935,7 @@ "message": "SSH-avain" }, "typeNote": { - "message": "Note" + "message": "Muistiinpano" }, "newItemHeader": { "message": "Uusi $TYPE$", @@ -2166,7 +2169,7 @@ "message": "Aseta PIN-koodi Bitwardenin avaukselle. PIN-asetukset tyhjentyvät, jos kirjaudut laajennuksesta kokonaan ulos." }, "setPinCode": { - "message": "You can use this PIN to unlock Bitwarden. Your PIN will be reset if you ever fully log out of the application." + "message": "Voit käyttää PIN-koodia avataksesi Bitwardenin. PIN-koodisi nollataan, mikäli kirjaudut täysin ulos sovelluksesta." }, "pinRequired": { "message": "PIN-koodi vaaditaan." @@ -2497,10 +2500,10 @@ "message": "Organisaatiokäytäntö estää kohteiden tuonnin yksityiseen holviisi." }, "restrictCardTypeImport": { - "message": "Cannot import card item types" + "message": "Ei voitu tuoda kortteja" }, "restrictCardTypeImportDesc": { - "message": "A policy set by 1 or more organizations prevents you from importing cards to your vaults." + "message": "Käytäntö, jonka on asettanut 1 tai useampi organisaatiosi estää sinua tuomasta korttitietoja holviisi." }, "domainsTitle": { "message": "Verkkotunnukset", @@ -2547,7 +2550,7 @@ } }, "atRiskPassword": { - "message": "At-risk password" + "message": "Riskialttiit salasanat" }, "atRiskPasswords": { "message": "Vaarantuneet salasanat" @@ -2584,7 +2587,7 @@ } }, "atRiskChangePrompt": { - "message": "Your password for this site is at-risk. $ORGANIZATION$ has requested that you change it.", + "message": "Salasanasi tälle sivustolle ei ole turvallinen. $ORGANIZATION$ on ilmoittanut, että se tulisi vaihtaa.", "placeholders": { "organization": { "content": "$1", @@ -2594,7 +2597,7 @@ "description": "Notification body when a login triggers an at-risk password change request and the change password domain is known." }, "atRiskNavigatePrompt": { - "message": "$ORGANIZATION$ wants you to change this password because it is at-risk. Navigate to your account settings to change the password.", + "message": "$ORGANIZATION$ ovat pyytäneet, että vaihdat tämän salasnaan, sillä se ei ole turvallinen. Mene tilin asetuksiin ja vaihda salasana.", "placeholders": { "organization": { "content": "$1", @@ -2723,7 +2726,7 @@ "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": "Käyttökertojen enimmäismäärä on saavutettu", "description": "This text will be displayed after a Send has been accessed the maximum amount of times." }, "hideTextByDefault": { @@ -2929,7 +2932,7 @@ "message": "Sinun on vahvistettava sähköpostiosoitteesi käyttääksesi ominaisuutta. Voit vahvistaa osoitteesi verkkoholvissa." }, "masterPasswordSuccessfullySet": { - "message": "Master password successfully set" + "message": "Pääsalasana asetettu" }, "updatedMasterPassword": { "message": "Pääsalasanasi on vaihdettu" @@ -3070,13 +3073,13 @@ "message": "Yksilöllistä tunnistetta ei löytynyt." }, "removeMasterPasswordForOrganizationUserKeyConnector": { - "message": "A master password is no longer required for members of the following organization. Please confirm the domain below with your organization administrator." + "message": "Pääsalasanaa ei enää tarvita tämän organisaation jäsenille. Ole hyvä ja vahvista alla oleva verkkotunnus organisaation ylläpitäjän kanssa." }, "organizationName": { "message": "Organisaation nimi" }, "keyConnectorDomain": { - "message": "Key Connector domain" + "message": "Key Connector URL" }, "leaveOrganization": { "message": "Poistu organisaatiosta" @@ -3464,7 +3467,7 @@ "message": "Pyyntö lähetetty" }, "loginRequestApprovedForEmailOnDevice": { - "message": "Login request approved for $EMAIL$ on $DEVICE$", + "message": "Kirjautuminen hyväksytty tunnuksella $EMAIL$ laitteella $DEVICE$", "placeholders": { "email": { "content": "$1", @@ -3477,13 +3480,13 @@ } }, "youDeniedLoginAttemptFromAnotherDevice": { - "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + "message": "Kirjautumispyyntö on estetty toiselta laitteelta. Jos se olit sinä, yritä kirjautua uudelleen samalla laitteella." }, "device": { - "message": "Device" + "message": "Laite" }, "loginStatus": { - "message": "Login status" + "message": "Kirjautumisen tila" }, "masterPasswordChanged": { "message": "Pääsalasana tallennettiin" @@ -3582,53 +3585,53 @@ "message": "Muista tämä laite tehdäksesi tulevista kirjautumisista saumattomia" }, "manageDevices": { - "message": "Manage devices" + "message": "Hallinnoi laitteita" }, "currentSession": { - "message": "Current session" + "message": "Nykyinen istunto" }, "mobile": { - "message": "Mobile", + "message": "Mobiili", "description": "Mobile app" }, "extension": { - "message": "Extension", + "message": "Laajennus", "description": "Browser extension/addon" }, "desktop": { - "message": "Desktop", + "message": "Työpöytä", "description": "Desktop app" }, "webVault": { - "message": "Web vault" + "message": "Verkkoholvi" }, "webApp": { - "message": "Web app" + "message": "Verkkosovellus" }, "cli": { - "message": "CLI" + "message": "Komentorivi" }, "sdk": { "message": "SDK", "description": "Software Development Kit" }, "requestPending": { - "message": "Request pending" + "message": "Pyyntö odottaa" }, "firstLogin": { - "message": "First login" + "message": "Ensimmäinen kirjautuminen" }, "trusted": { - "message": "Trusted" + "message": "Luotettu" }, "needsApproval": { - "message": "Needs approval" + "message": "Vaatii hyväksynnän" }, "devices": { - "message": "Devices" + "message": "Laitteet" }, "accessAttemptBy": { - "message": "Access attempt by $EMAIL$", + "message": "Kirjautumisyritys sähköpostilla $EMAIL$ ", "placeholders": { "email": { "content": "$1", @@ -3637,28 +3640,28 @@ } }, "confirmAccess": { - "message": "Confirm access" + "message": "Hyväksy pääsy" }, "denyAccess": { - "message": "Deny access" + "message": "Estä pääsy" }, "time": { - "message": "Time" + "message": "Aika" }, "deviceType": { - "message": "Device Type" + "message": "Laitteen tyyppi" }, "loginRequest": { - "message": "Login request" + "message": "Kirjautumispyyntö" }, "thisRequestIsNoLongerValid": { - "message": "This request is no longer valid." + "message": "Tämä pyyntö ei ole enää voimassa." }, "areYouTryingToAccessYourAccount": { - "message": "Are you trying to access your account?" + "message": "Yritätkö kirjautua tilillesi?" }, "logInConfirmedForEmailOnDevice": { - "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "message": "Kirjautuminen vahvistettu tunnuksella $EMAIL$ laitteella $DEVICE$", "placeholders": { "email": { "content": "$1", @@ -3671,16 +3674,16 @@ } }, "youDeniedALogInAttemptFromAnotherDevice": { - "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + "message": "Estit toisen laitteen lähettämän kirjautumispyynnön. Jos kuitenkin tunnistit kirjautumisyrityksen, suorita kirjautuminen uudelleen." }, "loginRequestHasAlreadyExpired": { - "message": "Login request has already expired." + "message": "Kirjautumispyyntö on jo vanhentunut." }, "justNow": { - "message": "Just now" + "message": "juuri nyt" }, "requestedXMinutesAgo": { - "message": "Requested $MINUTES$ minutes ago", + "message": "pyydetty $MINUTES$ minuuttia sitten", "placeholders": { "minutes": { "content": "$1", @@ -3710,10 +3713,10 @@ "message": "Pyydä hyväksyntää ylläpidolta" }, "unableToCompleteLogin": { - "message": "Unable to complete login" + "message": "Kirjautuminen epäonnistui" }, "loginOnTrustedDeviceOrAskAdminToAssignPassword": { - "message": "You need to log in on a trusted device or ask your administrator to assign you a password." + "message": "Sinun on kirjauduttava luotettuun laitteeseen tai pyydettävä järjestelmänvalvojaasi antamaan sinulle salasana." }, "ssoIdentifierRequired": { "message": "Organisaation kertakirjautumistunniste tarvitaan." @@ -3789,23 +3792,23 @@ "message": "Organisaatio ei ole luotettu" }, "emergencyAccessTrustWarning": { - "message": "For the security of your account, only confirm if you have granted emergency access to this user and their fingerprint matches what is displayed in their account" + "message": "Tilisi turvallisuuden varmistamiseksi, vahvista vain, jos olet antanut hätäpääsyn tälle käyttäjälle ja hänen sormenjälkensä vastaa sitä, mitä hänen tilillään näkyy" }, "orgTrustWarning": { - "message": "For the security of your account, only proceed if you are a member of this organization, have account recovery enabled, and the fingerprint displayed below matches the organization's fingerprint." + "message": "Tilisi turvallisuuden takaamiseksi jatka vain, jos olet tämän organisaation jäsen, tilin palautus on käytössä ja alla näkyvä sormenjälki vastaa organisaatiosi sormenjälkeä." }, "orgTrustWarning1": { - "message": "This organization has an Enterprise policy that will enroll you in account recovery. Enrollment will allow organization administrators to change your password. Only proceed if you recognize this organization and the fingerprint phrase displayed below matches the organization's fingerprint." + "message": "Tällä organisaatiolla on yrityskäytäntö, joka tulee ilmi, kun yrität palauttaa tiliäsi. Ilmoittautuminen sallii organisaation ylläpitäjien vaihtaa salasanasi. Jatka vain, jos tunnistat tämän organisaation ja alla näkyvän sormenjäljen, joka vastaa organisaation sormenjälkeä." }, "trustUser": { "message": "Luota käyttäjään" }, "sendsTitleNoItems": { - "message": "Send sensitive information safely", + "message": "Lähetä arkaluonteisia tietoja turvallisesti", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendsBodyNoItems": { - "message": "Share files and data securely with anyone, on any platform. Your information will remain end-to-end encrypted while limiting exposure.", + "message": "Jaa tiedostoja ja dataa turvallisesti kenen tahansa kanssa millä tahansa alustalla. Tiedot pysyvät päästä päähän salattuina.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "inputRequired": { @@ -4395,23 +4398,23 @@ "description": "Label indicating the most common import formats" }, "uriMatchDefaultStrategyHint": { - "message": "URI match detection is how Bitwarden identifies autofill suggestions.", + "message": "URI:n Säännöllinen lauseke -asetus on se tapa, jolla Bitwarden tekee automaattisen täytön.", "description": "Explains to the user that URI match detection determines how Bitwarden suggests autofill options, and clarifies that this default strategy applies when no specific match detection is set for a login item." }, "regExAdvancedOptionWarning": { - "message": "\"Regular expression\" is an advanced option with increased risk of exposing credentials.", + "message": "Säänöllinen lauseke -asetus on kehittynyt asetus, joka lisää kirjautumistietoja kaappausriskiä.", "description": "Content for dialog which warns a user when selecting 'regular expression' matching strategy as a cipher match strategy" }, "startsWithAdvancedOptionWarning": { - "message": "\"Starts with\" is an advanced option with increased risk of exposing credentials.", + "message": "Alkaa sanoilla -asetus on kehittynyt asetus, joka lisää kirjautumistietoja kaappausriskiä.", "description": "Content for dialog which warns a user when selecting 'starts with' matching strategy as a cipher match strategy" }, "uriMatchWarningDialogLink": { - "message": "More about match detection", + "message": "Lisätietoa vastaavuustunnistuksesta", "description": "Link to match detection docs on warning dialog for advance match strategy" }, "uriAdvancedOption": { - "message": "Advanced options", + "message": "Lisäasetukset", "description": "Advanced option placeholder for uri option component" }, "confirmContinueToBrowserSettingsTitle": { @@ -4598,7 +4601,7 @@ } }, "copyFieldCipherName": { - "message": "Copy $FIELD$, $CIPHERNAME$", + "message": "Kopioi $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { @@ -4754,16 +4757,16 @@ "message": "Hanki mobiilisovellus" }, "getTheMobileAppDesc": { - "message": "Access your passwords on the go with the Bitwarden mobile app." + "message": "Pääse käsiksi salasanoihisi, jos et pääse tietokoneen ääreen Bitwarden-mobiilisovelluksella." }, "getTheDesktopApp": { "message": "Hanki työpöytäsovellus" }, "getTheDesktopAppDesc": { - "message": "Access your vault without a browser, then set up unlock with biometrics to expedite unlocking in both the desktop app and browser extension." + "message": "Käytä holviasi ilman selainta ja aseta sitten lukitus biometriikan avulla nopeuttaaksesi lukituksen avaamista sekä työpöytäsovelluksessa että selaimessa." }, "downloadFromBitwardenNow": { - "message": "Download from bitwarden.com now" + "message": "Lataa bitwarden.comista nyt" }, "getItOnGooglePlay": { "message": "Hanki se Google Playstä" @@ -5233,16 +5236,16 @@ "message": "Biometrinen avaus ei ole tällä hetkellä käytettävissä tuntemattomasta syystä." }, "unlockVault": { - "message": "Unlock your vault in seconds" + "message": "Avaa holvisi lukitus sekunneissa" }, "unlockVaultDesc": { - "message": "You can customize your unlock and timeout settings to more quickly access your vault." + "message": "Voit muokata avaus- ja aikakatkaisuasetuksiasi päästäksesi holvisi nopeammin käsiksi." }, "unlockPinSet": { - "message": "Unlock PIN set" + "message": "PIN asetettu" }, "unlockWithBiometricSet": { - "message": "Unlock with biometrics set" + "message": "Biometrinen kirjautuminen otettu käyttöön" }, "authenticating": { "message": "Todennetaan" @@ -5464,7 +5467,7 @@ "message": "Holvin asetukset" }, "emptyVaultDescription": { - "message": "The vault protects more than just your passwords. Store secure logins, IDs, cards and notes securely here." + "message": "Holvi suojaa muutakin kuin salasanojasi. Säilytä kirjautumsitietojen lisäksi kortteja, muistiinpanoja ja henkilötietoja turvallisesti." }, "introCarouselLabel": { "message": "Tervetuloa Bitwardeniin" @@ -5500,7 +5503,7 @@ "message": "Tuo olemassa olevat salasanat" }, "emptyVaultNudgeBody": { - "message": "Use the importer to quickly transfer logins to Bitwarden without manually adding them." + "message": "Käytä tuojaa siirtääksesi kirjautumisia nopeasti Bitwardeniin lisäämättä niitä manuaalisesti." }, "emptyVaultNudgeButton": { "message": "Tuo nyt" @@ -5509,19 +5512,19 @@ "message": "Tervetuloa holviisi!" }, "hasItemsVaultNudgeBodyOne": { - "message": "Autofill items for the current page" + "message": "Täytä nykyisen sivun kohteet automaattisesti" }, "hasItemsVaultNudgeBodyTwo": { - "message": "Favorite items for easy access" + "message": "Suosikkikohteita helppoon käyttöön" }, "hasItemsVaultNudgeBodyThree": { - "message": "Search your vault for something else" + "message": "Etsi holvistasi jotain muuta" }, "newLoginNudgeTitle": { "message": "Säästä aikaa automaattitäytöllä" }, "newLoginNudgeBodyOne": { - "message": "Include a", + "message": "Sisällytä a", "description": "This is in multiple parts to allow for bold text in the middle of the sentence.", "example": "Include a Website so this login appears as an autofill suggestion." }, @@ -5531,63 +5534,63 @@ "example": "Include a Website so this login appears as an autofill suggestion." }, "newLoginNudgeBodyTwo": { - "message": "so this login appears as an autofill suggestion.", + "message": ", joten tämä kirjautuminen näkyy automaattisen täytön ehdotuksena.", "description": "This is in multiple parts to allow for bold text in the middle of the sentence.", "example": "Include a Website so this login appears as an autofill suggestion." }, "newCardNudgeTitle": { - "message": "Seamless online checkout" + "message": "Saumaton verkkomaksaminen" }, "newCardNudgeBody": { - "message": "With cards, easily autofill payment forms securely and accurately." + "message": "Korteilla voit helposti täyttää automaattisesti maksulomakkeet turvallisesti ja oikein." }, "newIdentityNudgeTitle": { - "message": "Simplify creating accounts" + "message": "Yksinkertaista tilien luomista" }, "newIdentityNudgeBody": { - "message": "With identities, quickly autofill long registration or contact forms." + "message": "Identiteettien avulla täytä pitkät rekisteröinti- tai yhteydenottolomakkeet nopeasti automaattisesti." }, "newNoteNudgeTitle": { - "message": "Keep your sensitive data safe" + "message": "Pidä arkaluonteiset tietosi turvassa" }, "newNoteNudgeBody": { - "message": "With notes, securely store sensitive data like banking or insurance details." + "message": "Muistiinpanojen avulla tallennetaan turvallisesti arkaluonteiset tiedot, kuten pankkitiedot." }, "newSshNudgeTitle": { - "message": "Developer-friendly SSH access" + "message": "Kehittäjäystävällinen SSH-käyttö" }, "newSshNudgeBodyOne": { - "message": "Store your keys and connect with the SSH agent for fast, encrypted authentication.", + "message": "Säilytä avaimet ja yhdistä SSH-agenttiin, niin saat nopean ja salatun todennuksen.", "description": "Two part message", "example": "Store your keys and connect with the SSH agent for fast, encrypted authentication. Learn more about SSH agent" }, "newSshNudgeBodyTwo": { - "message": "Learn more about SSH agent", + "message": "Lue lisää SSH-agentista", "description": "Two part message", "example": "Store your keys and connect with the SSH agent for fast, encrypted authentication. Learn more about SSH agent" }, "generatorNudgeTitle": { - "message": "Quickly create passwords" + "message": "Luo salasanat nopeasti" }, "generatorNudgeBodyOne": { - "message": "Easily create strong and unique passwords by clicking on", + "message": "Luo helposti vahvoja ja uniikkeja salasanoja klikkaamalla", "description": "Two part message", "example": "Easily create strong and unique passwords by clicking on {icon} to help you keep your logins secure." }, "generatorNudgeBodyTwo": { - "message": "to help you keep your logins secure.", + "message": "auttaakssi sinua pitämään kirjautumisesi turvassa.", "description": "Two part message", "example": "Easily create strong and unique passwords by clicking on {icon} to help you keep your logins secure." }, "generatorNudgeBodyAria": { - "message": "Easily create strong and unique passwords by clicking on the Generate password button to help you keep your logins secure.", + "message": "Luo helposti vahvoja ja uniikkeja salasanoja klikkaamalla Luo salasana -painiketta. Sen avuilla voit pitää kirjautumisesi turvallisina.", "description": "Aria label for the body content of the generator nudge" }, "noPermissionsViewPage": { - "message": "You do not have permissions to view this page. Try logging in with a different account." + "message": "Sinulla ei ole oikeuksia tähän sivuun. Yritä kirjautua sisään toisella tilillä." }, "wasmNotSupported": { - "message": "WebAssembly is not supported on your browser or is not enabled. WebAssembly is required to use the Bitwarden app.", + "message": "WebAssembly ei ole tuettu selaimessasi tai se ei ole käytössä. WebAssembly vaaditaan, jotta voi käyttää Bitwardenia.", "description": "'WebAssembly' is a technical term and should not be translated." } } diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json index 88610d6874c..dfc8d65cfd9 100644 --- a/apps/browser/src/_locales/fil/messages.json +++ b/apps/browser/src/_locales/fil/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Hanapin ang vault" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "I-edit" }, diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json index 680a19f33cc..c35f4ca4bb9 100644 --- a/apps/browser/src/_locales/fr/messages.json +++ b/apps/browser/src/_locales/fr/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Rechercher dans le coffre" }, + "resetSearch": { + "message": "Réinitialiser la recherche" + }, "edit": { "message": "Modifier" }, @@ -1063,7 +1066,7 @@ "message": "Enregistrer" }, "notificationViewAria": { - "message": "View $ITEMNAME$, opens in new window", + "message": "Afficher $ITEMNAME$, s'ouvre dans une nouvelle fenêtre", "placeholders": { "itemName": { "content": "$1" @@ -1076,14 +1079,14 @@ "description": "Aria label for the new item button in notification bar confirmation message when error is prompted" }, "notificationEditTooltip": { - "message": "Edit before saving", + "message": "Modifier avant d'enregistrer", "description": "Tooltip and Aria label for edit button on cipher item" }, "newNotification": { "message": "Nouvelle notification" }, "labelWithNotification": { - "message": "$LABEL$: New notification", + "message": "$LABEL$: Nouvelle notification", "description": "Label for the notification with a new login suggestion.", "placeholders": { "label": { @@ -1101,7 +1104,7 @@ "description": "Shown to user after item is updated." }, "selectItemAriaLabel": { - "message": "Select $ITEMTYPE$, $ITEMNAME$", + "message": "Sélectionner $ITEMTYPE$, $ITEMNAME$", "description": "Used by screen readers. $1 is the item type (like vault or folder), $2 is the selected item name.", "placeholders": { "itemType": { @@ -1141,7 +1144,7 @@ "description": "Message displayed when login details are successfully updated." }, "loginUpdateTaskSuccess": { - "message": "Great job! You took the steps to make you and $ORGANIZATION$ more secure.", + "message": "Bon travail ! Vous avez pris les mesures pour rendre vous et $ORGANIZATION$ plus sécurisés.", "placeholders": { "organization": { "content": "$1" @@ -1150,7 +1153,7 @@ "description": "Shown to user after login is updated." }, "loginUpdateTaskSuccessAdditional": { - "message": "Thank you for making $ORGANIZATION$ more secure. You have $TASK_COUNT$ more passwords to update.", + "message": "Merci d'avoir rendu $ORGANIZATION$ plus sécurisé. Il vous reste $TASK_COUNT$ mots de passe à mettre à jour.", "placeholders": { "organization": { "content": "$1" @@ -1174,10 +1177,10 @@ "description": "Detailed error message shown when saving login details fails." }, "changePasswordWarning": { - "message": "After changing your password, you will need to log in with your new password. Active sessions on other devices will be logged out within one hour." + "message": "Après avoir changé votre mot de passe, vous devrez vous connecter avec votre nouveau mot de passe. Les sessions actives sur d'autres appareils seront déconnectées dans l'heure qui suit." }, "accountRecoveryUpdateMasterPasswordSubtitle": { - "message": "Change your master password to complete account recovery." + "message": "Changez votre mot de passe principal pour finaliser la récupération de compte." }, "enableChangedPasswordNotification": { "message": "Demander de mettre à jour un identifiant existant" @@ -1372,7 +1375,7 @@ "message": "Fonctionnalité indisponible" }, "legacyEncryptionUnsupported": { - "message": "Legacy encryption is no longer supported. Please contact support to recover your account." + "message": "Le chiffrement hérité n'est plus pris en charge. Veuillez contacter le support pour récupérer votre compte." }, "premiumMembership": { "message": "Adhésion Premium" @@ -1606,10 +1609,10 @@ "message": "Suggestions de saisie automatique" }, "autofillSpotlightTitle": { - "message": "Easily find autofill suggestions" + "message": "Trouver facilement des suggestions de remplissage automatique" }, "autofillSpotlightDesc": { - "message": "Turn off your browser's autofill settings, so they don't conflict with Bitwarden." + "message": "Désactivez les paramètres de remplissage automatique de votre navigateur pour qu'ils n'entrent pas en conflit avec Bitwarden." }, "turnOffBrowserAutofill": { "message": "Désactiver le remplissage automatique de $BROWSER$", @@ -1830,7 +1833,7 @@ "message": "Code de sécurité" }, "cardNumber": { - "message": "card number" + "message": "numéro de carte" }, "ex": { "message": "ex." @@ -2166,7 +2169,7 @@ "message": "Définissez votre code PIN pour déverrouiller Bitwarden. Les paramètres relatifs à votre code PIN seront réinitialisés si vous vous déconnectez complètement de l'application." }, "setPinCode": { - "message": "You can use this PIN to unlock Bitwarden. Your PIN will be reset if you ever fully log out of the application." + "message": "Vous pouvez utiliser ce code PIN pour déverrouiller Bitwarden. Votre code PIN sera réinitialisé si vous vous déconnectez complètement de l'application." }, "pinRequired": { "message": "Le code PIN est requis." @@ -2217,7 +2220,7 @@ "message": "Utiliser ce mot de passe" }, "useThisPassphrase": { - "message": "Use this passphrase" + "message": "Utilisez cette phrase secrète" }, "useThisUsername": { "message": "Utiliser ce nom d'utilisateur" @@ -2497,10 +2500,10 @@ "message": "Une politique d'organisation a bloqué l'import d'éléments dans votre coffre personel." }, "restrictCardTypeImport": { - "message": "Cannot import card item types" + "message": "Impossible d'importer des types d'éléments de carte" }, "restrictCardTypeImportDesc": { - "message": "A policy set by 1 or more organizations prevents you from importing cards to your vaults." + "message": "Une politique définie par 1 ou plusieurs organisations vous empêche d'importer des cartes dans vos coffres." }, "domainsTitle": { "message": "Domaines", @@ -2584,7 +2587,7 @@ } }, "atRiskChangePrompt": { - "message": "Your password for this site is at-risk. $ORGANIZATION$ has requested that you change it.", + "message": "Votre mot de passe pour ce site est à risque. $ORGANIZATION$ vous a demandé de le modifier.", "placeholders": { "organization": { "content": "$1", @@ -2594,7 +2597,7 @@ "description": "Notification body when a login triggers an at-risk password change request and the change password domain is known." }, "atRiskNavigatePrompt": { - "message": "$ORGANIZATION$ wants you to change this password because it is at-risk. Navigate to your account settings to change the password.", + "message": "$ORGANIZATION$ souhaite que vous changiez ce mot de passe car il est à risque. Accédez aux paramètres de votre compte pour modifier le mot de passe.", "placeholders": { "organization": { "content": "$1", @@ -2632,14 +2635,14 @@ "description": "Description of the review at-risk login slide on the at-risk password page carousel" }, "reviewAtRiskLoginSlideImgAltPeriod": { - "message": "Illustration of a list of logins that are at-risk." + "message": "Illustration d'une liste de connexions à risque." }, "generatePasswordSlideDesc": { "message": "Générez rapidement un mot de passe fort et unique grâce au menu de saisie automatique de Bitwarden sur le site à risque.", "description": "Description of the generate password slide on the at-risk password page carousel" }, "generatePasswordSlideImgAltPeriod": { - "message": "Illustration of the Bitwarden autofill menu displaying a generated password." + "message": "Illustration du menu de remplissage automatique de Bitwarden affichant un mot de passe généré." }, "updateInBitwarden": { "message": "Mettre à jour dans Bitwarden" @@ -2649,7 +2652,7 @@ "description": "Description of the update in Bitwarden slide on the at-risk password page carousel" }, "updateInBitwardenSlideImgAltPeriod": { - "message": "Illustration of a Bitwarden’s notification prompting the user to update the login." + "message": "Illustration d'une notification de Bitwarden invitant l'utilisateur à mettre à jour la connexion." }, "turnOnAutofill": { "message": "Activer la saisie automatique" @@ -2723,7 +2726,7 @@ "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": "Nombre maximal d'accès atteint", "description": "This text will be displayed after a Send has been accessed the maximum amount of times." }, "hideTextByDefault": { @@ -2929,7 +2932,7 @@ "message": "Vous devez vérifier votre courriel pour utiliser cette fonctionnalité. Vous pouvez vérifier votre courriel dans le coffre web." }, "masterPasswordSuccessfullySet": { - "message": "Master password successfully set" + "message": "Mot de passe principal défini avec succès" }, "updatedMasterPassword": { "message": "Mot de passe principal mis à jour" @@ -3070,13 +3073,13 @@ "message": "Aucun identifiant unique trouvé." }, "removeMasterPasswordForOrganizationUserKeyConnector": { - "message": "A master password is no longer required for members of the following organization. Please confirm the domain below with your organization administrator." + "message": "Un mot de passe principal n’est plus requis pour les membres de l’organisation suivante. Veuillez confirmer le domaine ci-dessous auprès de l'administrateur de votre organisation." }, "organizationName": { "message": "Nom de l'organisation" }, "keyConnectorDomain": { - "message": "Key Connector domain" + "message": "Domaine du connecteur clé" }, "leaveOrganization": { "message": "Quitter l'organisation" @@ -3112,7 +3115,7 @@ } }, "exportingIndividualVaultWithAttachmentsDescription": { - "message": "Only the individual vault items including attachments associated with $EMAIL$ will be exported. Organization vault items will not be included", + "message": "Seuls les éléments individuels du coffre-fort, y compris les pièces jointes associées à $EMAIL$, seront exportés. Les éléments du coffre-fort de l'organisation ne seront pas inclus", "placeholders": { "email": { "content": "$1", @@ -3464,7 +3467,7 @@ "message": "Demande envoyée" }, "loginRequestApprovedForEmailOnDevice": { - "message": "Login request approved for $EMAIL$ on $DEVICE$", + "message": "Demande de connexion approuvée pour $EMAIL$ sur $DEVICE$", "placeholders": { "email": { "content": "$1", @@ -3477,16 +3480,16 @@ } }, "youDeniedLoginAttemptFromAnotherDevice": { - "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + "message": "Vous avez refusé une tentative de connexion depuis un autre appareil. Si c'était vous, essayez de vous reconnecter avec l'appareil." }, "device": { - "message": "Device" + "message": "Appareil" }, "loginStatus": { - "message": "Login status" + "message": "Statut de connexion" }, "masterPasswordChanged": { - "message": "Master password saved" + "message": "Mot de passe principal enregistré" }, "exposedMasterPassword": { "message": "Mot de passe principal exposé" @@ -3582,10 +3585,10 @@ "message": "Mémorisez cet appareil pour faciliter les futures connexions" }, "manageDevices": { - "message": "Manage devices" + "message": "Gérer les appareils" }, "currentSession": { - "message": "Current session" + "message": "Session en cours" }, "mobile": { "message": "Mobile", @@ -3596,14 +3599,14 @@ "description": "Browser extension/addon" }, "desktop": { - "message": "Desktop", + "message": "Bureau", "description": "Desktop app" }, "webVault": { - "message": "Web vault" + "message": "Coffre-fort Web" }, "webApp": { - "message": "Web app" + "message": "Application web" }, "cli": { "message": "CLI" @@ -3613,22 +3616,22 @@ "description": "Software Development Kit" }, "requestPending": { - "message": "Request pending" + "message": "Demande en attente" }, "firstLogin": { - "message": "First login" + "message": "Première connexion" }, "trusted": { - "message": "Trusted" + "message": "Approuvé" }, "needsApproval": { - "message": "Needs approval" + "message": "Requiert une approbation" }, "devices": { - "message": "Devices" + "message": "Appareils" }, "accessAttemptBy": { - "message": "Access attempt by $EMAIL$", + "message": "Tentative d'accès par $EMAIL$", "placeholders": { "email": { "content": "$1", @@ -3637,28 +3640,28 @@ } }, "confirmAccess": { - "message": "Confirm access" + "message": "Confirmer l'accès" }, "denyAccess": { - "message": "Deny access" + "message": "Refuser l'accès" }, "time": { - "message": "Time" + "message": "Temps" }, "deviceType": { - "message": "Device Type" + "message": "Type d'appareil" }, "loginRequest": { - "message": "Login request" + "message": "Demande de connexion" }, "thisRequestIsNoLongerValid": { - "message": "This request is no longer valid." + "message": "Cette demande n'est plus valide." }, "areYouTryingToAccessYourAccount": { - "message": "Are you trying to access your account?" + "message": "Essayez-vous d'accéder à votre compte ?" }, "logInConfirmedForEmailOnDevice": { - "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "message": "Connexion confirmée pour $EMAIL$ sur $DEVICE$", "placeholders": { "email": { "content": "$1", @@ -3671,16 +3674,16 @@ } }, "youDeniedALogInAttemptFromAnotherDevice": { - "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + "message": "Vous avez refusé une tentative de connexion depuis un autre appareil. Si c'était vraiment vous, essayez de vous reconnecter avec l'appareil." }, "loginRequestHasAlreadyExpired": { - "message": "Login request has already expired." + "message": "La demande de connexion a déjà expiré." }, "justNow": { - "message": "Just now" + "message": "À l’instant" }, "requestedXMinutesAgo": { - "message": "Requested $MINUTES$ minutes ago", + "message": "Demandé $MINUTES$ il y a quelques minutes", "placeholders": { "minutes": { "content": "$1", @@ -3710,10 +3713,10 @@ "message": "Demander l'approbation de l'administrateur" }, "unableToCompleteLogin": { - "message": "Unable to complete login" + "message": "Impossible de terminer la connexion" }, "loginOnTrustedDeviceOrAskAdminToAssignPassword": { - "message": "You need to log in on a trusted device or ask your administrator to assign you a password." + "message": "Vous devez vous connecter sur un appareil de confiance ou demander à votre administrateur de vous attribuer un mot de passe." }, "ssoIdentifierRequired": { "message": "Identifiant SSO de l'organisation requis." @@ -3786,26 +3789,26 @@ "message": "Ne pas faire confiance" }, "organizationNotTrusted": { - "message": "Organization is not trusted" + "message": "L'organisation n'est pas fiable" }, "emergencyAccessTrustWarning": { - "message": "For the security of your account, only confirm if you have granted emergency access to this user and their fingerprint matches what is displayed in their account" + "message": "Pour la sécurité de votre compte, ne confirmez que si vous avez accordé un accès d'urgence à cet utilisateur et que son empreinte digitale correspond à ce qui est affiché dans son compte" }, "orgTrustWarning": { - "message": "For the security of your account, only proceed if you are a member of this organization, have account recovery enabled, and the fingerprint displayed below matches the organization's fingerprint." + "message": "Pour la sécurité de votre compte, ne procédez que si vous êtes membre de cette organisation, que la récupération de compte est activée et que l'empreinte digitale affichée ci-dessous correspond à l'empreinte digitale de l'organisation." }, "orgTrustWarning1": { - "message": "This organization has an Enterprise policy that will enroll you in account recovery. Enrollment will allow organization administrators to change your password. Only proceed if you recognize this organization and the fingerprint phrase displayed below matches the organization's fingerprint." + "message": "Cette organisation dispose d’une politique d’entreprise qui vous inscrira au recouvrement de compte. L'inscription permettra aux administrateurs de l'organisation de modifier votre mot de passe. Ne continuez que si vous reconnaissez cette organisation et que la phrase d'empreinte digitale affichée ci-dessous correspond à l'empreinte digitale de l'organisation." }, "trustUser": { "message": "Faire confiance à l'utilisateur" }, "sendsTitleNoItems": { - "message": "Send sensitive information safely", + "message": "Envoyez des informations sensibles en toute sécurité", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendsBodyNoItems": { - "message": "Share files and data securely with anyone, on any platform. Your information will remain end-to-end encrypted while limiting exposure.", + "message": "Partagez des fichiers et des données en toute sécurité avec n'importe qui, sur n'importe quelle plateforme. Vos informations resteront cryptées de bout en bout tout en limitant l'exposition.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "inputRequired": { @@ -4395,19 +4398,19 @@ "description": "Label indicating the most common import formats" }, "uriMatchDefaultStrategyHint": { - "message": "URI match detection is how Bitwarden identifies autofill suggestions.", + "message": "La détection de correspondance d'URI est la manière dont Bitwarden identifie les suggestions de remplissage automatique.", "description": "Explains to the user that URI match detection determines how Bitwarden suggests autofill options, and clarifies that this default strategy applies when no specific match detection is set for a login item." }, "regExAdvancedOptionWarning": { - "message": "\"Regular expression\" is an advanced option with increased risk of exposing credentials.", + "message": "\"Expression régulière\" est une option avancée présentant un risque accru d’exposition des informations d’identification.", "description": "Content for dialog which warns a user when selecting 'regular expression' matching strategy as a cipher match strategy" }, "startsWithAdvancedOptionWarning": { - "message": "\"Starts with\" is an advanced option with increased risk of exposing credentials.", + "message": "\"Commence par\" est une option avancée présentant un risque accru d’exposition des informations d’identification.", "description": "Content for dialog which warns a user when selecting 'starts with' matching strategy as a cipher match strategy" }, "uriMatchWarningDialogLink": { - "message": "More about match detection", + "message": "En savoir plus sur la détection des correspondances", "description": "Link to match detection docs on warning dialog for advance match strategy" }, "uriAdvancedOption": { @@ -4560,7 +4563,7 @@ } }, "viewItemTitleWithField": { - "message": "View item - $ITEMNAME$ - $FIELD$", + "message": "Afficher l'élément - $ITEMNAME$ - $FIELD$", "description": "Title for a link that opens a view for an item.", "placeholders": { "itemname": { @@ -4584,7 +4587,7 @@ } }, "autofillTitleWithField": { - "message": "Autofill - $ITEMNAME$ - $FIELD$", + "message": "Remplissage automatique - $ITEMNAME$ - $FIELD$", "description": "Title for a button that autofills a login item.", "placeholders": { "itemname": { @@ -4598,7 +4601,7 @@ } }, "copyFieldCipherName": { - "message": "Copy $FIELD$, $CIPHERNAME$", + "message": "Copiez $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { @@ -4754,19 +4757,19 @@ "message": "Télécharger l'application mobile" }, "getTheMobileAppDesc": { - "message": "Access your passwords on the go with the Bitwarden mobile app." + "message": "Accédez à vos mots de passe en déplacement avec l'application mobile Bitwarden." }, "getTheDesktopApp": { "message": "Télécharger l'application de bureau" }, "getTheDesktopAppDesc": { - "message": "Access your vault without a browser, then set up unlock with biometrics to expedite unlocking in both the desktop app and browser extension." + "message": "Accédez à votre coffre-fort sans navigateur, puis configurez le déverrouillage avec la biométrie pour accélérer le déverrouillage à la fois dans l'application de bureau et dans l'extension du navigateur." }, "downloadFromBitwardenNow": { - "message": "Download from bitwarden.com now" + "message": "Téléchargez maintenant depuis bitwarden.com" }, "getItOnGooglePlay": { - "message": "Get it on Google Play" + "message": "Obtenez-le sur Google Play" }, "downloadOnTheAppStore": { "message": "Télécharger depuis l’App Store" @@ -5236,13 +5239,13 @@ "message": "Déverouillez votre coffre en quelques secondes" }, "unlockVaultDesc": { - "message": "You can customize your unlock and timeout settings to more quickly access your vault." + "message": "Vous pouvez personnaliser vos paramètres de déverrouillage et de délai d'attente pour accéder plus rapidement à votre coffre-fort." }, "unlockPinSet": { - "message": "Unlock PIN set" + "message": "Déverrouiller l'ensemble de codes PIN" }, "unlockWithBiometricSet": { - "message": "Unlock with biometrics set" + "message": "Déverrouiller avec l'ensemble biométrique" }, "authenticating": { "message": "Authentification" @@ -5256,7 +5259,7 @@ "description": "Notification message for when a password has been regenerated" }, "saveToBitwarden": { - "message": "Save to Bitwarden", + "message": "Enregistrer dans Bitwarden", "description": "Confirmation message for saving a login to Bitwarden" }, "spaceCharacterDescriptor": { @@ -5464,7 +5467,7 @@ "message": "Options du coffre" }, "emptyVaultDescription": { - "message": "The vault protects more than just your passwords. Store secure logins, IDs, cards and notes securely here." + "message": "Le coffre-fort protège bien plus que vos mots de passe. Stockez ici en toute sécurité des identifiants, des cartes d'identité, des cartes et des notes sécurisés." }, "introCarouselLabel": { "message": "Bienvenue sur Bitwarden" @@ -5473,34 +5476,34 @@ "message": "Priorité à la sécurité" }, "securityPrioritizedBody": { - "message": "Save logins, cards, and identities to your secure vault. Bitwarden uses zero-knowledge, end-to-end encryption to protect what’s important to you." + "message": "Enregistrez les identifiants, les cartes et les identités dans votre coffre-fort sécurisé. Bitwarden utilise un cryptage de bout en bout à connaissance nulle pour protéger ce qui est important pour vous." }, "quickLogin": { "message": "Connexion rapide et facile" }, "quickLoginBody": { - "message": "Set up biometric unlock and autofill to log into your accounts without typing a single letter." + "message": "Configurez le déverrouillage biométrique et le remplissage automatique pour vous connecter à vos comptes sans taper une seule lettre." }, "secureUser": { - "message": "Level up your logins" + "message": "Améliorez vos connexions" }, "secureUserBody": { - "message": "Use the generator to create and save strong, unique passwords for all your accounts." + "message": "Utilisez le générateur pour créer et enregistrer des mots de passe forts et uniques pour tous vos comptes." }, "secureDevices": { - "message": "Your data, when and where you need it" + "message": "Vos données, quand et où vous en avez besoin" }, "secureDevicesBody": { - "message": "Save unlimited passwords across unlimited devices with Bitwarden mobile, browser, and desktop apps." + "message": "Enregistrez des mots de passe illimités sur un nombre illimité d'appareils avec les applications mobiles, de navigateur et de bureau Bitwarden." }, "nudgeBadgeAria": { "message": "1 notification" }, "emptyVaultNudgeTitle": { - "message": "Import existing passwords" + "message": "Importer des mots de passe existants" }, "emptyVaultNudgeBody": { - "message": "Use the importer to quickly transfer logins to Bitwarden without manually adding them." + "message": "Utilisez l'importateur pour transférer rapidement les connexions vers Bitwarden sans les ajouter manuellement." }, "emptyVaultNudgeButton": { "message": "Importer maintenant" @@ -5509,19 +5512,19 @@ "message": "Bienvenue dans votre coffre !" }, "hasItemsVaultNudgeBodyOne": { - "message": "Autofill items for the current page" + "message": "Remplissage automatique des éléments de la page actuelle" }, "hasItemsVaultNudgeBodyTwo": { - "message": "Favorite items for easy access" + "message": "Articles préférés pour un accès facile" }, "hasItemsVaultNudgeBodyThree": { - "message": "Search your vault for something else" + "message": "Recherchez autre chose dans votre coffre-fort" }, "newLoginNudgeTitle": { "message": "Gagnez du temps avec le remplissage automatique" }, "newLoginNudgeBodyOne": { - "message": "Include a", + "message": "Inclure un", "description": "This is in multiple parts to allow for bold text in the middle of the sentence.", "example": "Include a Website so this login appears as an autofill suggestion." }, @@ -5531,33 +5534,33 @@ "example": "Include a Website so this login appears as an autofill suggestion." }, "newLoginNudgeBodyTwo": { - "message": "so this login appears as an autofill suggestion.", + "message": "cette connexion apparaît donc comme une suggestion de remplissage automatique.", "description": "This is in multiple parts to allow for bold text in the middle of the sentence.", "example": "Include a Website so this login appears as an autofill suggestion." }, "newCardNudgeTitle": { - "message": "Seamless online checkout" + "message": "Paiement en ligne transparent" }, "newCardNudgeBody": { - "message": "With cards, easily autofill payment forms securely and accurately." + "message": "Avec les cartes, remplissez facilement et automatiquement les formulaires de paiement de manière sécurisée et précise." }, "newIdentityNudgeTitle": { - "message": "Simplify creating accounts" + "message": "Simplifiez la création de comptes" }, "newIdentityNudgeBody": { - "message": "With identities, quickly autofill long registration or contact forms." + "message": "Avec les identités, remplissez rapidement automatiquement les longs formulaires d'inscription ou de contact." }, "newNoteNudgeTitle": { - "message": "Keep your sensitive data safe" + "message": "Gardez vos données sensibles en sécurité" }, "newNoteNudgeBody": { - "message": "With notes, securely store sensitive data like banking or insurance details." + "message": "Avec des notes, stockez en toute sécurité des données sensibles telles que des informations bancaires ou d’assurance." }, "newSshNudgeTitle": { - "message": "Developer-friendly SSH access" + "message": "Accès SSH convivial pour les développeurs" }, "newSshNudgeBodyOne": { - "message": "Store your keys and connect with the SSH agent for fast, encrypted authentication.", + "message": "Stockez vos clés et connectez-vous à l'agent SSH pour une authentification rapide et cryptée.", "description": "Two part message", "example": "Store your keys and connect with the SSH agent for fast, encrypted authentication. Learn more about SSH agent" }, @@ -5567,27 +5570,27 @@ "example": "Store your keys and connect with the SSH agent for fast, encrypted authentication. Learn more about SSH agent" }, "generatorNudgeTitle": { - "message": "Quickly create passwords" + "message": "Créez rapidement des mots de passe" }, "generatorNudgeBodyOne": { - "message": "Easily create strong and unique passwords by clicking on", + "message": "Créez facilement des mots de passe forts et uniques en cliquant sur", "description": "Two part message", "example": "Easily create strong and unique passwords by clicking on {icon} to help you keep your logins secure." }, "generatorNudgeBodyTwo": { - "message": "to help you keep your logins secure.", + "message": "pour vous aider à garder vos connexions sécurisées.", "description": "Two part message", "example": "Easily create strong and unique passwords by clicking on {icon} to help you keep your logins secure." }, "generatorNudgeBodyAria": { - "message": "Easily create strong and unique passwords by clicking on the Generate password button to help you keep your logins secure.", + "message": "Créez facilement des mots de passe forts et uniques en cliquant sur le bouton Générer un mot de passe pour vous aider à sécuriser vos connexions.", "description": "Aria label for the body content of the generator nudge" }, "noPermissionsViewPage": { - "message": "You do not have permissions to view this page. Try logging in with a different account." + "message": "Vous n'avez pas les autorisations pour consulter cette page. Essayez de vous connecter avec un autre compte." }, "wasmNotSupported": { - "message": "WebAssembly is not supported on your browser or is not enabled. WebAssembly is required to use the Bitwarden app.", + "message": "WebAssembly n'est pas pris en charge sur votre navigateur ou n'est pas activé. WebAssembly est requis pour utiliser l'application Bitwarden.", "description": "'WebAssembly' is a technical term and should not be translated." } } diff --git a/apps/browser/src/_locales/gl/messages.json b/apps/browser/src/_locales/gl/messages.json index 559d0ca82b3..c7d47b61209 100644 --- a/apps/browser/src/_locales/gl/messages.json +++ b/apps/browser/src/_locales/gl/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Buscar na caixa forte" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Editar" }, diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json index e4d959785bf..c13bcad10c6 100644 --- a/apps/browser/src/_locales/he/messages.json +++ b/apps/browser/src/_locales/he/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "חיפוש בכספת" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "ערוך" }, diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json index 4fd2652d786..cc89f9cc2dd 100644 --- a/apps/browser/src/_locales/hi/messages.json +++ b/apps/browser/src/_locales/hi/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "वॉल्ट खोजे" }, + "resetSearch": { + "message": "खोज रीसेट करें" + }, "edit": { "message": "संपादन करें" }, diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json index 07c3e20cd18..97bd79f2950 100644 --- a/apps/browser/src/_locales/hr/messages.json +++ b/apps/browser/src/_locales/hr/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Pretraži trezor" }, + "resetSearch": { + "message": "Ponovno postavljanje pretraživanja" + }, "edit": { "message": "Uredi" }, @@ -1830,7 +1833,7 @@ "message": "Sigurnosni kôd" }, "cardNumber": { - "message": "card number" + "message": "broj kartice" }, "ex": { "message": "npr." @@ -3464,7 +3467,7 @@ "message": "Zahtjev poslan" }, "loginRequestApprovedForEmailOnDevice": { - "message": "Login request approved for $EMAIL$ on $DEVICE$", + "message": "Prijava za $EMAIL$ potvrđena na uređaju $DEVICE$", "placeholders": { "email": { "content": "$1", @@ -3477,13 +3480,13 @@ } }, "youDeniedLoginAttemptFromAnotherDevice": { - "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + "message": "Odbijena je prijava na drugom uređaju. Ako si ovo stvarno ti, pokušaj se ponovno prijaviti uređajem." }, "device": { - "message": "Device" + "message": "Uređaj" }, "loginStatus": { - "message": "Login status" + "message": "Status prijave" }, "masterPasswordChanged": { "message": "Glavna lozinka promijenjena" @@ -3582,17 +3585,17 @@ "message": "Zapamti ovaj uređaj kako bi buduće prijave bile brže" }, "manageDevices": { - "message": "Manage devices" + "message": "Upravljaj uređajima" }, "currentSession": { - "message": "Current session" + "message": "Trenutna sesija" }, "mobile": { - "message": "Mobile", + "message": "Mobitel", "description": "Mobile app" }, "extension": { - "message": "Extension", + "message": "Proširenje", "description": "Browser extension/addon" }, "desktop": { @@ -3600,10 +3603,10 @@ "description": "Desktop app" }, "webVault": { - "message": "Web vault" + "message": "Web trezor" }, "webApp": { - "message": "Web app" + "message": "Web aplikacija" }, "cli": { "message": "CLI" @@ -3613,22 +3616,22 @@ "description": "Software Development Kit" }, "requestPending": { - "message": "Request pending" + "message": "Zahtjev u tijeku" }, "firstLogin": { - "message": "First login" + "message": "Prva prijava" }, "trusted": { - "message": "Trusted" + "message": "Pouzdan" }, "needsApproval": { - "message": "Needs approval" + "message": "Zahtijeva odobrenje" }, "devices": { - "message": "Devices" + "message": "Uređaji" }, "accessAttemptBy": { - "message": "Access attempt by $EMAIL$", + "message": "$EMAIL$ pokušava pristupiti", "placeholders": { "email": { "content": "$1", @@ -3637,28 +3640,28 @@ } }, "confirmAccess": { - "message": "Confirm access" + "message": "Potvrdi pristup" }, "denyAccess": { - "message": "Deny access" + "message": "Odbij pristup" }, "time": { - "message": "Time" + "message": "Vrijeme" }, "deviceType": { - "message": "Device Type" + "message": "Vrsta uređaja" }, "loginRequest": { - "message": "Login request" + "message": "Zahtjev za prijavu" }, "thisRequestIsNoLongerValid": { - "message": "This request is no longer valid." + "message": "Ovaj zahtjev više nije valjan." }, "areYouTryingToAccessYourAccount": { - "message": "Are you trying to access your account?" + "message": "Pokušavaš li pristupiti svom računu?" }, "logInConfirmedForEmailOnDevice": { - "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "message": "Prijava za $EMAIL$ potvrđena na uređaju $DEVICE$", "placeholders": { "email": { "content": "$1", @@ -3671,16 +3674,16 @@ } }, "youDeniedALogInAttemptFromAnotherDevice": { - "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + "message": "Odbijena je prijava na drugom uređaju. Ako si ovo stvarno ti, pokušaj se ponovno prijaviti uređajem." }, "loginRequestHasAlreadyExpired": { - "message": "Login request has already expired." + "message": "Zahtjev za prijavu je već istekao." }, "justNow": { - "message": "Just now" + "message": "Upravo" }, "requestedXMinutesAgo": { - "message": "Requested $MINUTES$ minutes ago", + "message": "Zatraženo prije $MINUTES$ minute/a", "placeholders": { "minutes": { "content": "$1", @@ -4598,7 +4601,7 @@ } }, "copyFieldCipherName": { - "message": "Copy $FIELD$, $CIPHERNAME$", + "message": "Kopiraj $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json index b77d613da51..cfe79ea4b20 100644 --- a/apps/browser/src/_locales/hu/messages.json +++ b/apps/browser/src/_locales/hu/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Keresés a széfben" }, + "resetSearch": { + "message": "Keresés visszaállítása" + }, "edit": { "message": "Szerkesztés" }, diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json index 07e094e10bd..4ce58ee7618 100644 --- a/apps/browser/src/_locales/id/messages.json +++ b/apps/browser/src/_locales/id/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Cari brankas" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Edit" }, diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index 167cc51c0b1..164d46bcec5 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Cerca nella cassaforte" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Modifica" }, diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index 49d22bd065f..977d04ca28a 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "保管庫を検索" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "編集" }, diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json index 1e75805638c..da70c255803 100644 --- a/apps/browser/src/_locales/ka/messages.json +++ b/apps/browser/src/_locales/ka/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Search vault" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "ჩასწორება" }, diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json index 9a6d9a4d316..f4c58318bc1 100644 --- a/apps/browser/src/_locales/km/messages.json +++ b/apps/browser/src/_locales/km/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Search vault" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Edit" }, diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json index c7a821de19b..31b285f6780 100644 --- a/apps/browser/src/_locales/kn/messages.json +++ b/apps/browser/src/_locales/kn/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "ವಾಲ್ಟ್ ಹುಡುಕಿ" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "ಎಡಿಟ್" }, diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index 730d3eeda61..89d59488aaf 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -3,7 +3,7 @@ "message": "Bitwarden" }, "appLogoLabel": { - "message": "Bitwarden logo" + "message": "Bitwarden 로고" }, "extName": { "message": "Bitwarden 비밀번호 관리자", @@ -465,10 +465,10 @@ "message": "암호 생성" }, "passwordGenerated": { - "message": "Password generated" + "message": "비밀번호 생성됨" }, "passphraseGenerated": { - "message": "Passphrase generated" + "message": "패스프레이즈 생성됨" }, "usernameGenerated": { "message": "Username generated" @@ -547,6 +547,9 @@ "searchVault": { "message": "보관함 검색" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "편집" }, @@ -1483,17 +1486,17 @@ "message": "Don't ask again on this device for 30 days" }, "selectAnotherMethod": { - "message": "Select another method", + "message": "다른 방법 시도", "description": "Select another two-step login method" }, "useYourRecoveryCode": { - "message": "Use your recovery code" + "message": "복구 코드 사용" }, "insertU2f": { "message": "보안 키를 컴퓨터의 USB 포트에 삽입하고 버튼이 있는 경우 누르세요." }, "openInNewTab": { - "message": "Open in new tab" + "message": "새 탭에서 열기" }, "webAuthnAuthenticate": { "message": "WebAuthn 인증" diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json index 29815c9de82..5a4f0d8c419 100644 --- a/apps/browser/src/_locales/lt/messages.json +++ b/apps/browser/src/_locales/lt/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Ieškoti saugykloje" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Keisti" }, diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index ba43b1e5f44..81447182f26 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Meklēt glabātavā" }, + "resetSearch": { + "message": "Atiestatīt meklēšanu" + }, "edit": { "message": "Labot" }, diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json index a39fe07b2c6..11709a4611b 100644 --- a/apps/browser/src/_locales/ml/messages.json +++ b/apps/browser/src/_locales/ml/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "വാൾട് തിരയുക" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "തിരുത്തുക" }, diff --git a/apps/browser/src/_locales/mr/messages.json b/apps/browser/src/_locales/mr/messages.json index c79b8b322a7..e7d06e4d5f9 100644 --- a/apps/browser/src/_locales/mr/messages.json +++ b/apps/browser/src/_locales/mr/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "तिजोरीत शोधा" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Edit" }, diff --git a/apps/browser/src/_locales/my/messages.json b/apps/browser/src/_locales/my/messages.json index 9a6d9a4d316..f4c58318bc1 100644 --- a/apps/browser/src/_locales/my/messages.json +++ b/apps/browser/src/_locales/my/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Search vault" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Edit" }, diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json index 01353cac5e0..7cbe8747d3b 100644 --- a/apps/browser/src/_locales/nb/messages.json +++ b/apps/browser/src/_locales/nb/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Søk i hvelvet" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Rediger" }, @@ -759,7 +762,7 @@ "message": "Hovedpassord" }, "masterPassImportant": { - "message": "Your master password cannot be recovered if you forget it!" + "message": "Hovedpassordet kan ikke gjenopprettes hvis du glemmer det!" }, "masterPassHintLabel": { "message": "Få et hint om hovedpassordet" @@ -814,7 +817,7 @@ "message": "En verifiseringskode er påkrevd." }, "webauthnCancelOrTimeout": { - "message": "The authentication was cancelled or took too long. Please try again." + "message": "Autentiseringen ble avbrutt eller tok for lang tid. Prøv igjen." }, "invalidVerificationCode": { "message": "Ugyldig bekreftelseskode" @@ -1097,7 +1100,7 @@ "description": "Shown to user after item is saved." }, "notificationLoginUpdatedConfirmation": { - "message": "updated in Bitwarden.", + "message": "oppdatert i Bitwarden.", "description": "Shown to user after item is updated." }, "selectItemAriaLabel": { @@ -1252,25 +1255,25 @@ "message": "Filformat" }, "fileEncryptedExportWarningDesc": { - "message": "This file export will be password protected and require the file password to decrypt." + "message": "Denne fileksporten vil bli passordbeskyttet og vil kreve filpassordet ved dekryptering." }, "filePassword": { "message": "Filpassord" }, "exportPasswordDescription": { - "message": "This password will be used to export and import this file" + "message": "Dette passordet brukes for eksport og import av denne filen" }, "accountRestrictedOptionDescription": { - "message": "Use your account encryption key, derived from your account's username and Master Password, to encrypt the export and restrict import to only the current Bitwarden account." + "message": "Bruk kontokrypteringsnøkkelen, avledet fra ditt kontobrukernavn og hovedpassord, for å kryptere eksporten og hindre import til andre kontoer enn den aktuelle Bitwarden-kontoen." }, "passwordProtectedOptionDescription": { - "message": "Set a file password to encrypt the export and import it to any Bitwarden account using the password for decryption." + "message": "Sett et filpassord for kryptering av eksporten. Bruk passordet for å dekryptere og importere til en hvilken som helst Bitwarden-konto." }, "exportTypeHeading": { "message": "Eksporttype" }, "accountRestricted": { - "message": "Account restricted" + "message": "Kontoen er begrenset" }, "filePasswordAndConfirmFilePasswordDoNotMatch": { "message": "«Filpassord» og «Bekreft filpassord» stemmer ikke overens." @@ -1621,7 +1624,7 @@ } }, "turnOffAutofill": { - "message": "Turn off autofill" + "message": "Skru av autoutfylling" }, "showInlineMenuLabel": { "message": "Vis autoutfyll-forslag i tekstbokser" @@ -1830,7 +1833,7 @@ "message": "Sikkerhetskode" }, "cardNumber": { - "message": "card number" + "message": "kortnummer" }, "ex": { "message": "f.eks." @@ -2534,7 +2537,7 @@ "message": "Endre" }, "changePassword": { - "message": "Change password", + "message": "Endre passord", "description": "Change password button for browser at risk notification on login." }, "changeButtonTitle": { @@ -2723,7 +2726,7 @@ "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": "Maks antall tilganger er nådd", "description": "This text will be displayed after a Send has been accessed the maximum amount of times." }, "hideTextByDefault": { @@ -3073,7 +3076,7 @@ "message": "A master password is no longer required for members of the following organization. Please confirm the domain below with your organization administrator." }, "organizationName": { - "message": "Organization name" + "message": "Organisasjonens navn" }, "keyConnectorDomain": { "message": "Key Connector domain" @@ -3103,7 +3106,7 @@ "message": "Eksporterer personlig hvelv" }, "exportingIndividualVaultDescription": { - "message": "Only the individual vault items associated with $EMAIL$ will be exported. Organization vault items will not be included. Only vault item information will be exported and will not include associated attachments.", + "message": "Kun de individuelle hvelvgjenstandene som er assosiert med $EMAIL$ vil bli eksportert. Organisasjonshvelv-gjenstander vil ikke bli inkludert. Kun hvelvgjenstandsinfo vil bli eksportert og vil ikke inkludere assosierte vedlegg.", "placeholders": { "email": { "content": "$1", @@ -3121,7 +3124,7 @@ } }, "exportingOrganizationVaultTitle": { - "message": "Exporting organization vault" + "message": "Eksporterer organisasjonshvelv" }, "exportingOrganizationVaultDesc": { "message": "Only the organization vault associated with $ORGANIZATION$ will be exported. Items in individual vaults or other organizations will not be included.", @@ -3480,13 +3483,13 @@ "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." }, "device": { - "message": "Device" + "message": "Enhet" }, "loginStatus": { - "message": "Login status" + "message": "Innloggingsstatus" }, "masterPasswordChanged": { - "message": "Master password saved" + "message": "Hovedpassordet er endret" }, "exposedMasterPassword": { "message": "Eksponert hovedpassord" @@ -3585,28 +3588,28 @@ "message": "Manage devices" }, "currentSession": { - "message": "Current session" + "message": "Gjeldende økt" }, "mobile": { - "message": "Mobile", + "message": "Mobil", "description": "Mobile app" }, "extension": { - "message": "Extension", + "message": "Utvidelse", "description": "Browser extension/addon" }, "desktop": { - "message": "Desktop", + "message": "Skrivebord", "description": "Desktop app" }, "webVault": { - "message": "Web vault" + "message": "Netthvelv" }, "webApp": { - "message": "Web app" + "message": "Nettapp" }, "cli": { - "message": "CLI" + "message": "Ledetekst" }, "sdk": { "message": "SDK", @@ -3619,13 +3622,13 @@ "message": "First login" }, "trusted": { - "message": "Trusted" + "message": "Betrodd" }, "needsApproval": { - "message": "Needs approval" + "message": "Trenger godkjenning" }, "devices": { - "message": "Devices" + "message": "Enheter" }, "accessAttemptBy": { "message": "Access attempt by $EMAIL$", @@ -3637,22 +3640,22 @@ } }, "confirmAccess": { - "message": "Confirm access" + "message": "Bekreft tilgang" }, "denyAccess": { - "message": "Deny access" + "message": "Nekt tilgang" }, "time": { - "message": "Time" + "message": "Tid" }, "deviceType": { - "message": "Device Type" + "message": "Enhetstype" }, "loginRequest": { - "message": "Login request" + "message": "Innloggingsforespørsel" }, "thisRequestIsNoLongerValid": { - "message": "This request is no longer valid." + "message": "Denne forespørselen er ikke lenger gyldig." }, "areYouTryingToAccessYourAccount": { "message": "Are you trying to access your account?" @@ -3674,13 +3677,13 @@ "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." }, "loginRequestHasAlreadyExpired": { - "message": "Login request has already expired." + "message": "Innloggingsforespørselen har allerede utløpt." }, "justNow": { - "message": "Just now" + "message": "Akkurat nå" }, "requestedXMinutesAgo": { - "message": "Requested $MINUTES$ minutes ago", + "message": "Forespurt for $MINUTES$ minutter siden", "placeholders": { "minutes": { "content": "$1", @@ -3716,7 +3719,7 @@ "message": "You need to log in on a trusted device or ask your administrator to assign you a password." }, "ssoIdentifierRequired": { - "message": "Organization SSO identifier is required." + "message": "Organisasjonsidentifikator er påkrevd." }, "creatingAccountOn": { "message": "Oppretter en konto på" @@ -3744,7 +3747,7 @@ "description": "European Union" }, "accessDenied": { - "message": "Access denied. You do not have permission to view this page." + "message": "Ingen tilgang. Du har ikke tillatelse til å se denne siden." }, "general": { "message": "Generelt" @@ -3753,10 +3756,10 @@ "message": "Vis" }, "accountSuccessfullyCreated": { - "message": "Account successfully created!" + "message": "Kontoen ble vellykket opprettet!" }, "adminApprovalRequested": { - "message": "Admin approval requested" + "message": "Admin-godkjenning forespurt" }, "adminApprovalRequestSentToAdmins": { "message": "Forespørselen din har blitt sendt til administratoren din." @@ -3836,7 +3839,7 @@ } }, "inputForbiddenCharacters": { - "message": "The following characters are not allowed: $CHARACTERS$", + "message": "Følgende tegn er ikke tillatt: $CHARACTERS$", "placeholders": { "characters": { "content": "$1", @@ -4043,7 +4046,7 @@ "message": "Importeringsfeil" }, "importErrorDesc": { - "message": "There was a problem with the data you tried to import. Please resolve the errors listed below in your source file and try again." + "message": "Det oppstod et problem med dataene du prøvde å importere. Vennligst løs feilene listet nedenfor i kildefilen og prøv på nytt." }, "resolveTheErrorsBelowAndTryAgain": { "message": "Fiks feilene nedenfor og prøv igjen." @@ -4103,7 +4106,7 @@ "message": "Total" }, "importWarning": { - "message": "You are importing data to $ORGANIZATION$. Your data may be shared with members of this organization. Do you want to proceed?", + "message": "Du importerer data til $ORGANIZATION$. Dataene kan deles med medlemmer av denne organisasjonen. Vil du fortsette?", "placeholders": { "organization": { "content": "$1", @@ -4130,7 +4133,7 @@ "message": "Ingenting ble importert." }, "importEncKeyError": { - "message": "Error decrypting the exported file. Your encryption key does not match the encryption key used export the data." + "message": "Feil under dekryptering av den eksporterte filen. Krypteringsnøkkelen samsvarte ikke med krypteringsnøkkelen som ble brukt eksport av data." }, "invalidFilePassword": { "message": "Ugyldig filpassord, vennligst bruk passordet du skrev inn da du opprettet eksportfilen." @@ -4148,7 +4151,7 @@ "message": "Velg en samling" }, "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", + "message": "Velg dette alternativet hvis du vil flytte den importerte filens innhold til en $DESTINATION$", "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", "placeholders": { "destination": { @@ -4210,7 +4213,7 @@ "message": "Passkoden vil ikke bli kopiert" }, "passkeyNotCopiedAlert": { - "message": "The passkey will not be copied to the cloned item. Do you want to continue cloning this item?" + "message": "Passnøkkelen kopieres ikke til det klonede elementet. Vil du fortsette kloningen av denne gjenstanden?" }, "passkeyFeatureIsNotImplementedForAccountsWithoutMasterPassword": { "message": "Verification required by the initiating site. This feature is not yet implemented for accounts without master password." @@ -4411,7 +4414,7 @@ "description": "Link to match detection docs on warning dialog for advance match strategy" }, "uriAdvancedOption": { - "message": "Advanced options", + "message": "Avanserte alternativer", "description": "Advanced option placeholder for uri option component" }, "confirmContinueToBrowserSettingsTitle": { @@ -4745,31 +4748,31 @@ } }, "downloadBitwarden": { - "message": "Download Bitwarden" + "message": "Last ned Bitwarden" }, "downloadBitwardenOnAllDevices": { "message": "Download Bitwarden on all devices" }, "getTheMobileApp": { - "message": "Get the mobile app" + "message": "Skaff deg mobilappen" }, "getTheMobileAppDesc": { "message": "Access your passwords on the go with the Bitwarden mobile app." }, "getTheDesktopApp": { - "message": "Get the desktop app" + "message": "Skaff deg skrivebordsappen" }, "getTheDesktopAppDesc": { "message": "Access your vault without a browser, then set up unlock with biometrics to expedite unlocking in both the desktop app and browser extension." }, "downloadFromBitwardenNow": { - "message": "Download from bitwarden.com now" + "message": "Last ned fra bitwarden.com nå" }, "getItOnGooglePlay": { - "message": "Get it on Google Play" + "message": "Skaff den på Google Play" }, "downloadOnTheAppStore": { - "message": "Download on the App Store" + "message": "Last ned fra App Store" }, "permanentlyDeleteAttachmentConfirmation": { "message": "Are you sure you want to permanently delete this attachment?" @@ -5494,7 +5497,7 @@ "message": "Save unlimited passwords across unlimited devices with Bitwarden mobile, browser, and desktop apps." }, "nudgeBadgeAria": { - "message": "1 notification" + "message": "1 varsel" }, "emptyVaultNudgeTitle": { "message": "Importer eksisterende passord" @@ -5521,12 +5524,12 @@ "message": "Spar tid med auto-utfylling" }, "newLoginNudgeBodyOne": { - "message": "Include a", + "message": "Inkluder en", "description": "This is in multiple parts to allow for bold text in the middle of the sentence.", "example": "Include a Website so this login appears as an autofill suggestion." }, "newLoginNudgeBodyBold": { - "message": "Website", + "message": "Nettsted", "description": "This is in multiple parts to allow for bold text in the middle of the sentence.", "example": "Include a Website so this login appears as an autofill suggestion." }, diff --git a/apps/browser/src/_locales/ne/messages.json b/apps/browser/src/_locales/ne/messages.json index 9a6d9a4d316..f4c58318bc1 100644 --- a/apps/browser/src/_locales/ne/messages.json +++ b/apps/browser/src/_locales/ne/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Search vault" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Edit" }, diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json index b5220861652..0c2bd31935f 100644 --- a/apps/browser/src/_locales/nl/messages.json +++ b/apps/browser/src/_locales/nl/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Kluis doorzoeken" }, + "resetSearch": { + "message": "Zoekopdracht resetten" + }, "edit": { "message": "Bewerken" }, diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json index 9a6d9a4d316..f4c58318bc1 100644 --- a/apps/browser/src/_locales/nn/messages.json +++ b/apps/browser/src/_locales/nn/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Search vault" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Edit" }, diff --git a/apps/browser/src/_locales/or/messages.json b/apps/browser/src/_locales/or/messages.json index 9a6d9a4d316..f4c58318bc1 100644 --- a/apps/browser/src/_locales/or/messages.json +++ b/apps/browser/src/_locales/or/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Search vault" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Edit" }, diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index aa8ab76d543..04112b08219 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -26,7 +26,7 @@ "message": "Nowy w Bitwarden?" }, "logInWithPasskey": { - "message": "Logowaniem kluczem dostępu" + "message": "Logowanie kluczem dostępu" }, "useSingleSignOn": { "message": "Użyj logowania jednokrotnego" @@ -96,7 +96,7 @@ "message": "Dołącz do organizacji" }, "joinOrganizationName": { - "message": "Dołącz do $ORGANIZATIONNAME$", + "message": "Dołącz do organizacji $ORGANIZATIONNAME$", "placeholders": { "organizationName": { "content": "$1", @@ -338,7 +338,7 @@ "message": "Przejść do bitwarden.com?" }, "bitwardenForBusiness": { - "message": "Bitwarden dla biznesu" + "message": "Bitwarden dla firm" }, "bitwardenAuthenticator": { "message": "Bitwarden Authenticator" @@ -347,16 +347,16 @@ "message": "Bitwarden Authenticator umożliwia przechowywanie kluczy uwierzytelniających i generowanie kodów TOTP dla weryfikacji dwustopniowej. Dowiedz się wiecej na bitwarden.com" }, "bitwardenSecretsManager": { - "message": "Menedżer sekretów Bitwarden" + "message": "Bitwarden Secrets Manager" }, "continueToSecretsManagerPageDesc": { - "message": "Bezpiecznie przechowuj, zarządzaj i udostępniaj sekrety programistów z Menedżerem sekretów Bitwarden. Dowiedz się więcej na stronie bitwarden.com." + "message": "Bezpiecznie przechowuj, zarządzaj i udostępniaj sekrety deweloperów za pomocą usługi Bitwarden Secrets Manager. Dowiedz się więcej na stronie bitwarden.com." }, "passwordlessDotDev": { "message": "Passwordless.dev" }, "continueToPasswordlessDotDevPageDesc": { - "message": "Twórz przyjemne i bezpieczne doświadczenia z logowaniem wolne od tradycyjnych haseł za pomocą Passwordless.dev. Dowiedz się więcej na stronie bitwarden.com." + "message": "Loguj się szybko i bezpiecznie bez tradycyjnych haseł za pomocą usługi Passwordless.dev. Dowiedz się więcej na stronie bitwarden.com." }, "freeBitwardenFamilies": { "message": "Darmowy plan rodzinny" @@ -541,12 +541,15 @@ "description": "Label for the avoid ambiguous characters checkbox." }, "generatorPolicyInEffect": { - "message": "Wymagania polityki przedsiębiorstwa zostały użyte do ustawienia opcji generatora.", + "message": "Zasady organizacji zostały zastosowane do opcji generatora.", "description": "Indicates that a policy limits the credential generator screen." }, "searchVault": { "message": "Szukaj w sejfie" }, + "resetSearch": { + "message": "Zresetuj wyszukiwanie" + }, "edit": { "message": "Edytuj" }, @@ -647,7 +650,7 @@ "message": "Blokowanie sejfu" }, "otherOptions": { - "message": "Pozostałe opcje" + "message": "Inne opcje" }, "rateExtension": { "message": "Oceń rozszerzenie" @@ -741,10 +744,10 @@ "message": "4 godziny" }, "onLocked": { - "message": "Po zablokowaniu komputera" + "message": "Po zablokowaniu urządzenia" }, "onRestart": { - "message": "Po restarcie przeglądarki" + "message": "Po uruchomieniu przeglądarki" }, "never": { "message": "Nigdy" @@ -802,7 +805,7 @@ "message": "Zalogowano!" }, "youSuccessfullyLoggedIn": { - "message": "Zalogowałeś się pomyślnie" + "message": "Zalogowano" }, "youMayCloseThisWindow": { "message": "Możesz zamknąć to okno" @@ -830,7 +833,7 @@ } }, "autofillError": { - "message": "Nie można zastosować autouzupełnienia na tej stronie. Skopiuj i wklej informacje ręcznie." + "message": "Nie można uzupełnić elementu na tej stronie internetowej. Skopiuj i wklej informacje ręcznie." }, "totpCaptureError": { "message": "Nie można zeskanować kodu QR z obecnej strony" @@ -860,7 +863,7 @@ "message": "Wylogowano" }, "loggedOutDesc": { - "message": "Zostałeś wylogowany z konta." + "message": "Wylogowano z konta." }, "loginExpired": { "message": "Twoja sesja wygasła." @@ -890,13 +893,13 @@ "message": "Wykonaj poniższe kroki, aby zakończyć logowanie za pomocą klucza bezpieczeństwa." }, "restartRegistration": { - "message": "Zacznij rejestrację od początku" + "message": "Rozpocznij rejestrację od początku" }, "expiredLink": { "message": "Link wygasł" }, "pleaseRestartRegistrationOrTryLoggingIn": { - "message": "Zrestartuj rejestrację lub spróbuj się zalogować." + "message": "Rozpocznij rejestrację od początku lub spróbuj się zalogować." }, "youMayAlreadyHaveAnAccount": { "message": "Możesz mieć już konto" @@ -926,7 +929,7 @@ "message": "Logowanie dwustopniowe zwiększa bezpieczeństwo konta, wymagając weryfikacji logowania za pomocą innego urządzenia, takiego jak klucz bezpieczeństwa, aplikacja uwierzytelniająca, wiadomość SMS, połączenie telefoniczne lub wiadomość e-mail. Logowanie dwustopniowe możesz skonfigurować w sejfie internetowym bitwarden.com. Czy chcesz przejść do strony?" }, "twoStepLoginConfirmationContent": { - "message": "Spraw, aby Twoje konto było bezpieczniejsze poprzez skonfigurowanie dwustopniowego logowania w aplikacji internetowej Bitwarden." + "message": "Zwiększ bezpieczeństwo konta, konfigurując logowanie dwustopniowe w aplikacji internetowej Bitwarden." }, "twoStepLoginConfirmationTitle": { "message": "Przejść do aplikacji internetowej?" @@ -1025,22 +1028,22 @@ "message": "Proponuj dodanie elementu, jeśli nie ma go w sejfie. Dotyczy wszystkich zalogowanych kont." }, "showCardsInVaultViewV2": { - "message": "Pokazuj zawsze karty w sugestiach autouzupełniania" + "message": "Zawsze pokazuj karty w sugestiach autouzupełniania" }, "showCardsCurrentTab": { "message": "Pokaż karty na stronie głównej" }, "showCardsCurrentTabDesc": { - "message": "Pokaż elementy karty na stronie głównej, aby ułatwić autouzupełnianie." + "message": "Wyświetla karty na głównej karcie sejfu." }, "showIdentitiesInVaultViewV2": { - "message": "Pokazuj zawsze tożsamości w sugestiach autouzupełniania" + "message": "Zawsze pokazuj tożsamości w sugestiach autouzupełniania" }, "showIdentitiesCurrentTab": { "message": "Pokaż tożsamości na stronie głównej" }, "showIdentitiesCurrentTabDesc": { - "message": "Pokaż elementy tożsamości na stronie głównej, aby ułatwić autouzupełnianie." + "message": "Wyświetla tożsamości na głównej karcie sejfu." }, "clickToAutofillOnVault": { "message": "Kliknij na elementy, aby je uzupełnić" @@ -1063,7 +1066,7 @@ "message": "Zapisz" }, "notificationViewAria": { - "message": "Wyświetl $ITEMNAME$, otworzy się w nowym oknie", + "message": "Pokaż $ITEMNAME$, otwiera się w nowym oknie", "placeholders": { "itemName": { "content": "$1" @@ -1129,7 +1132,7 @@ "description": "Prompt asking the user if they want to save their login details." }, "updateLogin": { - "message": "Zaktualizuj obecne dane logowania", + "message": "Zaktualizuj dane logowania", "description": "Prompt asking the user if they want to update an existing login entry." }, "loginSaveSuccess": { @@ -1174,7 +1177,7 @@ "description": "Detailed error message shown when saving login details fails." }, "changePasswordWarning": { - "message": "Po zmianie hasła musisz się zalogować przy użyciu nowego hasła. Aktywne sesje na innych urządzeniach zostaną wylogowane w ciągu jednej godziny." + "message": "Po zmianie hasła zaloguj się za pomocą nowego hasła. Aktywne sesje na innych urządzeniach zostaną wylogowane w ciągu jednej godziny." }, "accountRecoveryUpdateMasterPasswordSubtitle": { "message": "Zmień hasło główne, aby zakończyć odzyskiwanie konta." @@ -1201,7 +1204,7 @@ "message": "Zaktualizuj" }, "notificationUnlockDesc": { - "message": "Odblokuj swój sejf Bitwarden, aby ukończyć żądanie autouzupełniania." + "message": "Odblokuj sejf Bitwarden, aby uzupełnić dane." }, "notificationUnlock": { "message": "Odblokuj" @@ -1270,7 +1273,7 @@ "message": "Rodzaj eksportu" }, "accountRestricted": { - "message": "Konto ograniczone" + "message": "Konto zostało ograniczone" }, "filePasswordAndConfirmFilePasswordDoNotMatch": { "message": "Hasła pliku nie pasują do siebie." @@ -1287,7 +1290,7 @@ "message": "Potwierdź eksportowanie sejfu" }, "exportWarningDesc": { - "message": "Plik zawiera dane sejfu w niezaszyfrowanym formacie. Nie powinieneś go przechowywać, ani przesyłać poprzez niezabezpieczone kanały (takie jak poczta e-mail). Skasuj go natychmiast po użyciu." + "message": "Plik zawiera dane sejfu w niezaszyfrowanym formacie. Nie należy go przechowywać ani przesyłać poprzez niezabezpieczone kanały (takie jak poczta e-mail). Usuń go natychmiast po użyciu." }, "encExportKeyWarningDesc": { "message": "Dane eksportu zostaną zaszyfrowane za pomocą klucza szyfrowania konta. Jeśli kiedykolwiek zmienisz ten klucz, wyeksportuj dane ponownie, ponieważ nie będziesz w stanie odszyfrować tego pliku." @@ -1302,7 +1305,7 @@ "message": "Udostępnione" }, "bitwardenForBusinessPageDesc": { - "message": "Bitwarden dla biznesu pozwala na udostępnianie zawartości sejfu innym użytkownikom za pośrednictwem organizacji. Dowiedz się więcej na stronie bitwarden.com." + "message": "Bitwarden dla firm pozwala na udostępnianie zawartości sejfu innym użytkownikom za pośrednictwem organizacji. Dowiedz się więcej na stronie bitwarden.com." }, "moveToOrganization": { "message": "Przenieś do organizacji" @@ -1456,7 +1459,7 @@ "message": "Automatycznie kopiuje kod TOTP do schowka podczas autouzupełniania." }, "enableAutoBiometricsPrompt": { - "message": "Poproś o dane biometryczne przy uruchomieniu" + "message": "Wymagaj odblokowania biometrią po uruchomieniu przeglądarki" }, "premiumRequired": { "message": "Konto premium jest wymagane" @@ -1468,7 +1471,7 @@ "message": "Limit czasu uwierzytelniania" }, "authenticationSessionTimedOut": { - "message": "Upłynął limit czasu uwierzytelniania. Uruchom ponownie proces logowania." + "message": "Upłynął limit czasu uwierzytelniania. Zaloguj się ponownie." }, "verificationCodeEmailSent": { "message": "Wiadomość weryfikacyjna została wysłana na adres $EMAIL$.", @@ -1508,10 +1511,10 @@ "message": "Logowanie jest niedostępne" }, "noTwoStepProviders": { - "message": "Konto posiada włączoną opcję logowania dwustopniowego, jednak ta przeglądarka nie wspiera żadnego ze skonfigurowanych mechanizmów autoryzacji dwustopniowej." + "message": "Konto jest zabezpieczone logowaniem dwustopniowym, ale żadna ze skonfigurowanych metod nie jest obsługiwana w tej przeglądarce." }, "noTwoStepProviders2": { - "message": "Proszę użyć obsługiwanej przeglądarki (takiej jak Chrome) i/lub dodać dodatkowych dostawców, którzy są lepiej wspierani przez przeglądarki internetowe (np. aplikacja uwierzytelniająca)." + "message": "Użyj obsługiwanej przeglądarki (np. Chrome) lub dodaj dodatkowe opcje logowania dwustopniowego, które są obsługiwane na różnych przeglądarkach (takie jak aplikacja uwierzytelniająca)." }, "twoStepOptions": { "message": "Opcje logowania dwustopniowego" @@ -1609,7 +1612,7 @@ "message": "Łatwe wyszukiwanie sugestii autouzupełniania" }, "autofillSpotlightDesc": { - "message": "Wyłącz ustawienia autouzupełniania swojej przeglądarki, aby nie kolidowały z Bitwarden." + "message": "Wyłącz autouzupełnianie przeglądarki, aby uniknąć konfliktów z Bitwarden." }, "turnOffBrowserAutofill": { "message": "Wyłącz autouzupełnianie $BROWSER$", @@ -1645,15 +1648,15 @@ "message": "Edytuj ustawienia przeglądarki." }, "autofillOverlayVisibilityOff": { - "message": "Wył.", + "message": "Wyłączone", "description": "Overlay setting select option for disabling autofill overlay" }, "autofillOverlayVisibilityOnFieldFocus": { - "message": "Gdy pole jest zaznaczone", + "message": "Po kliknięciu pola", "description": "Overlay appearance select option for showing the field on focus of the input element" }, "autofillOverlayVisibilityOnButtonClick": { - "message": "Gdy wybrano ikonę autouzupełniania", + "message": "Po kliknięciu ikony autouzupełniania", "description": "Overlay appearance select option for showing the field on click of the overlay icon" }, "enableAutoFillOnPageLoadSectionTitle": { @@ -1971,7 +1974,7 @@ "message": "Wyczyść historię generatora" }, "cleargGeneratorHistoryDescription": { - "message": "Jeśli zatwierdzisz, wszystkie wygenerowane hasła zostaną usunięte z historii generatora. Czy chcesz kontynuować mimo to?" + "message": "Wszystkie wpisy zostaną trwale usunięte z historii generatora. Czy na pewno chcesz kontynuować?" }, "back": { "message": "Wstecz" @@ -1980,7 +1983,7 @@ "message": "Kolekcje" }, "nCollections": { - "message": "Kolekcje ($COUNT$)", + "message": "W $COUNT$ kolekcjach", "placeholders": { "count": { "content": "$1", @@ -2066,7 +2069,7 @@ "description": "Default URI match detection for autofill." }, "toggleOptions": { - "message": "Zmień opcje" + "message": "Przełącz opcje" }, "toggleCurrentUris": { "message": "Przełącz obecny URI", @@ -2096,13 +2099,13 @@ "message": "Brak zawartości do pokazania" }, "nothingGeneratedRecently": { - "message": "Nic nie zostało wygenerowane przez ciebie w ostatnim czasie" + "message": "Nic nie zostało wygenerowane w ostatnim czasie" }, "remove": { "message": "Usuń" }, "default": { - "message": "Domyślne" + "message": "Domyślna" }, "dateUpdated": { "message": "Zaktualizowano", @@ -2147,7 +2150,7 @@ "message": "Hasło główne jest słabe" }, "weakMasterPasswordDesc": { - "message": "Wybrane przez Ciebie hasło główne jest słabe. Powinieneś użyć silniejszego hasła (lub frazy), aby właściwie chronić swoje konto Bitwarden. Czy na pewno chcesz użyć tego hasła głównego?" + "message": "Użyj silniejszego hasła, aby odpowiednio chronić konto Bitwarden. Czy na pewno chcesz użyć tego hasła głównego?" }, "pin": { "message": "Kod PIN", @@ -2163,10 +2166,10 @@ "message": "Ustaw kod PIN" }, "setYourPinCode": { - "message": "Ustaw kod PIN do odblokowywania aplikacji Bitwarden. Ustawienia odblokowywania kodem PIN zostaną zresetowane po wylogowaniu." + "message": "Ustaw kod PIN do odblokowania aplikacji Bitwarden. Ustawienia kodu PIN zostaną zresetowane po wylogowaniu." }, "setPinCode": { - "message": "Możesz użyć tego kodu PIN, aby odblokować Bitwarden. Twój kod PIN zostanie zresetowany, jeśli kiedykolwiek wylogujesz się z aplikacji." + "message": "Możesz użyć tego kodu PIN do odblokowania aplikacji Bitwarden. Kod PIN zostanie zresetowany po wylogowaniu." }, "pinRequired": { "message": "Kod PIN jest wymagany." @@ -2187,13 +2190,13 @@ "message": "Oczekiwanie na potwierdzenie z aplikacji desktopowej" }, "awaitDesktopDesc": { - "message": "Włącz dane biometryczne w aplikacji desktopowej Bitwarden, aby włączyć tę samą funkcję w przeglądarce." + "message": "Włącz najpierw biometrię w aplikacji desktopowej Bitwarden, aby skonfigurować dane biometryczne w przeglądarce." }, "lockWithMasterPassOnRestart": { "message": "Zablokuj hasłem głównym po uruchomieniu przeglądarki" }, "lockWithMasterPassOnRestart1": { - "message": "Wymagaj hasła głównego przy ponownym uruchomieniu przeglądarki" + "message": "Wymagaj hasła głównego po uruchomieniu przeglądarki" }, "selectOneCollection": { "message": "Musisz wybrać co najmniej jedną kolekcję." @@ -2223,14 +2226,14 @@ "message": "Użyj tej nazwy użytkownika" }, "securePasswordGenerated": { - "message": "Wygenerowane bezpieczne hasło! Nie zapomnij również zaktualizować hasła na stronie." + "message": "Bezpieczne hasło zostało wygenerowane! Nie zapomnij zaktualizować hasła na stronie internetowej." }, "useGeneratorHelpTextPartOne": { "message": "Użyj generatora", "description": "This will be used as part of a larger sentence, broken up to include the generator icon. The full sentence will read 'Use the generator [GENERATOR_ICON] to create a strong unique password'" }, "useGeneratorHelpTextPartTwo": { - "message": ", aby utworzyć mocne unikalne hasło", + "message": ", aby utworzyć silne i unikalne hasło", "description": "This will be used as part of a larger sentence, broken up to include the generator icon. The full sentence will read 'Use the generator [GENERATOR_ICON] to create a strong unique password'" }, "vaultCustomization": { @@ -2296,10 +2299,10 @@ "message": "Czy chcesz uzupełnić dane logowania?" }, "autofillIframeWarning": { - "message": "Formularz jest hostowany przez inną domenę niż zapisany adres URI dla tego loginu. Wybierz OK, aby i tak automatycznie wypełnić lub anuluj, aby zatrzymać." + "message": "Formularz jest hostowany przez inną domenę niż URI zapisanych danych logowania. Kliknij OK, aby uzupełnić dane logowania lub Anuluj, aby zatrzymać." }, "autofillIframeWarningTip": { - "message": "Aby zapobiec temu ostrzeżeniu w przyszłości, zapisz ten URI, $HOSTNAME$, dla tej witryny.", + "message": "Aby uniknąć ostrzeżenia w przyszłości, zapisz URI $HOSTNAME$ w danych logowania.", "placeholders": { "hostname": { "content": "$1", @@ -2368,7 +2371,7 @@ "message": "Anuluj subskrypcję" }, "atAnyTime": { - "message": "w każdej chwili." + "message": "w dowolnym momencie." }, "byContinuingYouAgreeToThe": { "message": "Kontynuując, akceptujesz" @@ -2407,7 +2410,7 @@ "message": "Weryfikacja synchronizacji z aplikacją desktopową" }, "desktopIntegrationVerificationText": { - "message": "Zweryfikuj aplikację desktopową z odciskiem klucza: " + "message": "Zweryfikuj aplikację desktopową z identyfikatorem: " }, "desktopIntegrationDisabledTitle": { "message": "Połączenie z przeglądarką jest wyłączone" @@ -2419,7 +2422,7 @@ "message": "Uruchom aplikację desktopową Bitwarden" }, "startDesktopDesc": { - "message": "Aplikacja desktopowa Bitwarden, przed odblokowaniem danymi biometrycznymi, musi zostać ponownie uruchomiona." + "message": "Aplikacja desktopowa Bitwarden musi zostać uruchomiona przed odblokowaniem za pomocą biometrii." }, "errorEnableBiometricTitle": { "message": "Nie można włączyć biometrii" @@ -2434,7 +2437,7 @@ "message": "Komunikacja z aplikacją desktopową została przerwana" }, "nativeMessagingWrongUserDesc": { - "message": "W aplikacji desktopowej jesteś zalogowany na inne konto. Upewnij się, że w obu aplikacjach jesteś zalogowany na to same konto." + "message": "Aplikacja desktopowa jest zalogowana na inne konto. Upewnij się, że obie aplikacje są zalogowane na to samo konto." }, "nativeMessagingWrongUserTitle": { "message": "Konto jest niezgodne" @@ -2443,13 +2446,13 @@ "message": "Klucz biometrii jest nieprawidłowy" }, "nativeMessagingWrongUserKeyDesc": { - "message": "Odblokowanie biometryczne się nie powiodło. Sekretny klucz biometryczny nie odblokował sejfu. Spróbuj skonfigurować biometrię ponownie." + "message": "Odblokowanie biometrią nie powiodło się. Klucz biometrii nie odblokował sejfu. Spróbuj ponownie skonfigurować biometrię." }, "biometricsNotEnabledTitle": { "message": "Biometria jest wyłączona" }, "biometricsNotEnabledDesc": { - "message": "Aby włączyć dane biometryczne w przeglądarce, musisz włączyć tę samą funkcję w ustawianiach aplikacji desktopowej." + "message": "Aby skonfigurować dane biometryczne w przeglądarce, włącz najpierw biometrię w aplikacji desktopowej." }, "biometricsNotSupportedTitle": { "message": "Biometria nie jest obsługiwana" @@ -2485,7 +2488,7 @@ "message": "Wystąpił błąd żądania uprawnienia" }, "nativeMessaginPermissionSidebarDesc": { - "message": "Ta operacja nie może zostać wykonana na pasku bocznym. Spróbuj ponownie w nowym oknie." + "message": "Akcji nie można wykonać na pasku bocznym. Otwórz rozszerzenie w oknie." }, "personalOwnershipSubmitError": { "message": "Ze względu na zasadę organizacji, nie możesz zapisywać elementów w osobistym sejfie. Zmień właściciela elementu na organizację i wybierz jedną z dostępnych kolekcji." @@ -2494,7 +2497,7 @@ "message": "Zasada organizacji ma wpływ na opcję własności elementów." }, "personalOwnershipPolicyInEffectImports": { - "message": "Polityka organizacji zablokowała importowanie elementów do Twojego sejfu." + "message": "Zasada organizacji zablokowała importowanie elementów do osobistego sejfu." }, "restrictCardTypeImport": { "message": "Nie można zaimportować karty" @@ -2619,7 +2622,7 @@ "message": "Zmień zagrożone hasła szybciej" }, "changeAtRiskPasswordsFasterDesc": { - "message": "Zaktualizuj swoje ustawienia, aby szybko autouzupełniać hasła i generować nowe" + "message": "Zaktualizuj ustawienia, aby szybko uzupełniać hasła i generować nowe." }, "reviewAtRiskLogins": { "message": "Sprawdź zagrożone dane logowania" @@ -2645,7 +2648,7 @@ "message": "Zaktualizuj w Bitwarden" }, "updateInBitwardenSlideDesc": { - "message": "Bitwarden poprosi Cię o aktualizację hasła w menedżerze haseł.", + "message": "Bitwarden zaproponuje aktualizację hasła w menedżerze haseł.", "description": "Description of the update in Bitwarden slide on the at-risk password page carousel" }, "updateInBitwardenSlideImgAltPeriod": { @@ -2887,7 +2890,7 @@ "message": "Aby wybrać plik, otwórz rozszerzenie w oknie." }, "popOut": { - "message": "Odepnij" + "message": "Otwórz w nowym oknie" }, "sendFileCalloutHeader": { "message": "Zanim zaczniesz" @@ -2960,7 +2963,7 @@ "description": "Used as a message within the notification bar when no folders are found" }, "orgPermissionsUpdatedMustSetPassword": { - "message": "Uprawnienia w Twojej organizacji zostały zaktualizowane, musisz teraz ustawić hasło główne.", + "message": "Uprawnienia organizacji zostały zaktualizowane. Ustaw hasło główne.", "description": "Used as a card title description on the set password page to explain why the user is there" }, "orgRequiresYouToSetPassword": { @@ -3146,7 +3149,7 @@ "description": "This is part of a larger sentence. The full sentence will read 'Contact customer success to avoid additional data loss.'" }, "contactCSToAvoidDataLossPart2": { - "message": "aby uniknąć dalszej utraty danych.", + "message": "aby uniknąć dodatkowej utraty danych.", "description": "This is part of a larger sentence. The full sentence will read 'Contact customer success to avoid additional data loss.'" }, "generateUsername": { @@ -3243,7 +3246,7 @@ } }, "forwarderGeneratedBy": { - "message": "Wygenerowane przez Bitwarden.", + "message": "Wygenerowano przez Bitwarden.", "description": "Displayed with the address on the forwarding service's configuration screen." }, "forwarderGeneratedByWithWebsite": { @@ -3365,7 +3368,7 @@ "message": "Klucz API" }, "ssoKeyConnectorError": { - "message": "Błąd serwera Key Connector: upewnij się, że serwer Key Connector jest dostępny i działa poprawnie." + "message": "Wystąpił błąd serwera Key Connector. Upewnij się, że serwer jest dostępny i działa poprawnie." }, "premiumSubcriptionRequired": { "message": "Wymagana jest subskrypcja premium" @@ -3395,7 +3398,7 @@ "message": "Inny dostawca" }, "thirdPartyServerMessage": { - "message": "Połączono z implementacją serwera innego dostawcy, $SERVERNAME$. Zweryfikuj błędy za pomocą oficjalnego serwera lub zgłoś je serwerowi innego dostawcy.", + "message": "Połączono z implementacją serwera innego dostawcy $SERVERNAME$. Zweryfikuj błędy za pomocą oficjalnego serwera lub zgłoś je serwerowi.", "placeholders": { "servername": { "content": "$1", @@ -3428,7 +3431,7 @@ "message": "Unikalny identyfikator konta" }, "fingerprintMatchInfo": { - "message": "Upewnij się, że sejf jest odblokowany, a unikalny identyfikator konta pasuje do drugiego urządzenia." + "message": "Upewnij się, że sejf jest odblokowany, a identyfikator pasuje do drugiego urządzenia." }, "resendNotification": { "message": "Wyślij ponownie powiadomienie" @@ -3446,7 +3449,7 @@ "message": "aplikacji internetowej" }, "notificationSentDevicePart2": { - "message": "Upewnij się, że fraza odcisku palca zgadza się z tą poniżej, zanim zatwierdzisz." + "message": "Upewnij się, że identyfikator jest zgodny." }, "aNotificationWasSentToYourDevice": { "message": "Powiadomienie zostało wysłane na urządzenie" @@ -3483,7 +3486,7 @@ "message": "Urządzenie" }, "loginStatus": { - "message": "Status zalogowania" + "message": "Status logowania" }, "masterPasswordChanged": { "message": "Hasło główne zostało zapisane" @@ -3492,7 +3495,7 @@ "message": "Hasło główne zostało ujawnione" }, "exposedMasterPasswordDesc": { - "message": "Hasło ujawnione w wyniku naruszenia ochrony danych. Użyj unikalnego hasła, aby chronić swoje konto. Czy na pewno chcesz użyć ujawnionego hasła?" + "message": "Hasło zostało ujawnione w wycieku danych. Użyj unikalnego hasła, aby chronić konto. Czy na pewno chcesz użyć ujawnionego hasła?" }, "weakAndExposedMasterPassword": { "message": "Hasło główne jest słabe i ujawnione" @@ -3501,7 +3504,7 @@ "message": "Hasło jest słabe i zostało ujawnione w wycieku danych. Użyj mocnego i unikalnego hasła, aby chronić konto. Czy na pewno chcesz użyć tego hasła?" }, "checkForBreaches": { - "message": "Sprawdź znane naruszenia ochrony danych tego hasła" + "message": "Sprawdź hasło w znanych wyciekach danych" }, "important": { "message": "Ważne:" @@ -3534,7 +3537,7 @@ } }, "autofillSelectInfoWithoutCommand": { - "message": "Wybierz element z tego ekranu lub zobacz inne opcje w ustawieniach." + "message": "Wybierz element lub zobacz inne opcje w ustawieniach." }, "gotIt": { "message": "Ok" @@ -3579,7 +3582,7 @@ "message": "Otwiera w nowym oknie" }, "rememberThisDeviceToMakeFutureLoginsSeamless": { - "message": "Zapamiętaj to urządzenie, aby przyszłe logowania były bezproblemowe" + "message": "Zapamiętaj urządzenie, aby przyszłe logowania były bezproblemowe" }, "manageDevices": { "message": "Zarządzaj urządzeniami" @@ -3622,7 +3625,7 @@ "message": "Zaufane" }, "needsApproval": { - "message": "Wymagane potwierdzenie" + "message": "Potwierdzenie jest wymagane" }, "devices": { "message": "Urządzenia" @@ -3680,7 +3683,7 @@ "message": "Teraz" }, "requestedXMinutesAgo": { - "message": "Poproszono $MINUTES$ min temu", + "message": "$MINUTES$ min temu", "placeholders": { "minutes": { "content": "$1", @@ -3689,10 +3692,10 @@ } }, "deviceApprovalRequired": { - "message": "Wymagane zatwierdzenie urządzenia. Wybierz opcję zatwierdzenia poniżej:" + "message": "Potwierdzenie urządzenia jest wymagane. Wybierz opcję:" }, "deviceApprovalRequiredV2": { - "message": "Wymagane zatwierdzenie urządzenia" + "message": "Potwierdzenie urządzenia jest wymagane" }, "selectAnApprovalOptionBelow": { "message": "Wybierz opcję potwierdzenia" @@ -3725,7 +3728,7 @@ "message": "Sprawdź swoją pocztę e-mail" }, "followTheLinkInTheEmailSentTo": { - "message": "Kliknij łącze w wiadomości e-mail wysłanej do" + "message": "Kliknij link w wiadomości wysłanej na adres" }, "andContinueCreatingYourAccount": { "message": "i kontynuuj tworzenie konta." @@ -3792,7 +3795,7 @@ "message": "Dla bezpieczeństwa Twojego konta potwierdź tylko, jeśli przyznano temu użytkownikowi dostęp awaryjny i jego odcisk palca pasuje do tego, co widnieje na jego koncie" }, "orgTrustWarning": { - "message": "Dla zapewnienia bezpieczeństwa konta kontynuuj tylko wtedy, gdy jesteś członkiem tej organizacji, włączono odzyskiwanie konta, a odcisk palca wyświetlany poniżej pasuje do odcisku palca organizacji." + "message": "Kontynuuj tylko wtedy, gdy jesteś członkiem organizacji, masz włączone odzyskiwanie konta, a unikalny identyfikator pasuje do organizacji." }, "orgTrustWarning1": { "message": "Zasada organizacji pozwala administratorom organizacji na zmianę Twojego hasła. Kontynuuj tylko wtedy, gdy rozpoznajesz organizację, a unikalny identyfikator pasuje do organizacji." @@ -3805,7 +3808,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendsBodyNoItems": { - "message": "Udostępniaj pliki i teksty każdemu, na dowolnej platformie. Informacje będę szyfrowane end-to-end, zapewniając poufność.", + "message": "Udostępniaj pliki i teksty każdemu na dowolnej platformie. Informacje będę szyfrowane end-to-end, zapewniając poufność.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "inputRequired": { @@ -3943,7 +3946,7 @@ "message": "Przełącz nawigację boczną" }, "skipToContent": { - "message": "Przejdź do treści" + "message": "Przejdź do zawartości" }, "bitwardenOverlayButton": { "message": "Przycisk menu autouzupełniania Bitwarden", @@ -3958,7 +3961,7 @@ "description": "Page title in overlay" }, "unlockYourAccountToViewMatchingLogins": { - "message": "Odblokuj swoje konto, aby wyświetlić pasujące elementy", + "message": "Odblokuj konto, aby zobaczy pasujące dane logowania", "description": "Text to display in overlay when the account is locked." }, "unlockYourAccountToViewAutofillSuggestions": { @@ -3970,7 +3973,7 @@ "description": "Button text to display in overlay when the account is locked." }, "unlockAccountAria": { - "message": "Odblokuj swoje konto, otwiera się w nowym oknie", + "message": "Odblokuj konto, otwiera się w nowym oknie", "description": "Screen reader text (aria-label) for unlock account button in overlay" }, "totpCodeAria": { @@ -3978,7 +3981,7 @@ "description": "Aria label for the totp code displayed in the inline menu for autofill" }, "totpSecondsSpanAria": { - "message": "Pozostały czas do wygaśnięcia bieżącego TOTP", + "message": "Pozostały czas do wygaśnięcia kodu TOTP", "description": "Aria label for the totp seconds displayed in the inline menu for autofill" }, "fillCredentialsFor": { @@ -4006,7 +4009,7 @@ "description": "Button text to display within inline menu when there are no matching items on a login field" }, "addNewLoginItemAria": { - "message": "Dodaj nowe dane logowania do sejfu, otwiera się w nowym oknie", + "message": "Dodaj nowe dane logowania, otwiera się w nowym oknie", "description": "Screen reader text (aria-label) for new login button within inline menu" }, "newCard": { @@ -4014,7 +4017,7 @@ "description": "Button text to display within inline menu when there are no matching items on a credit card field" }, "addNewCardItemAria": { - "message": "Dodaj nową kartę do sejfu, otwiera się w nowym oknie", + "message": "Dodaj nową kartę, otwiera się w nowym oknie", "description": "Screen reader text (aria-label) for new card button within inline menu" }, "newIdentity": { @@ -4022,7 +4025,7 @@ "description": "Button text to display within inline menu when there are no matching items on an identity field" }, "addNewIdentityItemAria": { - "message": "Dodaj nową tożsamość do sejfu, otwiera się w nowym oknie", + "message": "Dodaj nową tożsamość, otwiera się w nowym oknie", "description": "Screen reader text (aria-label) for new identity button within inline menu" }, "bitwardenOverlayMenuAvailable": { @@ -4118,13 +4121,13 @@ "message": "Konto wymaga logowania dwustopniowego Duo." }, "popoutExtension": { - "message": "Otwórz rozszerzenie w nowym oknie" + "message": "Otwórz rozszerzenie w oknie" }, "launchDuo": { "message": "Uruchom Duo" }, "importFormatError": { - "message": "Dane nie są poprawnie sformatowane. Sprawdź importowany plik i spróbuj ponownie." + "message": "Dane nie są prawidłowo sformatowane. Sprawdź plik i spróbuj ponownie." }, "importNothingError": { "message": "Nic nie zostało zaimportowane." @@ -4133,7 +4136,7 @@ "message": "Wystąpił błąd podczas odszyfrowywania pliku. Klucz szyfrowania nie pasuje do klucza użytego podczas eksportowania danych." }, "invalidFilePassword": { - "message": "Hasło do pliku jest nieprawidłowe. Użyj hasła które podano przy tworzeniu pliku eksportu." + "message": "Hasło pliku jest nieprawidłowe. Użyj prawidłowego hasła." }, "destination": { "message": "Miejsce docelowe" @@ -4148,7 +4151,7 @@ "message": "Wybierz kolekcję" }, "importTargetHint": { - "message": "Wybierz tę opcję, jeśli chcesz, aby zawartość zaimportowanego pliku została przeniesiona do $DESTINATION$", + "message": "Wybierz tę opcję, jeśli chcesz przenieść dane do $DESTINATION$", "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", "placeholders": { "destination": { @@ -4189,7 +4192,7 @@ "message": "Potwierdź importowanie sejfu" }, "confirmVaultImportDesc": { - "message": "Plik jest chroniony hasłem. Wprowadź hasło pliku, aby zaimportować dane." + "message": "Plik jest chroniony hasłem. Wpisz hasło pliku, aby zaimportować dane." }, "confirmFilePassword": { "message": "Potwierdź hasło pliku" @@ -4246,7 +4249,7 @@ "message": "Wybierz dane logowania, do których przypisać klucz dostępu" }, "chooseCipherForPasskeyAuth": { - "message": "Wybierz klucz dostępu, żeby się zalogować" + "message": "Wybierz klucz dostępu" }, "passkeyItem": { "message": "Element klucza dostępu" @@ -4261,16 +4264,16 @@ "message": "Funkcja nie jest jeszcze obsługiwana" }, "yourPasskeyIsLocked": { - "message": "Wymagane uwierzytelnienie, aby używać klucza dostępu. Sprawdź swoją tożsamość, aby kontynuować." + "message": "Aby użyć klucza dostępu, wymagane jest uwierzytelnienie. Zweryfikuj swoją tożsamość." }, "multifactorAuthenticationCancelled": { - "message": "Uwierzytelnianie wieloskładnikowe zostało anulowane" + "message": "Logowanie dwustopniowe zostało anulowane" }, "noLastPassDataFound": { "message": "Nie znaleziono danych LastPass" }, "incorrectUsernameOrPassword": { - "message": "Nieprawidłowa nazwa użytkownika lub hasło" + "message": "Nazwa użytkownika lub hasło są nieprawidłowe" }, "incorrectPassword": { "message": "Hasło jest nieprawidłowe" @@ -4282,7 +4285,7 @@ "message": "Kod PIN jest nieprawidłowy" }, "multifactorAuthenticationFailed": { - "message": "Uwierzytelnianie wieloskładnikowe nie powiodło się" + "message": "Logowanie dwustopniowe nie powiodło się" }, "includeSharedFolders": { "message": "Dołącz udostępnione foldery" @@ -4294,10 +4297,10 @@ "message": "Importowanie konta..." }, "lastPassMFARequired": { - "message": "Wymagane jest uwierzytelnianie wieloskładnikowe LastPass" + "message": "Logowanie dwustopniowe LastPass jest wymagane" }, "lastPassMFADesc": { - "message": "Wprowadź jednorazowy kod z aplikacji uwierzytelniającej" + "message": "Wpisz jednorazowy kod z aplikacji uwierzytelniającej" }, "lastPassOOBDesc": { "message": "Zatwierdź żądanie logowania w aplikacji uwierzytelniającej lub wprowadź jednorazowe hasło." @@ -4309,7 +4312,7 @@ "message": "Hasło główne LastPass" }, "lastPassAuthRequired": { - "message": "Wymagane uwierzytelnianie LastPass" + "message": "Uwierzytelnianie LastPass jest wymagane" }, "awaitingSSO": { "message": "Oczekiwanie na logowanie jednokrotne" @@ -4328,7 +4331,7 @@ "message": "Importuj z CSV" }, "lastPassTryAgainCheckEmail": { - "message": "Spróbuj ponownie lub poszukaj wiadomości e-mail od LastPass, aby zweryfikować, że to Ty." + "message": "Spróbuj ponownie lub poszukaj wiadomości od LastPass, aby zweryfikować logowanie." }, "collection": { "message": "Kolekcja" @@ -4373,13 +4376,13 @@ "message": "hostowany w" }, "useDeviceOrHardwareKey": { - "message": "Użyj swojego urządzenia lub klucza sprzętowego" + "message": "Użyj urządzenia lub klucza sprzętowego" }, "justOnce": { "message": "Tylko raz" }, "alwaysForThisSite": { - "message": "Zawsze dla tej witryny" + "message": "Zawsze dla tej strony" }, "domainAddedToExcludedDomains": { "message": "Domena $DOMAIN$ została dodana do wykluczonych domen.", @@ -4411,7 +4414,7 @@ "description": "Link to match detection docs on warning dialog for advance match strategy" }, "uriAdvancedOption": { - "message": "Ustawienia zaawansowane", + "message": "Opcje zaawansowane", "description": "Advanced option placeholder for uri option component" }, "confirmContinueToBrowserSettingsTitle": { @@ -4443,7 +4446,7 @@ "description": "Dialog title facilitating the ability to override a chrome browser's default autofill behavior" }, "overrideDefaultBrowserAutofillDescription": { - "message": "Ignorowanie tej opcji może spowodować konflikty pomiędzy menu autouzupełniania Bitwarden a przeglądarką.", + "message": "Zignorowanie tej opcji może spowodować konflikty pomiędzy autouzupełnianiem Bitwarden a przeglądarką.", "description": "Dialog message facilitating the ability to override a chrome browser's default autofill behavior" }, "overrideDefaultBrowserAutoFillSettings": { @@ -4748,19 +4751,19 @@ "message": "Pobierz Bitwarden" }, "downloadBitwardenOnAllDevices": { - "message": "Pobierz Bitwarden na wszystkich urządzeniach" + "message": "Bitwarden na inne urządzenia" }, "getTheMobileApp": { "message": "Pobierz aplikację mobilną" }, "getTheMobileAppDesc": { - "message": "Uzyskaj dostęp do haseł przy pomocy aplikacji mobilnej Bitwarden." + "message": "Uzyskaj dostęp do haseł za pomocą aplikacji mobilnej Bitwarden." }, "getTheDesktopApp": { "message": "Pobierz aplikację desktopową" }, "getTheDesktopAppDesc": { - "message": "Uzyskaj dostęp do sejfu bez przeglądarki, a następnie ustaw odblokowanie biometryczne, aby przyspieszyć odblokowanie zarówno w aplikacji desktopowej, jak i w rozszerzeniu przeglądarki." + "message": "Uzyskaj dostęp do sejfu bez przeglądarki. Skonfiguruj biometrię, aby przyśpieszyć odblokowywanie aplikacji." }, "downloadFromBitwardenNow": { "message": "Pobierz z bitwarden.com" @@ -4787,7 +4790,7 @@ "message": "Filtruj sejf" }, "filterApplied": { - "message": "Zastosowano jeden filtr" + "message": "Zastosowano 1 filtr" }, "filterAppliedPlural": { "message": "$COUNT$ filtrów zastosowanych", @@ -4817,7 +4820,7 @@ } }, "cardNumberEndsWith": { - "message": "numer karty kończy się", + "message": "numer karty kończący się", "description": "Used within the inline menu to provide an aria description when users are attempting to fill a card cipher." }, "loginCredentials": { @@ -4886,7 +4889,7 @@ "message": "Karta wygasła" }, "cardExpiredMessage": { - "message": "Jeśli ją wznowiłeś, zaktualizuj informacje o karcie" + "message": "Jeśli karta została odnowiona, zaktualizuj informacje o niej" }, "cardDetails": { "message": "Szczegóły karty" @@ -4924,7 +4927,7 @@ "description": "A section header for a list of passwords." }, "logInWithPasskeyAriaLabel": { - "message": "Logowaniem kluczem dostępu", + "message": "Logowanie kluczem dostępu", "description": "ARIA label for the inline menu button that logs in with a passkey." }, "assign": { @@ -4964,16 +4967,16 @@ "message": "Użyj pól tekstowych dla danych takich jak pytania bezpieczeństwa" }, "hiddenHelpText": { - "message": "Użyj ukrytych pól dla danych poufnych, takich jak hasło" + "message": "Użyj ukrytych pól dla danych poufnych takich jak hasło" }, "checkBoxHelpText": { - "message": "Użyj pól wyboru, jeśli chcesz automatycznie wypełnić pole wyboru formularza, np. zapamiętaj e-mail" + "message": "Użyj pól wyboru, gdy chcesz uzupełnić pole wyboru formularza, np. zapamiętaj adres e-mail" }, "linkedHelpText": { "message": "Użyj powiązanego pola, gdy masz problemy z autouzupełnianiem na konkretnej stronie internetowej." }, "linkedLabelHelpText": { - "message": "Wprowadź atrybut z HTML'a: id, name, aria-label lub placeholder." + "message": "Wpisz identyfikator, nazwę, etykietę lub tekst zastępczy pola HTML." }, "editField": { "message": "Edytuj pole" @@ -5006,7 +5009,7 @@ } }, "reorderToggleButton": { - "message": "Zmień kolejność $LABEL$. Użyj klawiszy ze strzałkami, aby przenieść element w górę lub w dół.", + "message": "Zmień kolejność pola $LABEL$. Użyj klawiszy ze strzałkami, aby przenieść element w górę lub w dół.", "placeholders": { "label": { "content": "$1", @@ -5015,10 +5018,10 @@ } }, "reorderWebsiteUriButton": { - "message": "Zmień kolejność URI strony. Użyj klawiszy ze strzałkami, aby przenieść element w górę lub w dół." + "message": "Zmień kolejność URI stron internetowych. Użyj klawiszy ze strzałkami, aby przenieść element w górę lub w dół." }, "reorderFieldUp": { - "message": "$LABEL$ przeniósł się w górę, pozycja $INDEX$ z $LENGTH$", + "message": "Pole $LABEL$ zostało przeniesione w górę. Pozycja $INDEX$ z $LENGTH$", "placeholders": { "label": { "content": "$1", @@ -5075,7 +5078,7 @@ "message": "Przypisano kolekcje" }, "nothingSelected": { - "message": "Nie zaznaczyłeś żadnych elementów." + "message": "Nie zaznaczono żadnych elementów." }, "itemsMovedToOrg": { "message": "Elementy zostały przeniesione do organizacji $ORGNAME$", @@ -5096,7 +5099,7 @@ } }, "reorderFieldDown": { - "message": "$LABEL$ przeniósł się w dół, pozycja $INDEX$ z $LENGTH$", + "message": "Pole $LABEL$ zostało przeniesione w dół. Pozycja $INDEX$ z $LENGTH$", "placeholders": { "label": { "content": "$1", @@ -5140,7 +5143,7 @@ "message": "Domyślny systemu" }, "enterprisePolicyRequirementsApplied": { - "message": "Zastosowano wymagania zasady organizacji" + "message": "Wymagania zasady organizacji zostały zastosowane" }, "sshPrivateKey": { "message": "Klucz prywatny" @@ -5167,7 +5170,7 @@ "message": "RSA 4096-bit" }, "retry": { - "message": "Powtórz" + "message": "Spróbuj ponownie" }, "vaultCustomTimeoutMinimum": { "message": "Minimalny niestandardowy czas to 1 minuta." @@ -5176,7 +5179,7 @@ "message": "Dostępna jest dodatkowa zawartość" }, "fileSavedToDevice": { - "message": "Plik zapisany na urządzeniu. Zarządzaj plikiem na swoim urządzeniu." + "message": "Plik został zapisany na urządzeniu." }, "showCharacterCount": { "message": "Pokaż liczbę znaków" @@ -5200,10 +5203,10 @@ "message": "Przywróć" }, "deleteForever": { - "message": "Usuń na zawsze" + "message": "Usuń trwale" }, "noEditPermissions": { - "message": "Nie masz uprawnień do edycji tego elementu" + "message": "Nie masz uprawnień do edycji elementu" }, "biometricsStatusHelptextUnlockNeeded": { "message": "Odblokowanie biometrią jest niedostępne, ponieważ najpierw wymagane jest odblokowanie kodem PIN lub hasłem." @@ -5410,10 +5413,10 @@ "message": "Szerokość rozszerzenia" }, "wide": { - "message": "Szerokie" + "message": "Szeroka" }, "extraWide": { - "message": "Bardzo szerokie" + "message": "Bardzo szeroka" }, "sshKeyWrongPassword": { "message": "Hasło jest nieprawidłowe." @@ -5455,16 +5458,16 @@ "message": "Zaktualizuj aplikację desktopową" }, "updateDesktopAppOrDisableFingerprintDialogMessage": { - "message": "Aby używać odblokowywania biometrycznego, zaktualizuj aplikację na komputerze lub wyłącz odblokowywanie odciskiem palca w ustawieniach aplikacji na komputerze." + "message": "Aby używać biometrii, zaktualizuj aplikację desktopową." }, "changeAtRiskPassword": { "message": "Zmień zagrożone hasło" }, "settingsVaultOptions": { - "message": "Ustawienia Sejfu" + "message": "Opcje sejfu" }, "emptyVaultDescription": { - "message": "Sejf chroni nie tylko Twoje hasła. Przechowuj tutaj bezpiecznie loginy, identyfikatory, karty i notatki." + "message": "Sejf chroni nie tylko hasła. Przechowuj bezpiecznie dane logowania, identyfikatory, karty i notatki." }, "introCarouselLabel": { "message": "Witaj w Bitwarden" @@ -5509,13 +5512,13 @@ "message": "Witaj w sejfie!" }, "hasItemsVaultNudgeBodyOne": { - "message": "Autouzupełnianie elementów dla bieżącej strony" + "message": "Uzupełniaj elementy na stronie internetowej" }, "hasItemsVaultNudgeBodyTwo": { - "message": "Ulubione elementy dla szybkiego dostępu" + "message": "Dodawaj do ulubionych wybrane elementy" }, "hasItemsVaultNudgeBodyThree": { - "message": "Przeszukaj sejf w poszukiwaniu czegoś innego" + "message": "Przeszukuj sejf w poszukiwaniu czegoś innego" }, "newLoginNudgeTitle": { "message": "Oszczędzaj czas dzięki autouzupełnianiu" @@ -5584,7 +5587,7 @@ "description": "Aria label for the body content of the generator nudge" }, "noPermissionsViewPage": { - "message": "Nie masz uprawnień do przeglądania tej strony. Spróbuj zalogować się na inne konto." + "message": "Nie masz uprawnień do przeglądania tej strony. Zaloguj się na inne konto." }, "wasmNotSupported": { "message": "WebAssembly nie jest obsługiwany w przeglądarce lub jest wyłączony. WebAssembly jest wymagany do korzystania z aplikacji Bitwarden.", diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index 7d5509a628b..46fbb9beca3 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Pesquisar no Cofre" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Editar" }, diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json index 1e77e1c3035..3cd813847d1 100644 --- a/apps/browser/src/_locales/pt_PT/messages.json +++ b/apps/browser/src/_locales/pt_PT/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Procurar no cofre" }, + "resetSearch": { + "message": "Repor pesquisa" + }, "edit": { "message": "Editar" }, diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json index 7f54640af25..13fe8aa9482 100644 --- a/apps/browser/src/_locales/ro/messages.json +++ b/apps/browser/src/_locales/ro/messages.json @@ -398,7 +398,7 @@ "message": "Numele folderului" }, "folderHintText": { - "message": "Nest a folder by adding the parent folder's name followed by a “/”. Example: Social/Forums" + "message": "Grupează un folder prin adăugarea numelui folderului părinte urmat de \"/\" Exemplu: Social/Forums" }, "noFoldersAdded": { "message": "No folders added" @@ -547,6 +547,9 @@ "searchVault": { "message": "Căutare în seif" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Editare" }, @@ -887,7 +890,7 @@ "message": "Follow the steps below to finish logging in." }, "followTheStepsBelowToFinishLoggingInWithSecurityKey": { - "message": "Follow the steps below to finish logging in with your security key." + "message": "Urmează pașii de mai jos pentru a finaliza autentificarea cu cheia de securitate." }, "restartRegistration": { "message": "Reporniți înregistrarea" @@ -929,7 +932,7 @@ "message": "Make your account more secure by setting up two-step login in the Bitwarden web app." }, "twoStepLoginConfirmationTitle": { - "message": "Continue to web app?" + "message": "Continuați în aplicația web?" }, "editedFolder": { "message": "Dosar salvat" @@ -1046,7 +1049,7 @@ "message": "Click items to autofill on Vault view" }, "clickToAutofill": { - "message": "Click items in autofill suggestion to fill" + "message": "Faceți clic pe elementele din sugestia de completare automată pentru a completa" }, "clearClipboard": { "message": "Golire clipboard", diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json index db236cbfcc8..a5a6809a059 100644 --- a/apps/browser/src/_locales/ru/messages.json +++ b/apps/browser/src/_locales/ru/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Поиск в хранилище" }, + "resetSearch": { + "message": "Сбросить поиск" + }, "edit": { "message": "Изменить" }, @@ -3795,7 +3798,7 @@ "message": "В целях обеспечения безопасности вашего аккаунта продолжайте только в том случае, если вы являетесь членом этой организации, у вас включено восстановление аккаунта, а отображаемый ниже отпечаток совпадает с отпечатком организации." }, "orgTrustWarning1": { - "message": "В этой организации действует политика, которая позволит вам участвовать в восстановлении аккаунта. Регистрация позволит администраторам организации изменить ваш пароль. Продолжайте, только если вы знаете эту организацию и фраза отпечатков, показанная ниже, совпадает с отпечатками организации." + "message": "Эта организация имеет корпоративную политику, которая зарегистрирует вас в системе восстановления аккаунта. Регистрация позволит администраторам организации изменить ваш пароль. Продолжайте только в том случае, если вы узнаете эту организацию и фраза отпечатка, отображаемая ниже, соответствует отпечатку организации." }, "trustUser": { "message": "Доверенный пользователь" @@ -5242,7 +5245,7 @@ "message": "Установить PIN--код разблокировки" }, "unlockWithBiometricSet": { - "message": "Разблокировать с помощью биометрии" + "message": "Разблокировка с помощью биометрии настроена" }, "authenticating": { "message": "Аутентификация" diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json index 13e6c2522bf..7bc0ba2694a 100644 --- a/apps/browser/src/_locales/si/messages.json +++ b/apps/browser/src/_locales/si/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "සුරක්ෂිතාගාරය සොයන්න" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "සංස්කරණය" }, diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json index e98c643edb9..28a687be339 100644 --- a/apps/browser/src/_locales/sk/messages.json +++ b/apps/browser/src/_locales/sk/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Prehľadávať trezor" }, + "resetSearch": { + "message": "Resetovať vyhľadávanie" + }, "edit": { "message": "Upraviť" }, diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index 397b7be54e8..2db40266cd7 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Išči v trezorju" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Uredi" }, diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index f68d0b97447..3ee18612553 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Претражи сеф" }, + "resetSearch": { + "message": "Ресетовати претрагу" + }, "edit": { "message": "Уреди" }, @@ -1830,7 +1833,7 @@ "message": "Сигурносни код" }, "cardNumber": { - "message": "card number" + "message": "број картице" }, "ex": { "message": "нпр." @@ -3464,7 +3467,7 @@ "message": "Захтев је послат" }, "loginRequestApprovedForEmailOnDevice": { - "message": "Login request approved for $EMAIL$ on $DEVICE$", + "message": "Захтев за пријаву одобрен за $EMAIL$ на $DEVICE$", "placeholders": { "email": { "content": "$1", @@ -3477,13 +3480,13 @@ } }, "youDeniedLoginAttemptFromAnotherDevice": { - "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + "message": "Одбили сте покушај пријаве са другог уређаја. Ако сте то били ви, покушајте поново да се пријавите помоћу уређаја." }, "device": { - "message": "Device" + "message": "Уређај" }, "loginStatus": { - "message": "Login status" + "message": "Статус пријаве" }, "masterPasswordChanged": { "message": "Главна лозинка сачувана" @@ -3582,28 +3585,28 @@ "message": "Запамтити овај уређај да би будуће пријаве биле беспрекорне" }, "manageDevices": { - "message": "Manage devices" + "message": "Управљање уређајима" }, "currentSession": { - "message": "Current session" + "message": "Тренутна сесија" }, "mobile": { - "message": "Mobile", + "message": "Мобилни", "description": "Mobile app" }, "extension": { - "message": "Extension", + "message": "Додатак", "description": "Browser extension/addon" }, "desktop": { - "message": "Desktop", + "message": "Десктоп", "description": "Desktop app" }, "webVault": { - "message": "Web vault" + "message": "Интернет Сеф" }, "webApp": { - "message": "Web app" + "message": "Веб апликација" }, "cli": { "message": "CLI" @@ -3613,22 +3616,22 @@ "description": "Software Development Kit" }, "requestPending": { - "message": "Request pending" + "message": "Захтев је на чекању" }, "firstLogin": { - "message": "First login" + "message": "Прва пријава" }, "trusted": { - "message": "Trusted" + "message": "Поуздан" }, "needsApproval": { - "message": "Needs approval" + "message": "Потребно је одобрење" }, "devices": { - "message": "Devices" + "message": "Уређаји" }, "accessAttemptBy": { - "message": "Access attempt by $EMAIL$", + "message": "Покушај приступа са $EMAIL$", "placeholders": { "email": { "content": "$1", @@ -3637,28 +3640,28 @@ } }, "confirmAccess": { - "message": "Confirm access" + "message": "Потврди приступ" }, "denyAccess": { - "message": "Deny access" + "message": "Одбиј приступ" }, "time": { - "message": "Time" + "message": "Време" }, "deviceType": { - "message": "Device Type" + "message": "Тип уређаја" }, "loginRequest": { - "message": "Login request" + "message": "Захтев за пријаву" }, "thisRequestIsNoLongerValid": { - "message": "This request is no longer valid." + "message": "Овај захтев више није важећи." }, "areYouTryingToAccessYourAccount": { - "message": "Are you trying to access your account?" + "message": "Да ли покушавате да приступите вашем налогу?" }, "logInConfirmedForEmailOnDevice": { - "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "message": "Пријава потврђена за $EMAIL$ на $DEVICE$", "placeholders": { "email": { "content": "$1", @@ -3671,16 +3674,16 @@ } }, "youDeniedALogInAttemptFromAnotherDevice": { - "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + "message": "Одбили сте покушај пријаве са другог уређаја. Ако сте то заиста били ви, покушајте поново да се пријавите помоћу уређаја." }, "loginRequestHasAlreadyExpired": { - "message": "Login request has already expired." + "message": "Захтев за пријаву је већ истекао." }, "justNow": { - "message": "Just now" + "message": "Управо сада" }, "requestedXMinutesAgo": { - "message": "Requested $MINUTES$ minutes ago", + "message": "Затражено пре $MINUTES$ минута", "placeholders": { "minutes": { "content": "$1", @@ -4598,7 +4601,7 @@ } }, "copyFieldCipherName": { - "message": "Copy $FIELD$, $CIPHERNAME$", + "message": "Копирај $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index cbfc3e478f5..49d2765bf6e 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Sök i valvet" }, + "resetSearch": { + "message": "Nollställ sökning" + }, "edit": { "message": "Redigera" }, diff --git a/apps/browser/src/_locales/te/messages.json b/apps/browser/src/_locales/te/messages.json index 9a6d9a4d316..f4c58318bc1 100644 --- a/apps/browser/src/_locales/te/messages.json +++ b/apps/browser/src/_locales/te/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Search vault" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "Edit" }, diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json index 49515eb1c64..fd92c71c200 100644 --- a/apps/browser/src/_locales/th/messages.json +++ b/apps/browser/src/_locales/th/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "ค้นหาในตู้นิรภัย" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "แก้ไข" }, diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index cd7c8d3f0b6..83265497ddf 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -462,13 +462,13 @@ "message": "Parola oluştur" }, "generatePassphrase": { - "message": "Parola üret" + "message": "Parola cümlesi üret" }, "passwordGenerated": { "message": "Parola üretildi" }, "passphraseGenerated": { - "message": "Parola ifadesi oluşturuldu" + "message": "Parola cümlesi üretildi" }, "usernameGenerated": { "message": "Kullanıcı adı üretildi" @@ -547,6 +547,9 @@ "searchVault": { "message": "Kasada ara" }, + "resetSearch": { + "message": "Aramayı sıfırla" + }, "edit": { "message": "Düzenle" }, @@ -569,7 +572,7 @@ "message": "Kimlik doğrulama sırrı" }, "passphrase": { - "message": "Uzun söz" + "message": "Parola cümlesi" }, "favorite": { "message": "Favori" @@ -2217,7 +2220,7 @@ "message": "Bu parolayı kullan" }, "useThisPassphrase": { - "message": "Bu parola ifadesini kullanın" + "message": "Bu parola cümlesini kullan" }, "useThisUsername": { "message": "Bu kullanıcı adını kullan" @@ -3180,7 +3183,7 @@ } }, "passphraseNumWordsRecommendationHint": { - "message": "Güçlü bir parola ifadesi oluşturmak için $RECOMMENDED$ veya daha fazla kelime kullanın.", + "message": " Güçlü bir parola cümlesi üretmek için en az $RECOMMENDED$ kelime kullanın.", "description": "Appended to `spinboxBoundariesHint` to recommend a number of words to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json index 083d89fbd12..a03440efe02 100644 --- a/apps/browser/src/_locales/uk/messages.json +++ b/apps/browser/src/_locales/uk/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "Пошук" }, + "resetSearch": { + "message": "Скинути пошук" + }, "edit": { "message": "Змінити" }, @@ -1830,7 +1833,7 @@ "message": "Код безпеки" }, "cardNumber": { - "message": "card number" + "message": "номер картки" }, "ex": { "message": "зразок" @@ -3464,7 +3467,7 @@ "message": "Запит надіслано" }, "loginRequestApprovedForEmailOnDevice": { - "message": "Login request approved for $EMAIL$ on $DEVICE$", + "message": "Запит входу підтверджено для $EMAIL$ на $DEVICE$", "placeholders": { "email": { "content": "$1", @@ -3477,13 +3480,13 @@ } }, "youDeniedLoginAttemptFromAnotherDevice": { - "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + "message": "Ви відхилили спробу входу з іншого пристрою. Якщо це були ви, спробуйте ввійти з пристроєм знову." }, "device": { - "message": "Device" + "message": "Пристрій" }, "loginStatus": { - "message": "Login status" + "message": "Стан входу в систему" }, "masterPasswordChanged": { "message": "Головний пароль збережено" @@ -3582,28 +3585,28 @@ "message": "Запам'ятайте цей пристрій, щоб спростити майбутні входи в систему" }, "manageDevices": { - "message": "Manage devices" + "message": "Керувати пристроями" }, "currentSession": { - "message": "Current session" + "message": "Поточний сеанс" }, "mobile": { - "message": "Mobile", + "message": "Мобільний", "description": "Mobile app" }, "extension": { - "message": "Extension", + "message": "Розширення", "description": "Browser extension/addon" }, "desktop": { - "message": "Desktop", + "message": "Комп'ютер", "description": "Desktop app" }, "webVault": { - "message": "Web vault" + "message": "Вебсховище" }, "webApp": { - "message": "Web app" + "message": "Вебпрограма" }, "cli": { "message": "CLI" @@ -3613,22 +3616,22 @@ "description": "Software Development Kit" }, "requestPending": { - "message": "Request pending" + "message": "Запит в очікуванні" }, "firstLogin": { - "message": "First login" + "message": "Перший вхід" }, "trusted": { - "message": "Trusted" + "message": "Надійний" }, "needsApproval": { - "message": "Needs approval" + "message": "Потребує підтвердження" }, "devices": { - "message": "Devices" + "message": "Пристрої" }, "accessAttemptBy": { - "message": "Access attempt by $EMAIL$", + "message": "Спроба доступу з $EMAIL$", "placeholders": { "email": { "content": "$1", @@ -3637,28 +3640,28 @@ } }, "confirmAccess": { - "message": "Confirm access" + "message": "Підтвердити доступ" }, "denyAccess": { - "message": "Deny access" + "message": "Заборонити доступ" }, "time": { - "message": "Time" + "message": "Час" }, "deviceType": { - "message": "Device Type" + "message": "Тип пристрою" }, "loginRequest": { - "message": "Login request" + "message": "Запит входу" }, "thisRequestIsNoLongerValid": { - "message": "This request is no longer valid." + "message": "Цей запит більше недійсний." }, "areYouTryingToAccessYourAccount": { - "message": "Are you trying to access your account?" + "message": "Ви намагаєтесь отримати доступ до свого облікового запису?" }, "logInConfirmedForEmailOnDevice": { - "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "message": "Підтверджено вхід для $EMAIL$ на $DEVICE$", "placeholders": { "email": { "content": "$1", @@ -3671,16 +3674,16 @@ } }, "youDeniedALogInAttemptFromAnotherDevice": { - "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + "message": "Ви відхилили спробу входу з іншого пристрою. Якщо це були дійсно ви, спробуйте ввійти з пристроєм знову." }, "loginRequestHasAlreadyExpired": { - "message": "Login request has already expired." + "message": "Термін дії запиту на вхід завершився." }, "justNow": { - "message": "Just now" + "message": "Щойно" }, "requestedXMinutesAgo": { - "message": "Requested $MINUTES$ minutes ago", + "message": "Запитано $MINUTES$ хвилин тому", "placeholders": { "minutes": { "content": "$1", @@ -4598,7 +4601,7 @@ } }, "copyFieldCipherName": { - "message": "Copy $FIELD$, $CIPHERNAME$", + "message": "Копіювати $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json index b5de1c2981c..f25cc9c51dc 100644 --- a/apps/browser/src/_locales/vi/messages.json +++ b/apps/browser/src/_locales/vi/messages.json @@ -453,7 +453,7 @@ "message": "Ứng dụng web Bitwarden" }, "importItems": { - "message": "Nhập mục" + "message": "Nhập vào kho" }, "select": { "message": "Chọn" @@ -547,6 +547,9 @@ "searchVault": { "message": "Tìm kiếm trong kho lưu trữ" }, + "resetSearch": { + "message": "Đặt lại tìm kiếm" + }, "edit": { "message": "Sửa" }, @@ -1013,16 +1016,16 @@ "description": "This is the folder for uncategorized items" }, "enableAddLoginNotification": { - "message": "Hỏi để thêm đăng nhập" + "message": "Gợi ý thêm mục đăng nhập" }, "vaultSaveOptionsTitle": { "message": "Tùy chọn lưu vào kho" }, "addLoginNotificationDesc": { - "message": "Nếu không tìm thấy mục nào trong kho của bạn, hãy yêu cầu thêm mục đó." + "message": "Gợi ý thêm mục nếu không tìm thấy mục nào trong kho trùng khớp." }, "addLoginNotificationDescAlt": { - "message": "Nếu không tìm thấy mục nào trong kho của bạn, hãy yêu cầu thêm mục đó. Áp dụng cho tất cả tài khoản đã đăng nhập." + "message": "Gợi ý thêm mục nếu không tìm thấy mục nào trong kho trùng khớp. Áp dụng cho tất cả tài khoản đã đăng nhập." }, "showCardsInVaultViewV2": { "message": "Luôn hiển thị thẻ như đề xuất tự động điền trên giao diện kho" @@ -1223,7 +1226,7 @@ "description": "Default URI match detection for autofill." }, "defaultUriMatchDetectionDesc": { - "message": "Chọn cách thức mặc định hệ thống so khớp đường dẫn (URI) để xử lý đăng nhập khi thực hiện các thao tác như tự động điền." + "message": "Chọn cách hệ thống so khớp đường dẫn để xử lý đăng nhập khi thực hiện các thao tác như tự động điền." }, "theme": { "message": "Chủ đề" @@ -1735,7 +1738,7 @@ "message": "Văn bản" }, "cfTypeHidden": { - "message": "Đã ẩn đi" + "message": "Bí ẩn" }, "cfTypeBoolean": { "message": "Đúng/Sai" @@ -1845,10 +1848,10 @@ "message": "Bà" }, "ms": { - "message": "Chị" + "message": "Cô" }, "dr": { - "message": "Bác sĩ" + "message": "Tiến sĩ/Bác sĩ" }, "mx": { "message": "Mx" @@ -1902,7 +1905,7 @@ "message": "Xã / Phường" }, "stateProvince": { - "message": "Tỉnh/Thành Phố" + "message": "Tỉnh / Thành Phố" }, "zipPostalCode": { "message": "Mã bưu chính" @@ -2109,7 +2112,7 @@ "description": "ex. Date this item was updated" }, "dateCreated": { - "message": "Ngày tạo", + "message": "Tạo lúc", "description": "ex. Date this item was created" }, "datePasswordUpdated": { @@ -2688,7 +2691,7 @@ "message": "Giới hạn số lượt xem" }, "limitSendViewsHint": { - "message": "Không ai có thể xem mục Gửi này sau khi đạt đến giới hạn.", + "message": "Không ai có thể xem Send này sau khi đạt đến giới hạn.", "description": "Displayed under the limit views field on Send" }, "limitSendViewsCount": { @@ -2727,7 +2730,7 @@ "description": "This text will be displayed after a Send has been accessed the maximum amount of times." }, "hideTextByDefault": { - "message": "Mặc định ẩn văn bản" + "message": "Ẩn văn bản theo mặc định" }, "expired": { "message": "Đã hết hạn" @@ -2782,7 +2785,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "deletionDate": { - "message": "Ngày xóa" + "message": "Xóa sau" }, "deletionDateDescV2": { "message": "Send sẽ được xóa vĩnh viễn vào ngày này.", @@ -4312,7 +4315,7 @@ "message": "Yêu cầu xác thực LastPass" }, "awaitingSSO": { - "message": "Đang chờ xác thực Đăng nhập một lần" + "message": "Đang chờ xác thực SSO" }, "awaitingSSODesc": { "message": "Vui lòng tiếp tục đăng nhập bằng thông tin đăng nhập của công ty bạn." @@ -4757,7 +4760,7 @@ "message": "Truy cập mật khẩu của bạn mọi lúc mọi nơi với ứng dụng di động Bitwarden." }, "getTheDesktopApp": { - "message": "Tải ứng dụng cho máy tính" + "message": "Tải ứng dụng máy tính" }, "getTheDesktopAppDesc": { "message": "Truy cập kho lưu trữ của bạn mà không cần trình duyệt, sau đó thiết lập mở khóa bằng sinh trắc học để mở khóa dễ dàng trong cả ứng dụng trên máy tính và tiện ích mở rộng trình duyệt." @@ -4892,7 +4895,7 @@ "message": "Thông tin thẻ" }, "cardBrandDetails": { - "message": "Chi tiết $BRAND$", + "message": "Chi tiết thẻ $BRAND$", "placeholders": { "brand": { "content": "$1", diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index f44265425e9..2382e6fc971 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "搜索密码库" }, + "resetSearch": { + "message": "重置搜索" + }, "edit": { "message": "编辑" }, @@ -3477,7 +3480,7 @@ } }, "youDeniedLoginAttemptFromAnotherDevice": { - "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + "message": "您拒绝了一个来自其他设备的登录尝试。若确实是您本人,请尝试再次发起设备登录。" }, "device": { "message": "设备" @@ -3585,25 +3588,25 @@ "message": "Manage devices" }, "currentSession": { - "message": "Current session" + "message": "当前会话" }, "mobile": { - "message": "Mobile", + "message": "移动端", "description": "Mobile app" }, "extension": { - "message": "Extension", + "message": "扩展", "description": "Browser extension/addon" }, "desktop": { - "message": "Desktop", + "message": "桌面端", "description": "Desktop app" }, "webVault": { - "message": "Web vault" + "message": "网页密码库" }, "webApp": { - "message": "Web app" + "message": "网页 App" }, "cli": { "message": "CLI" @@ -3613,7 +3616,7 @@ "description": "Software Development Kit" }, "requestPending": { - "message": "Request pending" + "message": "请求待处理" }, "firstLogin": { "message": "First login" @@ -3671,7 +3674,7 @@ } }, "youDeniedALogInAttemptFromAnotherDevice": { - "message": "您拒绝了另一台设备的登录尝试。如果真的是您,请尝试再次使用该设备登录。" + "message": "您拒绝了一个来自其他设备的登录尝试。若确实是您本人,请尝试再次发起设备登录。" }, "loginRequestHasAlreadyExpired": { "message": "登录请求已过期。" @@ -3680,7 +3683,7 @@ "message": "Just now" }, "requestedXMinutesAgo": { - "message": "Requested $MINUTES$ minutes ago", + "message": "请求于 $MINUTES$ 分钟前", "placeholders": { "minutes": { "content": "$1", @@ -4407,7 +4410,7 @@ "description": "Content for dialog which warns a user when selecting 'starts with' matching strategy as a cipher match strategy" }, "uriMatchWarningDialogLink": { - "message": "More about match detection", + "message": "更多关于匹配检测", "description": "Link to match detection docs on warning dialog for advance match strategy" }, "uriAdvancedOption": { diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json index b41b9271c75..d2776cb227d 100644 --- a/apps/browser/src/_locales/zh_TW/messages.json +++ b/apps/browser/src/_locales/zh_TW/messages.json @@ -547,6 +547,9 @@ "searchVault": { "message": "搜尋密碼庫" }, + "resetSearch": { + "message": "Reset search" + }, "edit": { "message": "編輯" }, diff --git a/apps/browser/src/auth/popup/account-switching/current-account.component.html b/apps/browser/src/auth/popup/account-switching/current-account.component.html index f59a2b08fdd..09342c58756 100644 --- a/apps/browser/src/auth/popup/account-switching/current-account.component.html +++ b/apps/browser/src/auth/popup/account-switching/current-account.component.html @@ -1,4 +1,4 @@ -
+
-
-

- {{ "setMasterPassword" | i18n }} -

-
- -
- -
-
- -
-
-
-

- {{ "orgPermissionsUpdatedMustSetPassword" | i18n }} -

- - -

{{ "orgRequiresYouToSetPassword" | i18n }}

-
- - - {{ "resetPasswordAutoEnrollInviteWarning" | i18n }} - - - -
-
-
-
-
-
- - -
-
- -
-
- - - -
-
- -
-
-
-
-
-
- - -
-
- -
-
-
-
-
-
-
-
- - -
-
- -
-
-
- diff --git a/apps/browser/src/auth/popup/set-password.component.ts b/apps/browser/src/auth/popup/set-password.component.ts deleted file mode 100644 index 2a796854531..00000000000 --- a/apps/browser/src/auth/popup/set-password.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component } from "@angular/core"; - -import { SetPasswordComponent as BaseSetPasswordComponent } from "@bitwarden/angular/auth/components/set-password.component"; - -@Component({ - selector: "app-set-password", - templateUrl: "set-password.component.html", - standalone: false, -}) -export class SetPasswordComponent extends BaseSetPasswordComponent {} diff --git a/apps/browser/src/auth/popup/settings/account-security.component.spec.ts b/apps/browser/src/auth/popup/settings/account-security.component.spec.ts index b50e1f55032..014f2a7638b 100644 --- a/apps/browser/src/auth/popup/settings/account-security.component.spec.ts +++ b/apps/browser/src/auth/popup/settings/account-security.component.spec.ts @@ -5,7 +5,6 @@ import { mock } from "jest-mock-extended"; import { firstValueFrom, of } from "rxjs"; import { CollectionService } from "@bitwarden/admin-console/common"; -import { PinServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; @@ -13,6 +12,7 @@ import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; +import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction"; import { VaultTimeoutSettingsService, VaultTimeoutService, diff --git a/apps/browser/src/auth/popup/settings/account-security.component.ts b/apps/browser/src/auth/popup/settings/account-security.component.ts index 6c072532a5d..b41cfe14c4f 100644 --- a/apps/browser/src/auth/popup/settings/account-security.component.ts +++ b/apps/browser/src/auth/popup/settings/account-security.component.ts @@ -25,7 +25,6 @@ import { JslibModule } from "@bitwarden/angular/jslib.module"; import { NudgesService, NudgeType } from "@bitwarden/angular/vault"; import { SpotlightComponent } from "@bitwarden/angular/vault/components/spotlight/spotlight.component"; import { FingerprintDialogComponent, VaultTimeoutInputComponent } from "@bitwarden/auth/angular"; -import { PinServiceAbstraction } from "@bitwarden/auth/common"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { getFirstPolicy } from "@bitwarden/common/admin-console/services/policy/default-policy.service"; @@ -33,6 +32,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { PinServiceAbstraction } from "@bitwarden/common/key-management/pin/pin.service.abstraction"; import { VaultTimeout, VaultTimeoutAction, diff --git a/apps/browser/src/auth/popup/settings/vault-timeout-input.component.html b/apps/browser/src/auth/popup/settings/vault-timeout-input.component.html deleted file mode 100644 index c62f29130bf..00000000000 --- a/apps/browser/src/auth/popup/settings/vault-timeout-input.component.html +++ /dev/null @@ -1,44 +0,0 @@ -
-
- - -
-
-
-
-
- - -
-
-
-
- - -
-
-
-
-
diff --git a/apps/browser/src/auth/popup/settings/vault-timeout-input.component.ts b/apps/browser/src/auth/popup/settings/vault-timeout-input.component.ts deleted file mode 100644 index 25a4d01333d..00000000000 --- a/apps/browser/src/auth/popup/settings/vault-timeout-input.component.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Component } from "@angular/core"; -import { NG_VALIDATORS, NG_VALUE_ACCESSOR } from "@angular/forms"; - -import { VaultTimeoutInputComponent as VaultTimeoutInputComponentBase } from "@bitwarden/auth/angular"; - -@Component({ - selector: "app-vault-timeout-input", - templateUrl: "vault-timeout-input.component.html", - providers: [ - { - provide: NG_VALUE_ACCESSOR, - multi: true, - useExisting: VaultTimeoutInputComponent, - }, - { - provide: NG_VALIDATORS, - multi: true, - useExisting: VaultTimeoutInputComponent, - }, - ], - standalone: false, -}) -export class VaultTimeoutInputComponent extends VaultTimeoutInputComponentBase {} diff --git a/apps/browser/src/auth/popup/update-temp-password.component.html b/apps/browser/src/auth/popup/update-temp-password.component.html deleted file mode 100644 index 0ce82aa20cf..00000000000 --- a/apps/browser/src/auth/popup/update-temp-password.component.html +++ /dev/null @@ -1,142 +0,0 @@ -
-
-
- -
-

- {{ "updateMasterPassword" | i18n }} -

-
- -
-
-
- - {{ masterPasswordWarningText }} - - - -
-
-
-
-
- - -
-
-
-
-
-
-
-
-
-
- - -
-
- -
-
- - -
-
-
-
-
-
-
- - -
-
- -
-
-
-
-
-
-
- - -
-
- -
-
-
diff --git a/apps/browser/src/auth/popup/update-temp-password.component.ts b/apps/browser/src/auth/popup/update-temp-password.component.ts deleted file mode 100644 index e8cf64b7548..00000000000 --- a/apps/browser/src/auth/popup/update-temp-password.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Component } from "@angular/core"; -import { firstValueFrom } from "rxjs"; - -import { UpdateTempPasswordComponent as BaseUpdateTempPasswordComponent } from "@bitwarden/angular/auth/components/update-temp-password.component"; - -import { postLogoutMessageListener$ } from "./utils/post-logout-message-listener"; - -@Component({ - selector: "app-update-temp-password", - templateUrl: "update-temp-password.component.html", - standalone: false, -}) -export class UpdateTempPasswordComponent extends BaseUpdateTempPasswordComponent { - onSuccessfulChangePassword: () => Promise = this.doOnSuccessfulChangePassword.bind(this); - - private async doOnSuccessfulChangePassword() { - // start listening for "switchAccountFinish" or "doneLoggingOut" - const messagePromise = firstValueFrom(postLogoutMessageListener$); - this.messagingService.send("logout"); - // wait for messages - const command = await messagePromise; - - // doneLoggingOut already has a message handler that will navigate us - if (command === "switchAccountFinish") { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["/"]); - } - } -} diff --git a/apps/browser/src/autofill/background/abstractions/notification.background.ts b/apps/browser/src/autofill/background/abstractions/notification.background.ts index 9c9c5c0e243..f2152b44862 100644 --- a/apps/browser/src/autofill/background/abstractions/notification.background.ts +++ b/apps/browser/src/autofill/background/abstractions/notification.background.ts @@ -1,9 +1,6 @@ import { NeverDomains } from "@bitwarden/common/models/domain/domain-service"; import { ServerConfig } from "@bitwarden/common/platform/abstractions/config/server-config"; -import { UserId } from "@bitwarden/common/types/guid"; -import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; -import { SecurityTask } from "@bitwarden/common/vault/tasks"; import { CollectionView } from "../../content/components/common-types"; import { NotificationQueueMessageTypes } from "../../enums/notification-queue-message-type.enum"; @@ -60,23 +57,10 @@ type LockedVaultPendingNotificationsData = { target: string; }; -type AtRiskPasswordNotificationsData = { - activeUserId: UserId; - cipher: CipherView; - securityTask: SecurityTask; - uri: string; -}; - type AdjustNotificationBarMessageData = { height: number; }; -type ChangePasswordMessageData = { - currentPassword: string; - newPassword: string; - url: string; -}; - type AddLoginMessageData = { username: string; password: string; @@ -92,10 +76,7 @@ type NotificationBackgroundExtensionMessage = { command: string; data?: Partial & Partial & - Partial & - Partial & - Partial; - login?: AddLoginMessageData; + Partial; folder?: string; edit?: boolean; details?: AutofillPageDetails; @@ -121,18 +102,6 @@ type NotificationBackgroundExtensionMessageHandlers = { bgCloseNotificationBar: ({ message, sender }: BackgroundOnMessageHandlerParams) => Promise; bgOpenAtRiskPasswords: ({ message, sender }: BackgroundOnMessageHandlerParams) => Promise; bgAdjustNotificationBar: ({ message, sender }: BackgroundOnMessageHandlerParams) => Promise; - bgTriggerAddLoginNotification: ({ - message, - sender, - }: BackgroundOnMessageHandlerParams) => Promise; - bgTriggerChangedPasswordNotification: ({ - message, - sender, - }: BackgroundOnMessageHandlerParams) => Promise; - bgTriggerAtRiskPasswordNotification: ({ - message, - sender, - }: BackgroundOnMessageHandlerParams) => Promise; bgRemoveTabFromNotificationQueue: ({ sender }: BackgroundSenderParam) => void; bgSaveCipher: ({ message, sender }: BackgroundOnMessageHandlerParams) => void; bgOpenAddEditVaultItemPopout: ({ @@ -162,7 +131,6 @@ export { NotificationQueueMessageItem, LockedVaultPendingNotificationsData, AdjustNotificationBarMessageData, - ChangePasswordMessageData, UnlockVaultMessageData, AddLoginMessageData, NotificationBackgroundExtensionMessage, diff --git a/apps/browser/src/autofill/background/abstractions/overlay-notifications.background.ts b/apps/browser/src/autofill/background/abstractions/overlay-notifications.background.ts index 0ec6a9ae04a..d446e18b480 100644 --- a/apps/browser/src/autofill/background/abstractions/overlay-notifications.background.ts +++ b/apps/browser/src/autofill/background/abstractions/overlay-notifications.background.ts @@ -1,3 +1,6 @@ +import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { SecurityTask } from "@bitwarden/common/vault/tasks"; + import AutofillPageDetails from "../../models/autofill-page-details"; export type NotificationTypeData = { @@ -8,6 +11,12 @@ export type NotificationTypeData = { launchTimestamp?: number; }; +export type LoginSecurityTaskInfo = { + securityTask: SecurityTask; + cipher: CipherView; + uri: ModifyLoginCipherFormData["uri"]; +}; + export type WebsiteOriginsWithFields = Map>; export type ActiveFormSubmissionRequests = Set; diff --git a/apps/browser/src/autofill/background/abstractions/overlay.background.ts b/apps/browser/src/autofill/background/abstractions/overlay.background.ts index 5e2b755ad4a..75f2659c9df 100644 --- a/apps/browser/src/autofill/background/abstractions/overlay.background.ts +++ b/apps/browser/src/autofill/background/abstractions/overlay.background.ts @@ -245,6 +245,7 @@ export type OverlayBackgroundExtensionMessageHandlers = { editedCipher: () => void; deletedCipher: () => void; bgSaveCipher: () => void; + updateOverlayCiphers: () => void; fido2AbortRequest: ({ message, sender }: BackgroundOnMessageHandlerParams) => void; }; diff --git a/apps/browser/src/autofill/background/notification.background.spec.ts b/apps/browser/src/autofill/background/notification.background.spec.ts index 5e7e3ed30f5..7302ae7d705 100644 --- a/apps/browser/src/autofill/background/notification.background.spec.ts +++ b/apps/browser/src/autofill/background/notification.background.spec.ts @@ -3,17 +3,18 @@ import { BehaviorSubject, firstValueFrom, of } from "rxjs"; import { CollectionService } from "@bitwarden/admin-console/common"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { DefaultPolicyService } from "@bitwarden/common/admin-console/services/policy/default-policy.service"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { AuthService } from "@bitwarden/common/auth/services/auth.service"; import { ExtensionCommand } from "@bitwarden/common/autofill/constants"; import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; -import { UserNotificationSettingsService } from "@bitwarden/common/autofill/services/user-notification-settings.service"; +import { UserNotificationSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/user-notification-settings.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { ThemeTypes } from "@bitwarden/common/platform/enums"; import { SelfHostedEnvironment } from "@bitwarden/common/platform/services/default-environment.service"; import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; import { UserId } from "@bitwarden/common/types/guid"; @@ -38,6 +39,7 @@ import { LockedVaultPendingNotificationsData, NotificationBackgroundExtensionMessage, } from "./abstractions/notification.background"; +import { ModifyLoginCipherFormData } from "./abstractions/overlay-notifications.background"; import NotificationBackground from "./notification.background"; jest.mock("rxjs", () => { @@ -58,13 +60,21 @@ describe("NotificationBackground", () => { const collectionService = mock(); let activeAccountStatusMock$: BehaviorSubject; let authService: MockProxy; - const policyService = mock(); + const policyAppliesToUser$ = new BehaviorSubject(true); + const policyService = mock({ + policyAppliesToUser$: jest.fn().mockReturnValue(policyAppliesToUser$), + }); const folderService = mock(); - const userNotificationSettingsService = mock(); + const enableChangedPasswordPromptMock$ = new BehaviorSubject(true); + const userNotificationSettingsService = mock(); + userNotificationSettingsService.enableChangedPasswordPrompt$ = enableChangedPasswordPromptMock$; + const domainSettingsService = mock(); const environmentService = mock(); const logService = mock(); + const selectedThemeMock$ = new BehaviorSubject(ThemeTypes.Light); const themeStateService = mock(); + themeStateService.selectedTheme$ = selectedThemeMock$; const configService = mock(); const accountService = mock(); const organizationService = mock(); @@ -164,7 +174,7 @@ describe("NotificationBackground", () => { }); }); - describe("notification bar extension message handlers", () => { + describe("notification bar extension message handlers and triggers", () => { beforeEach(() => { notificationBackground.init(); }); @@ -283,7 +293,12 @@ describe("NotificationBackground", () => { let pushAddLoginToQueueSpy: jest.SpyInstance; let pushChangePasswordToQueueSpy: jest.SpyInstance; let getAllDecryptedForUrlSpy: jest.SpyInstance; - + const mockModifyLoginCipherFormData: ModifyLoginCipherFormData = { + username: "test", + password: "password", + uri: "https://example.com", + newPassword: null, + }; beforeEach(() => { tab = createChromeTabMock(); sender = mock({ tab }); @@ -304,43 +319,34 @@ describe("NotificationBackground", () => { }); it("skips attempting to add the login if the user is logged out", async () => { - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerAddLoginNotification", - login: { username: "test", password: "password", url: "https://example.com" }, - }; + const data: ModifyLoginCipherFormData = mockModifyLoginCipherFormData; activeAccountStatusMock$.next(AuthenticationStatus.LoggedOut); - sendMockExtensionMessage(message, sender); - await flushPromises(); + await notificationBackground.triggerAddLoginNotification(data, tab); expect(getEnableAddedLoginPromptSpy).not.toHaveBeenCalled(); expect(pushAddLoginToQueueSpy).not.toHaveBeenCalled(); }); it("skips attempting to add the login if the login data does not contain a valid url", async () => { - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerAddLoginNotification", - login: { username: "test", password: "password", url: "" }, + const data: ModifyLoginCipherFormData = { + ...mockModifyLoginCipherFormData, + uri: "", }; activeAccountStatusMock$.next(AuthenticationStatus.Locked); - sendMockExtensionMessage(message, sender); - await flushPromises(); + await notificationBackground.triggerAddLoginNotification(data, tab); expect(getEnableAddedLoginPromptSpy).not.toHaveBeenCalled(); expect(pushAddLoginToQueueSpy).not.toHaveBeenCalled(); }); it("skips attempting to add the login if the user with a locked vault has disabled the login notification", async () => { - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerAddLoginNotification", - login: { username: "test", password: "password", url: "https://example.com" }, - }; + const data: ModifyLoginCipherFormData = mockModifyLoginCipherFormData; activeAccountStatusMock$.next(AuthenticationStatus.Locked); getEnableAddedLoginPromptSpy.mockReturnValueOnce(false); - sendMockExtensionMessage(message, sender); - await flushPromises(); + await notificationBackground.triggerAddLoginNotification(data, tab); expect(getEnableAddedLoginPromptSpy).toHaveBeenCalled(); expect(getAllDecryptedForUrlSpy).not.toHaveBeenCalled(); @@ -349,16 +355,12 @@ describe("NotificationBackground", () => { }); it("skips attempting to add the login if the user with an unlocked vault has disabled the login notification", async () => { - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerAddLoginNotification", - login: { username: "test", password: "password", url: "https://example.com" }, - }; + const data: ModifyLoginCipherFormData = mockModifyLoginCipherFormData; activeAccountStatusMock$.next(AuthenticationStatus.Unlocked); getEnableAddedLoginPromptSpy.mockReturnValueOnce(false); getAllDecryptedForUrlSpy.mockResolvedValueOnce([]); - sendMockExtensionMessage(message, sender); - await flushPromises(); + await notificationBackground.triggerAddLoginNotification(data, tab); expect(getEnableAddedLoginPromptSpy).toHaveBeenCalled(); expect(getAllDecryptedForUrlSpy).toHaveBeenCalled(); @@ -367,10 +369,7 @@ describe("NotificationBackground", () => { }); it("skips attempting to change the password for an existing login if the user has disabled changing the password notification", async () => { - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerAddLoginNotification", - login: { username: "test", password: "password", url: "https://example.com" }, - }; + const data: ModifyLoginCipherFormData = mockModifyLoginCipherFormData; activeAccountStatusMock$.next(AuthenticationStatus.Unlocked); getEnableAddedLoginPromptSpy.mockReturnValueOnce(true); getEnableChangedPasswordPromptSpy.mockReturnValueOnce(false); @@ -378,8 +377,7 @@ describe("NotificationBackground", () => { mock({ login: { username: "test", password: "oldPassword" } }), ]); - sendMockExtensionMessage(message, sender); - await flushPromises(); + await notificationBackground.triggerAddLoginNotification(data, tab); expect(getEnableAddedLoginPromptSpy).toHaveBeenCalled(); expect(getAllDecryptedForUrlSpy).toHaveBeenCalled(); @@ -389,18 +387,14 @@ describe("NotificationBackground", () => { }); it("skips attempting to change the password for an existing login if the password has not changed", async () => { - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerAddLoginNotification", - login: { username: "test", password: "password", url: "https://example.com" }, - }; + const data: ModifyLoginCipherFormData = mockModifyLoginCipherFormData; activeAccountStatusMock$.next(AuthenticationStatus.Unlocked); getEnableAddedLoginPromptSpy.mockReturnValueOnce(true); getAllDecryptedForUrlSpy.mockResolvedValueOnce([ mock({ login: { username: "test", password: "password" } }), ]); - sendMockExtensionMessage(message, sender); - await flushPromises(); + await notificationBackground.triggerAddLoginNotification(data, tab); expect(getEnableAddedLoginPromptSpy).toHaveBeenCalled(); expect(getAllDecryptedForUrlSpy).toHaveBeenCalled(); @@ -409,48 +403,55 @@ describe("NotificationBackground", () => { }); it("adds the login to the queue if the user has a locked account", async () => { - const login = { username: "test", password: "password", url: "https://example.com" }; - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerAddLoginNotification", - login, - }; + const data: ModifyLoginCipherFormData = mockModifyLoginCipherFormData; activeAccountStatusMock$.next(AuthenticationStatus.Locked); getEnableAddedLoginPromptSpy.mockReturnValueOnce(true); - sendMockExtensionMessage(message, sender); - await flushPromises(); + await notificationBackground.triggerAddLoginNotification(data, tab); - expect(pushAddLoginToQueueSpy).toHaveBeenCalledWith("example.com", login, sender.tab, true); + expect(pushAddLoginToQueueSpy).toHaveBeenCalledWith( + "example.com", + { + url: data.uri, + username: data.username, + password: data.password, + }, + sender.tab, + true, + ); }); it("adds the login to the queue if the user has an unlocked account and the login is new", async () => { - const login = { - username: undefined, - password: "password", - url: "https://example.com", - } as any; - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerAddLoginNotification", - login, + const data: ModifyLoginCipherFormData = { + ...mockModifyLoginCipherFormData, + username: null, }; + activeAccountStatusMock$.next(AuthenticationStatus.Unlocked); getEnableAddedLoginPromptSpy.mockReturnValueOnce(true); getAllDecryptedForUrlSpy.mockResolvedValueOnce([ mock({ login: { username: "anotherTestUsername", password: "password" } }), ]); - sendMockExtensionMessage(message, sender); - await flushPromises(); + await notificationBackground.triggerAddLoginNotification(data, tab); - expect(pushAddLoginToQueueSpy).toHaveBeenCalledWith("example.com", login, sender.tab); + expect(pushAddLoginToQueueSpy).toHaveBeenCalledWith( + "example.com", + { + url: data.uri, + username: data.username, + password: data.password, + }, + sender.tab, + ); }); it("adds a change password message to the queue if the user has changed an existing cipher's password", async () => { - const login = { username: "tEsT", password: "password", url: "https://example.com" }; - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerAddLoginNotification", - login, + const data: ModifyLoginCipherFormData = { + ...mockModifyLoginCipherFormData, + username: "tEsT", }; + activeAccountStatusMock$.next(AuthenticationStatus.Unlocked); getEnableAddedLoginPromptSpy.mockResolvedValueOnce(true); getEnableChangedPasswordPromptSpy.mockResolvedValueOnce(true); @@ -461,13 +462,12 @@ describe("NotificationBackground", () => { }), ]); - sendMockExtensionMessage(message, sender); - await flushPromises(); + await notificationBackground.triggerAddLoginNotification(data, tab); expect(pushChangePasswordToQueueSpy).toHaveBeenCalledWith( "cipher-id", "example.com", - login.password, + data.password, sender.tab, ); }); @@ -478,6 +478,12 @@ describe("NotificationBackground", () => { let sender: chrome.runtime.MessageSender; let pushChangePasswordToQueueSpy: jest.SpyInstance; let getAllDecryptedForUrlSpy: jest.SpyInstance; + const mockModifyLoginCipherFormData: ModifyLoginCipherFormData = { + username: null, + uri: null, + password: "currentPassword", + newPassword: "newPassword", + }; beforeEach(() => { tab = createChromeTabMock(); @@ -490,69 +496,51 @@ describe("NotificationBackground", () => { }); it("skips attempting to add the change password message to the queue if the passed url is not valid", async () => { - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerChangedPasswordNotification", - data: { newPassword: "newPassword", currentPassword: "currentPassword", url: "" }, - }; + const data: ModifyLoginCipherFormData = mockModifyLoginCipherFormData; - sendMockExtensionMessage(message); - await flushPromises(); + await notificationBackground.triggerChangedPasswordNotification(data, tab); expect(pushChangePasswordToQueueSpy).not.toHaveBeenCalled(); }); it("adds a change password message to the queue if the user does not have an unlocked account", async () => { - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerChangedPasswordNotification", - data: { - newPassword: "newPassword", - currentPassword: "currentPassword", - url: "https://example.com", - }, + const data: ModifyLoginCipherFormData = { + ...mockModifyLoginCipherFormData, + uri: "https://example.com", }; + activeAccountStatusMock$.next(AuthenticationStatus.Locked); - sendMockExtensionMessage(message, sender); - await flushPromises(); + await notificationBackground.triggerChangedPasswordNotification(data, tab); expect(pushChangePasswordToQueueSpy).toHaveBeenCalledWith( null, "example.com", - message.data?.newPassword, + data?.newPassword, sender.tab, true, ); }); it("skips adding a change password message to the queue if the multiple ciphers exist for the passed URL and the current password is not found within the list of ciphers", async () => { - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerChangedPasswordNotification", - data: { - newPassword: "newPassword", - currentPassword: "currentPassword", - url: "https://example.com", - }, + const data: ModifyLoginCipherFormData = { + ...mockModifyLoginCipherFormData, + uri: "https://example.com", }; activeAccountStatusMock$.next(AuthenticationStatus.Unlocked); getAllDecryptedForUrlSpy.mockResolvedValueOnce([ mock({ login: { username: "test", password: "password" } }), ]); - - sendMockExtensionMessage(message, sender); - await flushPromises(); + await notificationBackground.triggerChangedPasswordNotification(data, tab); expect(getAllDecryptedForUrlSpy).toHaveBeenCalled(); expect(pushChangePasswordToQueueSpy).not.toHaveBeenCalled(); }); it("skips adding a change password message if more than one existing cipher is found with a matching password ", async () => { - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerChangedPasswordNotification", - data: { - newPassword: "newPassword", - currentPassword: "currentPassword", - url: "https://example.com", - }, + const data: ModifyLoginCipherFormData = { + ...mockModifyLoginCipherFormData, + uri: "https://example.com", }; activeAccountStatusMock$.next(AuthenticationStatus.Unlocked); getAllDecryptedForUrlSpy.mockResolvedValueOnce([ @@ -560,21 +548,16 @@ describe("NotificationBackground", () => { mock({ login: { username: "test2", password: "password" } }), ]); - sendMockExtensionMessage(message, sender); - await flushPromises(); + await notificationBackground.triggerChangedPasswordNotification(data, tab); expect(getAllDecryptedForUrlSpy).toHaveBeenCalled(); expect(pushChangePasswordToQueueSpy).not.toHaveBeenCalled(); }); it("adds a change password message to the queue if a single cipher matches the passed current password", async () => { - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerChangedPasswordNotification", - data: { - newPassword: "newPassword", - currentPassword: "currentPassword", - url: "https://example.com", - }, + const data: ModifyLoginCipherFormData = { + ...mockModifyLoginCipherFormData, + uri: "https://example.com", }; activeAccountStatusMock$.next(AuthenticationStatus.Unlocked); getAllDecryptedForUrlSpy.mockResolvedValueOnce([ @@ -584,24 +567,20 @@ describe("NotificationBackground", () => { }), ]); - sendMockExtensionMessage(message, sender); - await flushPromises(); + await notificationBackground.triggerChangedPasswordNotification(data, tab); expect(pushChangePasswordToQueueSpy).toHaveBeenCalledWith( "cipher-id", "example.com", - message.data?.newPassword, + data?.newPassword, sender.tab, ); }); it("skips adding a change password message if no current password is passed in the message and more than one cipher is found for a url", async () => { - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerChangedPasswordNotification", - data: { - newPassword: "newPassword", - url: "https://example.com", - }, + const data: ModifyLoginCipherFormData = { + ...mockModifyLoginCipherFormData, + uri: "https://example.com", }; activeAccountStatusMock$.next(AuthenticationStatus.Unlocked); getAllDecryptedForUrlSpy.mockResolvedValueOnce([ @@ -609,20 +588,17 @@ describe("NotificationBackground", () => { mock({ login: { username: "test2", password: "password" } }), ]); - sendMockExtensionMessage(message, sender); - await flushPromises(); + await notificationBackground.triggerChangedPasswordNotification(data, tab); expect(getAllDecryptedForUrlSpy).toHaveBeenCalled(); expect(pushChangePasswordToQueueSpy).not.toHaveBeenCalled(); }); it("adds a change password message to the queue if no current password is passed with the message, but a single cipher is matched for the uri", async () => { - const message: NotificationBackgroundExtensionMessage = { - command: "bgTriggerChangedPasswordNotification", - data: { - newPassword: "newPassword", - url: "https://example.com", - }, + const data: ModifyLoginCipherFormData = { + ...mockModifyLoginCipherFormData, + uri: "https://example.com", + password: null, }; activeAccountStatusMock$.next(AuthenticationStatus.Unlocked); getAllDecryptedForUrlSpy.mockResolvedValueOnce([ @@ -632,13 +608,12 @@ describe("NotificationBackground", () => { }), ]); - sendMockExtensionMessage(message, sender); - await flushPromises(); + await notificationBackground.triggerChangedPasswordNotification(data, tab); expect(pushChangePasswordToQueueSpy).toHaveBeenCalledWith( "cipher-id", "example.com", - message.data?.newPassword, + data?.newPassword, sender.tab, ); }); diff --git a/apps/browser/src/autofill/background/notification.background.ts b/apps/browser/src/autofill/background/notification.background.ts index 65c1ca0277f..3f6e93d8454 100644 --- a/apps/browser/src/autofill/background/notification.background.ts +++ b/apps/browser/src/autofill/background/notification.background.ts @@ -41,7 +41,7 @@ import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view"; import { LoginView } from "@bitwarden/common/vault/models/view/login.view"; import { TaskService } from "@bitwarden/common/vault/tasks"; -import { SecurityTaskType } from "@bitwarden/common/vault/tasks/enums"; +import { SecurityTaskStatus, SecurityTaskType } from "@bitwarden/common/vault/tasks/enums"; import { SecurityTask } from "@bitwarden/common/vault/tasks/models/security-task"; // FIXME (PM-22628): Popup imports are forbidden in background @@ -68,14 +68,17 @@ import { AddChangePasswordQueueMessage, AddLoginQueueMessage, AddUnlockVaultQueueMessage, - ChangePasswordMessageData, AddLoginMessageData, NotificationQueueMessageItem, LockedVaultPendingNotificationsData, NotificationBackgroundExtensionMessage, NotificationBackgroundExtensionMessageHandlers, } from "./abstractions/notification.background"; -import { NotificationTypeData } from "./abstractions/overlay-notifications.background"; +import { + LoginSecurityTaskInfo, + ModifyLoginCipherFormData, + NotificationTypeData, +} from "./abstractions/overlay-notifications.background"; import { OverlayBackgroundExtensionMessage } from "./abstractions/overlay.background"; export default class NotificationBackground { @@ -91,12 +94,6 @@ export default class NotificationBackground { private readonly extensionMessageHandlers: NotificationBackgroundExtensionMessageHandlers = { bgAdjustNotificationBar: ({ message, sender }) => this.handleAdjustNotificationBarMessage(message, sender), - bgTriggerAddLoginNotification: ({ message, sender }) => - this.triggerAddLoginNotification(message, sender), - bgTriggerChangedPasswordNotification: ({ message, sender }) => - this.triggerChangedPasswordNotification(message, sender), - bgTriggerAtRiskPasswordNotification: ({ message, sender }) => - this.triggerAtRiskPasswordNotification(message, sender), bgCloseNotificationBar: ({ message, sender }) => this.handleCloseNotificationBarMessage(message, sender), bgOpenAtRiskPasswords: ({ message, sender }) => @@ -286,6 +283,62 @@ export default class NotificationBackground { }; } + /** + * If there is a security task for this cipher at login, return the task, cipher view, and uri. + * + * @param modifyLoginData - The modified login form data + * @param activeUserId - The currently logged in user ID + */ + private async getSecurityTaskAndCipherForLoginData( + modifyLoginData: ModifyLoginCipherFormData, + activeUserId: UserId, + ): Promise { + const tasks: SecurityTask[] = await this.getSecurityTasks(activeUserId); + if (!tasks?.length) { + return null; + } + + const urlCiphers: CipherView[] = await this.cipherService.getAllDecryptedForUrl( + modifyLoginData.uri, + activeUserId, + ); + if (!urlCiphers?.length) { + return null; + } + + const securityTaskForLogin = urlCiphers.reduce( + (taskInfo: LoginSecurityTaskInfo | null, cipher: CipherView) => { + if ( + // exit early if info was found already + taskInfo || + // exit early if the cipher was deleted + cipher.deletedDate || + // exit early if the entered login info doesn't match an existing cipher + modifyLoginData.username !== cipher.login.username || + modifyLoginData.password !== cipher.login.password + ) { + return taskInfo; + } + + // Find the first security task for the cipherId belonging to the entered login + const cipherSecurityTask = tasks.find( + ({ cipherId, status }) => + cipher.id === cipherId && // match security task cipher id to url cipher id + status === SecurityTaskStatus.Pending, // security task has not been completed + ); + + if (cipherSecurityTask) { + return { securityTask: cipherSecurityTask, cipher, uri: modifyLoginData.uri }; + } + + return taskInfo; + }, + null, + ); + + return securityTaskForLogin; + } + /** * Gets the active user server config from the config service. */ @@ -302,6 +355,10 @@ export default class NotificationBackground { return flagValue; } + /** + * Gets the current authentication status of the user. + * @returns Promise - The current authentication status of the user. + */ private async getAuthStatus() { return await firstValueFrom(this.authService.activeAccountStatus$); } @@ -400,11 +457,32 @@ export default class NotificationBackground { * @param sender - The contextual sender of the message */ async triggerAtRiskPasswordNotification( - message: NotificationBackgroundExtensionMessage, - sender: chrome.runtime.MessageSender, + data: ModifyLoginCipherFormData, + tab: chrome.tabs.Tab, ): Promise { - const { activeUserId, securityTask, cipher } = message.data; - const domain = Utils.getDomain(sender.tab.url); + const flag = await this.getNotificationFlag(); + if (!flag) { + return false; + } + + const activeUserId = await firstValueFrom( + this.accountService.activeAccount$.pipe(getOptionalUserId), + ); + + if (!activeUserId) { + return false; + } + const loginSecurityTaskInfo = await this.getSecurityTaskAndCipherForLoginData( + data, + activeUserId, + ); + + if (!loginSecurityTaskInfo) { + return false; + } + + const { securityTask, cipher } = loginSecurityTaskInfo; + const domain = Utils.getDomain(tab.url); const passwordChangeUri = await new TemporaryNotificationChangeLoginService().getChangePasswordUrl(cipher); @@ -418,7 +496,7 @@ export default class NotificationBackground { .pipe(getOrganizationById(securityTask.organizationId)), ); - this.removeTabFromNotificationQueue(sender.tab); + this.removeTabFromNotificationQueue(tab); const launchTimestamp = new Date().getTime(); const queueMessage: NotificationQueueMessageItem = { domain, @@ -426,12 +504,12 @@ export default class NotificationBackground { type: NotificationQueueMessageType.AtRiskPassword, passwordChangeUri, organizationName: organization.name, - tab: sender.tab, + tab: tab, launchTimestamp, expires: new Date(launchTimestamp + NOTIFICATION_BAR_LIFESPAN_MS), }; this.notificationQueue.push(queueMessage); - await this.checkNotificationQueue(sender.tab); + await this.checkNotificationQueue(tab); return true; } @@ -444,17 +522,22 @@ export default class NotificationBackground { * @param sender - The contextual sender of the message */ async triggerAddLoginNotification( - message: NotificationBackgroundExtensionMessage, - sender: chrome.runtime.MessageSender, + data: ModifyLoginCipherFormData, + tab: chrome.tabs.Tab, ): Promise { + const login = { + url: data.uri, + username: data.username, + password: data.password || data.newPassword, + }; + const authStatus = await this.getAuthStatus(); if (authStatus === AuthenticationStatus.LoggedOut) { return false; } - const loginInfo = message.login; - const normalizedUsername = loginInfo.username ? loginInfo.username.toLowerCase() : ""; - const loginDomain = Utils.getDomain(loginInfo.url); + const normalizedUsername = login.username ? login.username.toLowerCase() : ""; + const loginDomain = Utils.getDomain(login.url); if (loginDomain == null) { return false; } @@ -463,7 +546,7 @@ export default class NotificationBackground { if (authStatus === AuthenticationStatus.Locked) { if (addLoginIsEnabled) { - await this.pushAddLoginToQueue(loginDomain, loginInfo, sender.tab, true); + await this.pushAddLoginToQueue(loginDomain, login, tab, true); } return false; @@ -476,12 +559,12 @@ export default class NotificationBackground { return false; } - const ciphers = await this.cipherService.getAllDecryptedForUrl(loginInfo.url, activeUserId); + const ciphers = await this.cipherService.getAllDecryptedForUrl(login.url, activeUserId); const usernameMatches = ciphers.filter( (c) => c.login.username != null && c.login.username.toLowerCase() === normalizedUsername, ); if (addLoginIsEnabled && usernameMatches.length === 0) { - await this.pushAddLoginToQueue(loginDomain, loginInfo, sender.tab); + await this.pushAddLoginToQueue(loginDomain, login, tab); return true; } @@ -490,14 +573,9 @@ export default class NotificationBackground { if ( changePasswordIsEnabled && usernameMatches.length === 1 && - usernameMatches[0].login.password !== loginInfo.password + usernameMatches[0].login.password !== login.password ) { - await this.pushChangePasswordToQueue( - usernameMatches[0].id, - loginDomain, - loginInfo.password, - sender.tab, - ); + await this.pushChangePasswordToQueue(usernameMatches[0].id, loginDomain, login.password, tab); return true; } return false; @@ -535,23 +613,22 @@ export default class NotificationBackground { * @param sender - The contextual sender of the message */ async triggerChangedPasswordNotification( - message: NotificationBackgroundExtensionMessage, - sender: chrome.runtime.MessageSender, - ) { - const changeData = message.data as ChangePasswordMessageData; + data: ModifyLoginCipherFormData, + tab: chrome.tabs.Tab, + ): Promise { + const changeData = { + url: data.uri, + currentPassword: data.password, + newPassword: data.newPassword, + }; + const loginDomain = Utils.getDomain(changeData.url); if (loginDomain == null) { return false; } if ((await this.getAuthStatus()) < AuthenticationStatus.Unlocked) { - await this.pushChangePasswordToQueue( - null, - loginDomain, - changeData.newPassword, - sender.tab, - true, - ); + await this.pushChangePasswordToQueue(null, loginDomain, changeData.newPassword, tab, true); return true; } @@ -575,7 +652,7 @@ export default class NotificationBackground { id = ciphers[0].id; } if (id != null) { - await this.pushChangePasswordToQueue(id, loginDomain, changeData.newPassword, sender.tab); + await this.pushChangePasswordToQueue(id, loginDomain, changeData.newPassword, tab); return true; } return false; @@ -1030,18 +1107,23 @@ export default class NotificationBackground { private async getCollectionData( message: NotificationBackgroundExtensionMessage, ): Promise { - const collections = (await this.collectionService.getAllDecrypted()).reduce( - (acc, collection) => { - if (collection.organizationId === message?.orgId) { - acc.push({ - id: collection.id, - name: collection.name, - organizationId: collection.organizationId, - }); - } - return acc; - }, - [], + const collections = await firstValueFrom( + this.accountService.activeAccount$.pipe( + getUserId, + switchMap((userId) => this.collectionService.decryptedCollections$(userId)), + map((collections) => + collections.reduce((acc, collection) => { + if (collection.organizationId === message?.orgId) { + acc.push({ + id: collection.id, + name: collection.name, + organizationId: collection.organizationId, + }); + } + return acc; + }, []), + ), + ), ); return collections; } diff --git a/apps/browser/src/autofill/background/overlay-notifications.background.ts b/apps/browser/src/autofill/background/overlay-notifications.background.ts index 93357113fc4..1d7f2b1f9d8 100644 --- a/apps/browser/src/autofill/background/overlay-notifications.background.ts +++ b/apps/browser/src/autofill/background/overlay-notifications.background.ts @@ -1,17 +1,15 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { firstValueFrom, Subject, switchMap, timer } from "rxjs"; +import { Subject, switchMap, timer } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { getOptionalUserId } from "@bitwarden/common/auth/services/account.service"; import { CLEAR_NOTIFICATION_LOGIN_DATA_DURATION } from "@bitwarden/common/autofill/constants"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; -import { SecurityTask, SecurityTaskStatus, TaskService } from "@bitwarden/common/vault/tasks"; +import { TaskService } from "@bitwarden/common/vault/tasks"; import { BrowserApi } from "../../platform/browser/browser-api"; +import { NotificationType, NotificationTypes } from "../notification/abstractions/notification-bar"; import { generateDomainMatchPatterns, isInvalidResponseStatusCode } from "../utils"; import { @@ -25,12 +23,6 @@ import { } from "./abstractions/overlay-notifications.background"; import NotificationBackground from "./notification.background"; -type LoginSecurityTaskInfo = { - securityTask: SecurityTask; - cipher: CipherView; - uri: ModifyLoginCipherFormData["uri"]; -}; - export class OverlayNotificationsBackground implements OverlayNotificationsBackgroundInterface { private websiteOriginsWithFields: WebsiteOriginsWithFields = new Map(); private activeFormSubmissionRequests: ActiveFormSubmissionRequests = new Set(); @@ -274,8 +266,8 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg const modifyLoginData = this.modifyLoginCipherFormData.get(tabId); return ( !modifyLoginData || - !this.shouldAttemptAddLoginNotification(modifyLoginData) || - !this.shouldAttemptChangedPasswordNotification(modifyLoginData) + !this.shouldAttemptNotification(modifyLoginData, NotificationTypes.Add) || + !this.shouldAttemptNotification(modifyLoginData, NotificationTypes.Change) ); }; @@ -381,7 +373,7 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg return; } - await this.triggerNotificationInit(requestId, modifyLoginData, tab); + await this.processNotifications(requestId, modifyLoginData, tab); }; /** @@ -401,171 +393,86 @@ export class OverlayNotificationsBackground implements OverlayNotificationsBackg const handleWebNavigationOnCompleted = async () => { chrome.webNavigation.onCompleted.removeListener(handleWebNavigationOnCompleted); const tab = await BrowserApi.getTab(tabId); - await this.triggerNotificationInit(requestId, modifyLoginData, tab); + await this.processNotifications(requestId, modifyLoginData, tab); }; chrome.webNavigation.onCompleted.addListener(handleWebNavigationOnCompleted); }; /** - * Initializes the add login or change password notification based on the modified login form data - * and the tab details. This will trigger the notification to be displayed to the user. + * This method attempts to trigger the add login, change password, or at-risk password notifications + * based on the modified login data and the tab details. * * @param requestId - The details of the web response * @param modifyLoginData - The modified login form data * @param tab - The tab details */ - private triggerNotificationInit = async ( + private processNotifications = async ( requestId: chrome.webRequest.ResourceRequest["requestId"], modifyLoginData: ModifyLoginCipherFormData, tab: chrome.tabs.Tab, + config: { skippable: NotificationType[] } = { skippable: [] }, ) => { - let result: string; - if (this.shouldAttemptChangedPasswordNotification(modifyLoginData)) { - // These notifications are temporarily setup as "messages" to the notification background. - // This will be structured differently in a future refactor. - const success = await this.notificationBackground.triggerChangedPasswordNotification( - { - command: "bgChangedPassword", - data: { - url: modifyLoginData.uri, - currentPassword: modifyLoginData.password, - newPassword: modifyLoginData.newPassword, - }, - }, - { tab }, - ); - if (!success) { - result = "Unqualified changedPassword notification attempt."; - } - } - - if (this.shouldAttemptAddLoginNotification(modifyLoginData)) { - const success = await this.notificationBackground.triggerAddLoginNotification( - { - command: "bgTriggerAddLoginNotification", - login: { - url: modifyLoginData.uri, - username: modifyLoginData.username, - password: modifyLoginData.password || modifyLoginData.newPassword, - }, - }, - { tab }, - ); - if (!success) { - result = "Unqualified addLogin notification attempt."; - } - } - - const shouldGetTasks = - (await this.notificationBackground.getNotificationFlag()) && !modifyLoginData.newPassword; - - if (shouldGetTasks) { - const activeUserId = await firstValueFrom( - this.accountService.activeAccount$.pipe(getOptionalUserId), - ); - - if (activeUserId) { - const loginSecurityTaskInfo = await this.getSecurityTaskAndCipherForLoginData( - modifyLoginData, - activeUserId, - ); - - if (loginSecurityTaskInfo) { - await this.notificationBackground.triggerAtRiskPasswordNotification( - { - command: "bgTriggerAtRiskPasswordNotification", - data: { - activeUserId, - cipher: loginSecurityTaskInfo.cipher, - securityTask: loginSecurityTaskInfo.securityTask, - }, - }, - { tab }, - ); - } else { - result = "Unqualified atRiskPassword notification attempt."; - } - } - } - this.clearCompletedWebRequest(requestId, tab); - return result; - }; - - /** - * Determines if the change password notification should be triggered. - * - * @param modifyLoginData - The modified login form data - */ - private shouldAttemptChangedPasswordNotification = ( - modifyLoginData: ModifyLoginCipherFormData, - ) => { - return modifyLoginData?.newPassword && !modifyLoginData.username; - }; - - /** - * Determines if the add login notification should be triggered. - * - * @param modifyLoginData - The modified login form data - */ - private shouldAttemptAddLoginNotification = (modifyLoginData: ModifyLoginCipherFormData) => { - return modifyLoginData?.username && (modifyLoginData.password || modifyLoginData.newPassword); - }; - - /** - * If there is a security task for this cipher at login, return the task, cipher view, and uri. - * - * @param modifyLoginData - The modified login form data - * @param activeUserId - The currently logged in user ID - */ - private async getSecurityTaskAndCipherForLoginData( - modifyLoginData: ModifyLoginCipherFormData, - activeUserId: UserId, - ): Promise { - const tasks: SecurityTask[] = await this.notificationBackground.getSecurityTasks(activeUserId); - if (!tasks?.length) { - return null; - } - - const urlCiphers: CipherView[] = await this.cipherService.getAllDecryptedForUrl( - modifyLoginData.uri, - activeUserId, - ); - if (!urlCiphers?.length) { - return null; - } - - const securityTaskForLogin = urlCiphers.reduce( - (taskInfo: LoginSecurityTaskInfo | null, cipher: CipherView) => { - if ( - // exit early if info was found already - taskInfo || - // exit early if the cipher was deleted - cipher.deletedDate || - // exit early if the entered login info doesn't match an existing cipher - modifyLoginData.username !== cipher.login.username || - modifyLoginData.password !== cipher.login.password - ) { - return taskInfo; - } - - // Find the first security task for the cipherId belonging to the entered login - const cipherSecurityTask = tasks.find( - ({ cipherId, status }) => - cipher.id === cipherId && // match security task cipher id to url cipher id - status === SecurityTaskStatus.Pending, // security task has not been completed - ); - - if (cipherSecurityTask) { - return { securityTask: cipherSecurityTask, cipher, uri: modifyLoginData.uri }; - } - - return taskInfo; + const notificationCandidates = [ + { + type: NotificationTypes.Change, + trigger: this.notificationBackground.triggerChangedPasswordNotification, }, - null, + { + type: NotificationTypes.Add, + trigger: this.notificationBackground.triggerAddLoginNotification, + }, + { + type: NotificationTypes.AtRiskPassword, + trigger: this.notificationBackground.triggerAtRiskPasswordNotification, + }, + ].filter( + (candidate) => + this.shouldAttemptNotification(modifyLoginData, candidate.type) || + config.skippable.includes(candidate.type), ); - return securityTaskForLogin; - } + const results: string[] = []; + for (const { trigger, type } of notificationCandidates) { + const success = await trigger.bind(this.notificationBackground)(modifyLoginData, tab); + if (success) { + results.push(`Success: ${type}`); + break; + } else { + results.push(`Unqualified ${type} notification attempt.`); + } + } + + this.clearCompletedWebRequest(requestId, tab); + return results.join(" "); + }; + + /** + * Determines if the add login notification should be attempted based on the modified login form data. + * @param modifyLoginData modified login form data + * @param notificationType The type of notification to be triggered + * @returns true if the notification should be attempted, false otherwise + */ + private shouldAttemptNotification = ( + modifyLoginData: ModifyLoginCipherFormData, + notificationType: NotificationType, + ): boolean => { + switch (notificationType) { + case NotificationTypes.Change: + return modifyLoginData?.newPassword && !modifyLoginData.username; + case NotificationTypes.Add: + return ( + modifyLoginData?.username && !!(modifyLoginData.password || modifyLoginData.newPassword) + ); + case NotificationTypes.AtRiskPassword: + return !modifyLoginData.newPassword; + case NotificationTypes.Unlock: + // Unlock notifications are handled separately and do not require form data + return false; + default: + this.logService.error(`Unknown notification type: ${notificationType}`); + return false; + } + }; /** * Clears the completed web request and removes the modified login form data for the tab. diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index 1f249454393..f55b5c8cc3d 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -191,6 +191,7 @@ export class OverlayBackground implements OverlayBackgroundInterface { editedCipher: () => this.updateOverlayCiphers(), deletedCipher: () => this.updateOverlayCiphers(), bgSaveCipher: () => this.updateOverlayCiphers(), + updateOverlayCiphers: () => this.updateOverlayCiphers(), fido2AbortRequest: ({ sender }) => this.abortFido2ActiveRequest(sender.tab.id), }; private readonly inlineMenuButtonPortMessageHandlers: InlineMenuButtonPortMessageHandlers = { diff --git a/apps/browser/src/autofill/background/tabs.background.ts b/apps/browser/src/autofill/background/tabs.background.ts index 4d520680980..cd2c1595d69 100644 --- a/apps/browser/src/autofill/background/tabs.background.ts +++ b/apps/browser/src/autofill/background/tabs.background.ts @@ -20,10 +20,8 @@ export default class TabsBackground { return; } - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.updateCurrentTabData(); - this.setupTabEventListeners(); + void this.updateCurrentTabData(); + void this.setupTabEventListeners(); } /** diff --git a/apps/browser/src/autofill/content/autofill-init.ts b/apps/browser/src/autofill/content/autofill-init.ts index 8f69937ac60..b6fc6c3392e 100644 --- a/apps/browser/src/autofill/content/autofill-init.ts +++ b/apps/browser/src/autofill/content/autofill-init.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { EVENTS } from "@bitwarden/common/autofill/constants"; import AutofillPageDetails from "../models/autofill-page-details"; @@ -122,7 +120,7 @@ class AutofillInit implements AutofillInitInterface { * @param {AutofillExtensionMessage} message */ private async fillForm({ fillScript, pageDetailsUrl }: AutofillExtensionMessage) { - if ((document.defaultView || window).location.href !== pageDetailsUrl) { + if ((document.defaultView || window).location.href !== pageDetailsUrl || !fillScript) { return; } @@ -177,7 +175,7 @@ class AutofillInit implements AutofillInitInterface { message: AutofillExtensionMessage, sender: chrome.runtime.MessageSender, sendResponse: (response?: any) => void, - ): boolean => { + ): boolean | null => { const command: string = message.command; const handler: CallableFunction | undefined = this.getExtensionMessageHandler(command); if (!handler) { diff --git a/apps/browser/src/autofill/content/autofiller.ts b/apps/browser/src/autofill/content/autofiller.ts index c7a742f1fe1..bc9fd0bb05f 100644 --- a/apps/browser/src/autofill/content/autofiller.ts +++ b/apps/browser/src/autofill/content/autofiller.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { setupExtensionDisconnectAction } from "../utils"; if (document.readyState === "loading") { @@ -9,7 +7,7 @@ if (document.readyState === "loading") { } function loadAutofiller() { - let pageHref: string = null; + let pageHref: null | string = null; let filledThisHref = false; let delayFillTimeout: number; let doFillInterval: number | NodeJS.Timeout; @@ -51,9 +49,7 @@ function loadAutofiller() { sender: "autofiller", }; - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - chrome.runtime.sendMessage(msg); + void chrome.runtime.sendMessage(msg); } } diff --git a/apps/browser/src/autofill/content/bootstrap-autofill-overlay-menu.ts b/apps/browser/src/autofill/content/bootstrap-autofill-overlay-menu.ts index 605ffff0fec..40e32843fd4 100644 --- a/apps/browser/src/autofill/content/bootstrap-autofill-overlay-menu.ts +++ b/apps/browser/src/autofill/content/bootstrap-autofill-overlay-menu.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { AutofillInlineMenuContentService } from "../overlay/inline-menu/content/autofill-inline-menu-content.service"; import { AutofillOverlayContentService } from "../services/autofill-overlay-content.service"; import DomElementVisibilityService from "../services/dom-element-visibility.service"; @@ -11,7 +9,7 @@ import AutofillInit from "./autofill-init"; (function (windowContext) { if (!windowContext.bitwardenAutofillInit) { - let inlineMenuContentService: AutofillInlineMenuContentService; + let inlineMenuContentService: undefined | AutofillInlineMenuContentService; if (globalThis.self === globalThis.top) { inlineMenuContentService = new AutofillInlineMenuContentService(); } diff --git a/apps/browser/src/autofill/content/bootstrap-autofill-overlay-notifications.ts b/apps/browser/src/autofill/content/bootstrap-autofill-overlay-notifications.ts index 495ae0e22db..8a079fa26c8 100644 --- a/apps/browser/src/autofill/content/bootstrap-autofill-overlay-notifications.ts +++ b/apps/browser/src/autofill/content/bootstrap-autofill-overlay-notifications.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { OverlayNotificationsContentService } from "../overlay/notifications/content/overlay-notifications-content.service"; import { AutofillOverlayContentService } from "../services/autofill-overlay-content.service"; import DomElementVisibilityService from "../services/dom-element-visibility.service"; @@ -20,7 +18,7 @@ import AutofillInit from "./autofill-init"; inlineMenuFieldQualificationService, ); - let overlayNotificationsContentService: OverlayNotificationsContentService; + let overlayNotificationsContentService: undefined | OverlayNotificationsContentService; if (globalThis.self === globalThis.top) { overlayNotificationsContentService = new OverlayNotificationsContentService(); } @@ -29,7 +27,7 @@ import AutofillInit from "./autofill-init"; domQueryService, domElementVisibilityService, autofillOverlayContentService, - null, + undefined, overlayNotificationsContentService, ); setupAutofillInitDisconnectAction(windowContext); diff --git a/apps/browser/src/autofill/content/bootstrap-autofill-overlay.ts b/apps/browser/src/autofill/content/bootstrap-autofill-overlay.ts index 1777b135fe9..d204362ee25 100644 --- a/apps/browser/src/autofill/content/bootstrap-autofill-overlay.ts +++ b/apps/browser/src/autofill/content/bootstrap-autofill-overlay.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { AutofillInlineMenuContentService } from "../overlay/inline-menu/content/autofill-inline-menu-content.service"; import { OverlayNotificationsContentService } from "../overlay/notifications/content/overlay-notifications-content.service"; import { AutofillOverlayContentService } from "../services/autofill-overlay-content.service"; @@ -12,8 +10,8 @@ import AutofillInit from "./autofill-init"; (function (windowContext) { if (!windowContext.bitwardenAutofillInit) { - let inlineMenuContentService: AutofillInlineMenuContentService; - let overlayNotificationsContentService: OverlayNotificationsContentService; + let inlineMenuContentService: undefined | AutofillInlineMenuContentService; + let overlayNotificationsContentService: undefined | OverlayNotificationsContentService; if (globalThis.self === globalThis.top) { inlineMenuContentService = new AutofillInlineMenuContentService(); overlayNotificationsContentService = new OverlayNotificationsContentService(); diff --git a/apps/browser/src/autofill/content/components/.lit-storybook/main.ts b/apps/browser/src/autofill/content/components/.lit-storybook/main.ts index a316d8f5baa..53c06264672 100644 --- a/apps/browser/src/autofill/content/components/.lit-storybook/main.ts +++ b/apps/browser/src/autofill/content/components/.lit-storybook/main.ts @@ -1,9 +1,16 @@ -import path, { dirname, join } from "path"; +import { createRequire } from "module"; +import { dirname, join, resolve } from "path"; +import { fileURLToPath } from "url"; import type { StorybookConfig } from "@storybook/web-components-webpack5"; import remarkGfm from "remark-gfm"; import TsconfigPathsPlugin from "tsconfig-paths-webpack-plugin"; +const currentFile = fileURLToPath(import.meta.url); +const currentDirectory = dirname(currentFile); + +const require = createRequire(import.meta.url); + const getAbsolutePath = (value: string): string => dirname(require.resolve(join(value, "package.json"))); @@ -43,7 +50,7 @@ const config: StorybookConfig = { if (config.resolve) { config.resolve.plugins = [ new TsconfigPathsPlugin({ - configFile: path.resolve(__dirname, "../../../../../tsconfig.json"), + configFile: resolve(currentDirectory, "../../../../../tsconfig.json"), }), ] as any; } diff --git a/apps/browser/src/autofill/content/components/buttons/action-button.ts b/apps/browser/src/autofill/content/components/buttons/action-button.ts index 339b628875c..b43bed7f96b 100644 --- a/apps/browser/src/autofill/content/components/buttons/action-button.ts +++ b/apps/browser/src/autofill/content/components/buttons/action-button.ts @@ -8,6 +8,7 @@ import { Spinner } from "../icons"; export type ActionButtonProps = { buttonText: string | TemplateResult; + dataTestId?: string; disabled?: boolean; isLoading?: boolean; theme: Theme; @@ -17,6 +18,7 @@ export type ActionButtonProps = { export function ActionButton({ buttonText, + dataTestId, disabled = false, isLoading = false, theme, @@ -32,6 +34,7 @@ export function ActionButton({ return html` `, @@ -557,7 +557,10 @@ export const CenteredContent: Story = { -
+
+

Page with no content

Before centering a div One must first center oneself @@ -651,7 +654,7 @@ export const WithVirtualScrollChild: Story = { @defer (on immediate) { - +