diff --git a/.eslintrc.json b/.eslintrc.json index 8bbf78df51c..39f292e5306 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -98,6 +98,10 @@ { "target": "./libs/common/**/*", "from": "./libs/node/**/*" + }, + { + "target": "./libs/common/**/*", + "from": "./libs/importer/**/*" } ] } @@ -150,6 +154,12 @@ "rules": { "no-restricted-imports": ["error", { "patterns": ["@bitwarden/node/*", "src/**/*"] }] } + }, + { + "files": ["libs/importer/src/**/*.ts"], + "rules": { + "no-restricted-imports": ["error", { "patterns": ["@bitwarden/importer/*", "src/**/*"] }] + } } ] } diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 88e5f29d9b5..86b58baa2af 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,7 +7,7 @@ # @bitwarden/team-leads ## Secrets Manager team files ## -bitwarden_license/bit-web/src/app/secrets-manager @bitwarden/pod-sm-dev +bitwarden_license/bit-web/src/app/secrets-manager @bitwarden/team-secrets-manager-dev ## Auth team files ## apps/browser/src/auth @bitwarden/team-auth-dev @@ -19,10 +19,34 @@ apps/web/src/connectors @bitwarden/team-auth-dev libs/angular/src/auth @bitwarden/team-auth-dev libs/common/src/auth @bitwarden/team-auth-dev +## Tools team files ## +apps/browser/src/app/tools @bitwarden/team-tools-dev +apps/cli/src/app/tools @bitwarden/team-tools-dev +apps/desktop/src/app/tools @bitwarden/team-tools-dev +apps/web/src/app/tools @bitwarden/team-tools-dev +libs/angular/src/tools @bitwarden/team-tools-dev +libs/common/src/tools @bitwarden/team-tools-dev +libs/importer @bitwarden/team-tools-dev + ## Vault team files ## +apps/browser/src/autofill @bitwarden/team-vault-dev apps/browser/src/vault @bitwarden/team-vault-dev apps/cli/src/vault @bitwarden/team-vault-dev apps/desktop/src/vault @bitwarden/team-vault-dev -apps/web/src/vault @bitwarden/team-vault-dev +apps/web/src/app/vault @bitwarden/team-vault-dev libs/angular/src/vault @bitwarden/team-vault-dev libs/common/src/vault @bitwarden/team-vault-dev + +## Admin Console team files ## +apps/browser/src/admin-console @bitwarden/team-admin-console-dev +apps/cli/src/admin-console @bitwarden/team-admin-console-dev +apps/desktop/src/admin-console @bitwarden/team-admin-console-dev +apps/web/src/app/admin-console @bitwarden/team-admin-console-dev +bitwarden_license/bit-web/src/app/admin-console @bitwarden/team-admin-console-dev +libs/angular/src/admin-console @bitwarden/team-admin-console-dev +libs/common/src/admin-console @bitwarden/team-admin-console-dev + +## Billing team files ## +apps/web/src/app/billing @bitwarden/team-billing-dev +libs/angular/src/billing @bitwarden/team-billing-dev +libs/common/src/billing @bitwarden/team-billing-dev \ No newline at end of file diff --git a/.github/DISCUSSION_TEMPLATE/password-manager.yml b/.github/DISCUSSION_TEMPLATE/password-manager.yml new file mode 100644 index 00000000000..bf2d0900db9 --- /dev/null +++ b/.github/DISCUSSION_TEMPLATE/password-manager.yml @@ -0,0 +1,11 @@ +body: + - type: markdown + attributes: + value: | + If you would like to contribute code to the Bitwarden codebase for consideration, please review [https://contributing.bitwarden.com/](https://contributing.bitwarden.com/) before posting. To keep discussion on topic, posts that do not include a proposal for a code contribution you wish to develop will be removed. For feature requests and community discussion, please visit https://community.bitwarden.com/ + - type: textarea + attributes: + label: Code Contribution Proposal + description: "Please include a description of the code contribution you would like to contribute, including any relevant screenshots, and links to any existing [feature requests](https://community.bitwarden.com/c/feature-requests/5/none). This helps get feedback from the community and Bitwarden team members before you start writing code" + validations: + required: true diff --git a/.github/DISCUSSION_TEMPLATE/secrets-manager.yml b/.github/DISCUSSION_TEMPLATE/secrets-manager.yml new file mode 100644 index 00000000000..bf2d0900db9 --- /dev/null +++ b/.github/DISCUSSION_TEMPLATE/secrets-manager.yml @@ -0,0 +1,11 @@ +body: + - type: markdown + attributes: + value: | + If you would like to contribute code to the Bitwarden codebase for consideration, please review [https://contributing.bitwarden.com/](https://contributing.bitwarden.com/) before posting. To keep discussion on topic, posts that do not include a proposal for a code contribution you wish to develop will be removed. For feature requests and community discussion, please visit https://community.bitwarden.com/ + - type: textarea + attributes: + label: Code Contribution Proposal + description: "Please include a description of the code contribution you would like to contribute, including any relevant screenshots, and links to any existing [feature requests](https://community.bitwarden.com/c/feature-requests/5/none). This helps get feedback from the community and Bitwarden team members before you start writing code" + validations: + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index fdd6b70a9a1..a2ff0baf25f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -30,3 +30,4 @@ - Please add **unit tests** where it makes sense to do so (encouraged but not required) - If this change requires a **documentation update** - notify the documentation team - If this change has particular **deployment requirements** - notify the DevOps team +- Ensure that all UI additions follow [WCAG AA requirements](https://contributing.bitwarden.com/contributing/accessibility/) diff --git a/.github/renovate.json b/.github/renovate.json index dae887b3d02..485205a0d96 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -24,5 +24,5 @@ "updateTypes": "patch" } ], - "ignoreDeps": ["bootstrap", "electron-builder", "node-ipc", "regedit"] + "ignoreDeps": ["bootstrap", "electron-builder", "electron", "node-ipc", "regedit", "zone.js"] } diff --git a/.github/secrets/appstore-app-cert.p12.gpg b/.github/secrets/appstore-app-cert.p12.gpg index ef81792f3d3..284add80d50 100644 Binary files a/.github/secrets/appstore-app-cert.p12.gpg and b/.github/secrets/appstore-app-cert.p12.gpg differ diff --git a/.github/secrets/appstore-installer-cert.p12.gpg b/.github/secrets/appstore-installer-cert.p12.gpg index 09652a3a1ba..cd1f58eca16 100644 Binary files a/.github/secrets/appstore-installer-cert.p12.gpg and b/.github/secrets/appstore-installer-cert.p12.gpg differ diff --git a/.github/secrets/bitwarden-desktop-key.p12.gpg b/.github/secrets/bitwarden-desktop-key.p12.gpg index 84c7f00e2d3..76ee0cbb5e4 100644 Binary files a/.github/secrets/bitwarden-desktop-key.p12.gpg and b/.github/secrets/bitwarden-desktop-key.p12.gpg differ diff --git a/.github/secrets/bitwarden_desktop_appstore.provisionprofile.gpg b/.github/secrets/bitwarden_desktop_appstore.provisionprofile.gpg index 32e2f79f2c2..d55f4055170 100644 Binary files a/.github/secrets/bitwarden_desktop_appstore.provisionprofile.gpg and b/.github/secrets/bitwarden_desktop_appstore.provisionprofile.gpg differ diff --git a/.github/secrets/macdev-cert.p12.gpg b/.github/secrets/macdev-cert.p12.gpg index 4b8e0ef474b..f89cfb82a11 100644 Binary files a/.github/secrets/macdev-cert.p12.gpg and b/.github/secrets/macdev-cert.p12.gpg differ diff --git a/.github/whitelist-capital-letters.txt b/.github/whitelist-capital-letters.txt index db8e006640d..26558ff99da 100644 --- a/.github/whitelist-capital-letters.txt +++ b/.github/whitelist-capital-letters.txt @@ -9,7 +9,6 @@ ./libs/common/src/abstractions/vaultTimeout ./libs/common/src/services/vaultTimeout ./bitwarden_license/README.md -./bitwarden_license/bit-web/src/app/providers/services/webProvider.service.ts ./libs/angular/src/directives/cipherListVirtualScroll.directive.ts ./libs/angular/src/scss/webfonts/Open_Sans-italic-700.woff ./libs/angular/src/scss/webfonts/Open_Sans-normal-300.woff @@ -31,9 +30,6 @@ ./libs/common/spec/models/domain/encString.spec.ts ./libs/common/spec/models/domain/symmetricCryptoKey.spec.ts ./libs/common/spec/models/domain/encArrayBuffer.spec.ts -./libs/common/spec/models/domain/sendAccess.spec.ts -./libs/common/spec/models/domain/sendFile.spec.ts -./libs/common/spec/models/domain/sendText.spec.ts ./libs/common/spec/matchers/toEqualBuffer.spec.ts ./libs/common/spec/matchers/toEqualBuffer.ts ./libs/common/spec/services/stateMigration.service.spec.ts @@ -47,35 +43,22 @@ ./libs/common/src/enums/clientType.ts ./libs/common/src/enums/encryptedExportType.ts ./libs/common/src/enums/linkedIdType.ts -./libs/common/src/enums/sendType.ts -./libs/common/src/enums/importOptions.ts -./libs/common/src/enums/policyType.ts -./libs/common/src/enums/planSponsorshipType.ts ./libs/common/src/enums/encryptionType.ts ./libs/common/src/enums/htmlStorageLocation.ts -./libs/common/src/enums/providerUserType.ts -./libs/common/src/enums/organizationUserStatusType.ts ./libs/common/src/enums/notificationType.ts ./libs/common/src/enums/keySuffixOptions.ts ./libs/common/src/enums/productType.ts -./libs/common/src/enums/scimProviderType.ts ./libs/common/src/enums/eventType.ts ./libs/common/src/enums/hashPurpose.ts ./libs/common/src/enums/uriMatchType.ts ./libs/common/src/enums/deviceType.ts -./libs/common/src/enums/organizationConnectionType.ts ./libs/common/src/enums/secureNoteType.ts -./libs/common/src/enums/transactionType.ts -./libs/common/src/enums/providerUserStatusType.ts ./libs/common/src/enums/storageLocation.ts ./libs/common/src/enums/themeType.ts ./libs/common/src/enums/logLevelType.ts -./libs/common/src/enums/planType.ts ./libs/common/src/enums/stateVersion.ts ./libs/common/src/enums/fieldType.ts -./libs/common/src/enums/paymentMethodType.ts ./libs/common/src/enums/nativeMessagingVersion.ts -./libs/common/src/enums/organizationUserType.ts ./libs/common/src/factories/accountFactory.ts ./libs/common/src/factories/globalStateFactory.ts ./libs/common/src/factories/stateFactory.ts @@ -86,26 +69,20 @@ ./libs/common/src/abstractions/fileDownload/fileDownloadBuilder.ts ./libs/common/src/abstractions/fileDownload/fileDownload.service.ts ./libs/common/src/abstractions/fileDownload/fileDownloadRequest.ts -./libs/common/src/abstractions/passwordGeneration.service.ts ./libs/common/src/abstractions/formValidationErrors.service.ts ./libs/common/src/abstractions/vaultTimeout/vaultTimeoutSettings.service.ts ./libs/common/src/abstractions/vaultTimeout/vaultTimeout.service.ts -./libs/common/src/abstractions/fileUpload.service.ts ./libs/common/src/abstractions/cryptoFunction.service.ts ./libs/common/src/abstractions/anonymousHub.service.ts ./libs/common/src/abstractions/appId.service.ts -./libs/common/src/abstractions/usernameGeneration.service.ts ./libs/common/src/services/azureFileUpload.service.ts ./libs/common/src/services/stateMigration.service.ts -./libs/common/src/services/passwordGeneration.service.ts ./libs/common/src/services/consoleLog.service.ts ./libs/common/src/services/formValidationErrors.service.ts ./libs/common/src/services/vaultTimeout/vaultTimeoutSettings.service.ts ./libs/common/src/services/vaultTimeout/vaultTimeout.service.ts -./libs/common/src/services/fileUpload.service.ts ./libs/common/src/services/anonymousHub.service.ts ./libs/common/src/services/appId.service.ts -./libs/common/src/services/usernameGeneration.service.ts ./libs/common/src/services/noopMessaging.service.ts ./libs/common/src/services/memoryStorage.service.ts ./libs/common/src/services/bitwardenFileUpload.service.ts @@ -168,7 +145,6 @@ ./apps/browser/src/services/vaultTimeout/vaultTimeout.service.ts ./apps/browser/src/services/browserCrypto.service.ts ./apps/browser/src/services/browserPlatformUtils.service.ts -./apps/browser/src/services/autofillConstants.ts ./apps/browser/src/services/abstractions/abstractKeyGeneration.service.ts ./apps/browser/src/services/browserLocalStorage.service.ts ./apps/browser/src/services/localBackedSessionStorage.service.ts diff --git a/.github/workflows/build-browser.yml b/.github/workflows/build-browser.yml index e54dc936eb4..18e7f752bd9 100644 --- a/.github/workflows/build-browser.yml +++ b/.github/workflows/build-browser.yml @@ -10,6 +10,7 @@ on: - 'apps/browser/**' - 'libs/**' - '*' + - '!libs/importer' - '!*.md' - '!*.txt' push: @@ -21,6 +22,7 @@ on: - 'apps/browser/**' - 'libs/**' - '*' + - '!libs/importer' - '!*.md' - '!*.txt' - '.github/workflows/build-browser.yml' diff --git a/.github/workflows/build-cli.yml b/.github/workflows/build-cli.yml index 44b77afe36d..e319be23e23 100644 --- a/.github/workflows/build-cli.yml +++ b/.github/workflows/build-cli.yml @@ -66,10 +66,10 @@ jobs: cli: - name: Build CLI + name: Build CLI ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, windows-2019, macos-11] + os: [ubuntu-20.04, macos-11] runs-on: ${{ matrix.os }} needs: - setup @@ -82,14 +82,80 @@ jobs: uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 - name: Setup Unix Vars - if: runner.os != 'Windows' run: | echo "LOWER_RUNNER_OS=$(echo $RUNNER_OS | awk '{print tolower($0)}')" >> $GITHUB_ENV echo "SHORT_RUNNER_OS=$(echo $RUNNER_OS | awk '{print substr($0, 1, 3)}' | \ awk '{print tolower($0)}')" >> $GITHUB_ENV + - name: Set up Node + uses: actions/setup-node@17f8bd926464a1afa4c6a11669539e9c1ba77048 # v3.2.0 + with: + cache: 'npm' + cache-dependency-path: '**/package-lock.json' + node-version: '16' + + - name: Install node-gyp + run: | + npm install -g node-gyp + node-gyp install $(node -v) + + - name: Install + run: npm ci + working-directory: ./ + + - name: Build & Package Unix + run: npm run dist:${{ env.SHORT_RUNNER_OS }} --quiet + + - name: Zip Unix + run: | + cd ./dist/${{ env.LOWER_RUNNER_OS }} + zip ../bw-${{ env.LOWER_RUNNER_OS }}-${{ env._PACKAGE_VERSION }}.zip ./bw + + - name: Version Test + run: | + unzip "./dist/bw-${{ env.LOWER_RUNNER_OS }}-${{ env._PACKAGE_VERSION }}.zip" -d "./test" + testVersion=$(./test/bw -v) + echo "version: $_PACKAGE_VERSION" + echo "testVersion: $testVersion" + if [[ $testVersion != $_PACKAGE_VERSION ]]; then + echo "Version test failed." + exit 1 + fi + + - name: Create checksums Unix + run: | + cd ./dist + shasum -a 256 bw-${{ env.LOWER_RUNNER_OS }}-${{ env._PACKAGE_VERSION }}.zip \ + | awk '{split($0, a); print a[1]}' > bw-${{ env.LOWER_RUNNER_OS }}-sha256-${{ env._PACKAGE_VERSION }}.txt + + - name: Upload unix zip asset + uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 + with: + name: bw-${{ env.LOWER_RUNNER_OS }}-${{ env._PACKAGE_VERSION }}.zip + path: apps/cli/dist/bw-${{ env.LOWER_RUNNER_OS }}-${{ env._PACKAGE_VERSION }}.zip + if-no-files-found: error + + - name: Upload unix checksum asset + uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 + with: + name: bw-${{ env.LOWER_RUNNER_OS }}-sha256-${{ env._PACKAGE_VERSION }}.txt + path: apps/cli/dist/bw-${{ env.LOWER_RUNNER_OS }}-sha256-${{ env._PACKAGE_VERSION }}.txt + if-no-files-found: error + + cli-windows: + name: Build CLI Windows + runs-on: windows-2019 + needs: + - setup + env: + _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }} + _WIN_PKG_FETCH_VERSION: 16.16.0 + _WIN_PKG_VERSION: 3.4 + steps: + - name: Checkout repo + uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 + - name: Setup Windows builder - if: runner.os == 'Windows' run: | choco install checksum --no-progress choco install reshack --no-progress @@ -109,7 +175,6 @@ jobs: - name: Get pkg-fetch shell: pwsh - if: runner.os == 'Windows' run: | cd $HOME $fetchedUrl = "https://github.com/vercel/pkg-fetch/releases/download/v$env:_WIN_PKG_VERSION/node-v$env:_WIN_PKG_FETCH_VERSION-win-x64" @@ -120,7 +185,6 @@ jobs: - name: Setup Version Info shell: pwsh - if: runner.os == 'Windows' run: | $major,$minor,$patch = $env:_PACKAGE_VERSION.split('.') $versionInfo = @" @@ -155,7 +219,6 @@ jobs: - name: Resource Hacker shell: cmd - if: runner.os == 'Windows' run: | set PATH=%PATH%;C:\Program Files (x86)\Resource Hacker set WIN_PKG=C:\Users\runneradmin\.pkg-cache\v%_WIN_PKG_VERSION%\fetched-v%_WIN_PKG_FETCH_VERSION%-win-x64 @@ -170,16 +233,10 @@ jobs: working-directory: ./ - name: Build & Package Windows - if: runner.os == 'Windows' run: npm run dist:win --quiet - - name: Build & Package Unix - if: runner.os != 'Windows' - run: npm run dist:${{ env.SHORT_RUNNER_OS }} --quiet - - name: Package Chocolatey shell: pwsh - if: runner.os == 'Windows' run: | Copy-Item -Path stores/chocolatey -Destination dist/chocolatey -Recurse Copy-Item dist/windows/bw.exe -Destination dist/chocolatey/tools @@ -188,17 +245,9 @@ jobs: - name: Zip Windows shell: cmd - if: runner.os == 'Windows' run: 7z a ./dist/bw-windows-%_PACKAGE_VERSION%.zip ./dist/windows/bw.exe - - name: Zip Unix - if: runner.os != 'Windows' - run: | - cd ./dist/${{ env.LOWER_RUNNER_OS }} - zip ../bw-${{ env.LOWER_RUNNER_OS }}-${{ env._PACKAGE_VERSION }}.zip ./bw - - name: Version Test - if: runner.os == 'Windows' run: | dir ./dist/ Expand-Archive -Path "./dist/bw-windows-${env:_PACKAGE_VERSION}.zip" -DestinationPath "./test/windows" @@ -210,20 +259,11 @@ jobs: } - name: Create checksums Windows - if: runner.os == 'Windows' run: | checksum -f="./dist/bw-windows-${env:_PACKAGE_VERSION}.zip" ` -t sha256 | Out-File -Encoding ASCII ./dist/bw-windows-sha256-${env:_PACKAGE_VERSION}.txt - - name: Create checksums Unix - if: runner.os != 'Windows' - run: | - cd ./dist - sha256sum bw-${{ env.LOWER_RUNNER_OS }}-${{ env._PACKAGE_VERSION }}.zip \ - | awk '{split($0, a); print a[1]}' > bw-${{ env.LOWER_RUNNER_OS }}-sha256-${{ env._PACKAGE_VERSION }}.txt - - name: Upload windows zip asset - if: runner.os == 'Windows' uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 with: name: bw-windows-${{ env._PACKAGE_VERSION }}.zip @@ -231,31 +271,13 @@ jobs: if-no-files-found: error - name: Upload windows checksum asset - if: runner.os == 'Windows' uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 with: name: bw-windows-sha256-${{ env._PACKAGE_VERSION }}.txt path: apps/cli/dist/bw-windows-sha256-${{ env._PACKAGE_VERSION }}.txt if-no-files-found: error - - name: Upload unix zip asset - if: runner.os != 'Windows' - uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 - with: - name: bw-${{ env.LOWER_RUNNER_OS }}-${{ env._PACKAGE_VERSION }}.zip - path: apps/cli/dist/bw-${{ env.LOWER_RUNNER_OS }}-${{ env._PACKAGE_VERSION }}.zip - if-no-files-found: error - - - name: Upload unix checksum asset - if: runner.os != 'Windows' - uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 - with: - name: bw-${{ env.LOWER_RUNNER_OS }}-sha256-${{ env._PACKAGE_VERSION }}.txt - path: apps/cli/dist/bw-${{ env.LOWER_RUNNER_OS }}-sha256-${{ env._PACKAGE_VERSION }}.txt - if-no-files-found: error - - name: Upload Chocolatey asset - if: runner.os == 'Windows' uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 with: name: bitwarden-cli.${{ env._PACKAGE_VERSION }}.nupkg @@ -263,7 +285,6 @@ jobs: if-no-files-found: error - name: Upload NPM Build Directory asset - if: runner.os == 'Windows' uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0 with: name: bitwarden-cli-${{ env._PACKAGE_VERSION }}-npm-build.zip @@ -352,6 +373,7 @@ jobs: - cloc - setup - cli + - cli-windows - snap steps: - name: Check if any job failed diff --git a/.github/workflows/build-desktop.yml b/.github/workflows/build-desktop.yml index f92ae8a71e4..586e0f6d6e3 100644 --- a/.github/workflows/build-desktop.yml +++ b/.github/workflows/build-desktop.yml @@ -10,6 +10,7 @@ on: - 'apps/desktop/**' - 'libs/**' - '*' + - '!libs/importer' - '!*.md' - '!*.txt' - '.github/workflows/build-desktop.yml' @@ -22,6 +23,7 @@ on: - 'apps/desktop/**' - 'libs/**' - '*' + - '!libs/importer' - '!*.md' - '!*.txt' - '.github/workflows/build-desktop.yml' diff --git a/.github/workflows/build-web.yml b/.github/workflows/build-web.yml index 798f748bd60..be59be4123e 100644 --- a/.github/workflows/build-web.yml +++ b/.github/workflows/build-web.yml @@ -80,7 +80,7 @@ jobs: npm_command: "dist:bit:selfhost" - name: "cloud-QA" npm_command: "build:bit:qa" - - name: "cloud-POC" + - name: "cloud-POC2" npm_command: "build:bit:poc" - name: "ee" npm_command: "build:bit:ee" @@ -132,101 +132,71 @@ jobs: path: apps/web/web-${{ env._VERSION }}-${{ matrix.name }}.zip if-no-files-found: error - build-commercial-selfhost-image: - name: Build self-host docker image + + build-containers: + name: Build Docker images runs-on: ubuntu-22.04 needs: - setup - build-artifacts + strategy: + fail-fast: false + matrix: + include: + - artifact_name: cloud-QA + registries: [bitwardenprod.azurecr.io, bitwardenqa.azurecr.io] + image_name: web-qa-cloud + - artifact_name: ee + registries: [bitwardenprod.azurecr.io, bitwardenqa.azurecr.io] + image_name: web-ee + - artifact_name: selfhosted-COMMERCIAL + registries: [bitwarden, bitwardenprod.azurecr.io, bitwardenqa.azurecr.io] + image_name: web env: _VERSION: ${{ needs.setup.outputs.version }} - steps: - name: Checkout repo uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 - - name: Setup DCT - if: github.ref == 'refs/heads/master' || - github.ref == 'refs/heads/rc' || - github.ref == 'refs/heads/hotfix-rc-web' - id: setup-dct - uses: bitwarden/gh-actions/setup-docker-trust@a8c384a05a974c05c48374c818b004be221d43ff - with: - azure-creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }} - azure-keyvault-name: "bitwarden-prod-kv" - - - name: Download selfhosted-COMMERCIAL artifact - uses: actions/download-artifact@fb598a63ae348fa914e94cd0ff38f362e927b741 - with: - name: web-${{ env._VERSION }}-selfhosted-COMMERCIAL.zip - path: apps/web - - - name: Extract artifact - working-directory: apps/web - run: unzip web-${{ env._VERSION }}-selfhosted-COMMERCIAL.zip - - - name: Build Docker image - working-directory: apps/web - run: docker build -t bitwarden/web . - - - name: Tag rc branch - if: github.ref == 'refs/heads/rc' - run: docker tag bitwarden/web bitwarden/web:rc - - - name: Tag dev - if: github.ref == 'refs/heads/master' - run: docker tag bitwarden/web bitwarden/web:dev - - - name: Tag hotfix branch - if: github.ref == 'refs/heads/hotfix-rc-web' - run: docker tag bitwarden/web bitwarden/web:hotfix-rc-web - - - name: List Docker images - if: github.ref == 'refs/heads/master' || - github.ref == 'refs/heads/rc' || - github.ref == 'refs/heads/hotfix-rc-web' - run: docker images - - - name: Push rc image - if: github.ref == 'refs/heads/rc' - run: docker push bitwarden/web:rc + - name: Check Branch to Publish env: - DOCKER_CONTENT_TRUST: 1 - DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }} - - - name: Push dev image - if: github.ref == 'refs/heads/master' - run: docker push bitwarden/web:dev - env: - DOCKER_CONTENT_TRUST: 1 - DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }} - - - name: Push hotfix image - if: github.ref == 'refs/heads/hotfix-rc-web' - run: docker push bitwarden/web:hotfix-rc-web - env: - DOCKER_CONTENT_TRUST: 1 - DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }} - - - name: Log out of Docker - if: github.ref == 'refs/heads/master' || - github.ref == 'refs/heads/rc' || - github.ref == 'refs/heads/hotfix-rc-web' + PUBLISH_BRANCHES: "master,rc,hotfix-rc" + id: publish-branch-check run: | - docker logout - echo "DOCKER_CONTENT_TRUST=0" >> $GITHUB_ENV + IFS="," read -a publish_branches <<< $PUBLISH_BRANCHES - - name: Login to Azure - QA Subscription + if [[ " ${publish_branches[*]} " =~ " ${GITHUB_REF:11} " ]]; then + echo "is_publish_branch=true" >> $GITHUB_ENV + else + echo "is_publish_branch=false" >> $GITHUB_ENV + fi + + ########## ACRs ########## + - name: Login to Azure - QA uses: Azure/login@ec3c14589bd3e9312b3cc8c41e6860e258df9010 # v1.1 with: creds: ${{ secrets.AZURE_QA_KV_CREDENTIALS }} - - name: Login to Azure ACR + - name: Log into QA container registry run: az acr login -n bitwardenqa - - name: Tag and Push to Azure QA ACR - env: - REGISTRY: bitwardenqa.azurecr.io + - name: Login to Azure - Prod + uses: Azure/login@ec3c14589bd3e9312b3cc8c41e6860e258df9010 # v1.1 + with: + creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }} + + - name: Log into Prod container registry + run: az acr login -n bitwardenprod + + - name: Download ${{ matrix.artifact_name }} artifact + uses: actions/download-artifact@fb598a63ae348fa914e94cd0ff38f362e927b741 + with: + name: web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip + path: apps/web + + ########## Generate image tag and build Docker image ########## + - name: Generate Docker image tag + id: tag run: | if [[ $(grep "pull" <<< "${GITHUB_REF}") ]]; then IMAGE_TAG=$(echo "${GITHUB_HEAD_REF}" | sed "s#/#-#g") @@ -238,102 +208,67 @@ jobs: IMAGE_TAG=dev fi - docker tag bitwarden/web \ - $REGISTRY/web-sh:$IMAGE_TAG - - docker push $REGISTRY/web-sh:$IMAGE_TAG - - - name: Log out of Docker - run: docker logout - - build-containers: - name: Build Docker images for bitwardenqa - runs-on: ubuntu-22.04 - needs: - - setup - - build-artifacts - strategy: - fail-fast: false - matrix: - include: - - artifact_name: cloud-QA - image_name: web - - artifact_name: ee - image_name: web-ee - env: - _VERSION: ${{ needs.setup.outputs.version }} - steps: - - name: Checkout repo - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 - - - name: Login to Azure - uses: Azure/login@ec3c14589bd3e9312b3cc8c41e6860e258df9010 # v1.1 - with: - creds: ${{ secrets.AZURE_QA_KV_CREDENTIALS }} - - - name: Log into container registry - run: az acr login -n bitwardenqa - - - name: Download ${{ matrix.artifact_name }} artifact - uses: actions/download-artifact@fb598a63ae348fa914e94cd0ff38f362e927b741 - with: - name: web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip - path: apps/web - - - name: Extract artifact - working-directory: apps/web - run: unzip web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip - - - name: Build Docker image - working-directory: apps/web - run: | - docker --version - docker build -t bitwardenqa.azurecr.io/${{ matrix.image_name }} . - - - name: Get image tag - id: image-tag - run: | - if [[ $(grep "pull" <<< "${GITHUB_REF}") ]]; then - IMAGE_TAG=$(echo "${GITHUB_HEAD_REF}" | sed "s#/#-#g") - else - IMAGE_TAG=$(echo "${GITHUB_REF:11}" | sed "s#/#-#g") - fi - TAG_EXTENSION=${{ github.event.inputs.custom_tag_extension }} if [[ $TAG_EXTENSION ]]; then IMAGE_TAG=$IMAGE_TAG-$TAG_EXTENSION fi - echo "value=$IMAGE_TAG" >> $GITHUB_OUTPUT + echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT - - name: Tag image + - name: Generate tag list + id: tag-list env: - IMAGE_TAG: ${{ steps.image-tag.outputs.value }} - IMAGE_NAME: ${{ matrix.image_name }} - run: docker tag bitwardenqa.azurecr.io/$IMAGE_NAME "bitwardenqa.azurecr.io/$IMAGE_NAME:$IMAGE_TAG" + IMAGE_TAG: ${{ steps.tag.outputs.image_tag }} + PROJECT_NAME: ${{ matrix.image_name }} + run: echo "tags=bitwardenqa.azurecr.io/${PROJECT_NAME}:${IMAGE_TAG},bitwardenprod.azurecr.io/${PROJECT_NAME}:${IMAGE_TAG}" >> $GITHUB_OUTPUT - - name: Tag dev - if: github.ref == 'refs/heads/master' - env: - IMAGE_NAME: ${{ matrix.image_name }} - run: docker tag bitwardenqa.azurecr.io/$IMAGE_NAME "bitwardenqa.azurecr.io/$IMAGE_NAME:dev" + ########## Build Image ########## + - name: Extract artifact + working-directory: apps/web + run: unzip web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip - - name: Push image - env: - IMAGE_TAG: ${{ steps.image-tag.outputs.value }} - IMAGE_NAME: ${{ matrix.image_name }} - run: docker push "bitwardenqa.azurecr.io/$IMAGE_NAME:$IMAGE_TAG" + - name: Retrieve github PAT secrets + id: retrieve-secret-pat + uses: bitwarden/gh-actions/get-keyvault-secrets@c3b3285993151c5af47cefcb3b9134c28ab479af + with: + keyvault: "bitwarden-prod-kv" + secrets: "github-pat-bitwarden-devops-bot-repo-scope" - - name: Push dev images - if: github.ref == 'refs/heads/master' + - name: Setup DCT + if: ${{ env.is_publish_branch == 'true' }} + id: setup-dct + uses: bitwarden/gh-actions/setup-docker-trust@a8c384a05a974c05c48374c818b004be221d43ff + with: + azure-creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }} + azure-keyvault-name: "bitwarden-prod-kv" + + - name: Build Docker image + uses: docker/build-push-action@c56af957549030174b10d6867f20e78cfd7debc5 + with: + context: apps/web + file: apps/web/Dockerfile + platforms: linux/amd64 + push: true + tags: ${{ steps.tag-list.outputs.tags }} + secrets: | + "GH_PAT=${{ steps.retrieve-secret-pat.outputs.github-pat-bitwarden-devops-bot-repo-scope }}" + + - name: Push to DockerHub + if: contains(matrix.registries, 'bitwarden') && env.is_publish_branch == 'true' env: - IMAGE_NAME: ${{ matrix.image_name }} - run: docker push "bitwardenqa.azurecr.io/$IMAGE_NAME:dev" + IMAGE_TAG: ${{ steps.tag.outputs.image_tag }} + PROJECT_NAME: ${{ matrix.image_name }} + DOCKER_CONTENT_TRUST: 1 + DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }} + run: | + docker tag bitwardenprod.azurecr.io/$PROJECT_NAME:$IMAGE_TAG bitwarden/$PROJECT_NAME:$IMAGE_TAG + docker push bitwarden/$PROJECT_NAME:$IMAGE_TAG - name: Log out of Docker run: docker logout + crowdin-push: name: Crowdin Push if: github.ref == 'refs/heads/master' @@ -377,7 +312,6 @@ jobs: - cloc - setup - build-artifacts - - build-commercial-selfhost-image - build-containers - crowdin-push steps: @@ -387,7 +321,6 @@ jobs: CLOC_STATUS: ${{ needs.cloc.result }} SETUP_STATUS: ${{ needs.setup.result }} ARTIFACT_STATUS: ${{ needs.build-artifacts.result }} - BUILD_SELFHOST_STATUS: ${{ needs.build-commercial-selfhost-image.result }} BUILD_CONTAINERS_STATUS: ${{ needs.build-containers.result }} CROWDIN_PUSH_STATUS: ${{ needs.crowdin-push.result }} run: | diff --git a/.github/workflows/deploy-non-prod-web.yml b/.github/workflows/deploy-non-prod-web.yml index cc9d7c8e5a0..f5ca49964de 100644 --- a/.github/workflows/deploy-non-prod-web.yml +++ b/.github/workflows/deploy-non-prod-web.yml @@ -12,7 +12,7 @@ on: type: choice options: - QA - - POC + - POC2 jobs: diff --git a/.github/workflows/label-issue-pull-request.yml b/.github/workflows/label-issue-pull-request.yml new file mode 100644 index 00000000000..9975bd6ef2e --- /dev/null +++ b/.github/workflows/label-issue-pull-request.yml @@ -0,0 +1,22 @@ +# Runs creation of Pull Requests +# If the PR destination branch is master, add a needs-qa label +--- +name: Label Issue Pull Request + +on: + pull_request: + types: [opened, edited] # Check when PR is opened or target branch is edited + paths-ignore: + - .github/workflows/** # We don't need QA on workflow changes + branches: + - 'master' # We only want to check when PRs target master + +jobs: + add-needs-qa-label: + runs-on: ubuntu-latest + steps: + - name: Add label to pull request + uses: andymckay/labeler@e6c4322d0397f3240f0e7e30a33b5c5df2d39e90 + if: ${{ !github.event.pull_request.head.repo.fork }} + with: + add-labels: "needs-qa" diff --git a/.github/workflows/release-web.yml b/.github/workflows/release-web.yml index 68727e774dd..cf9379a8201 100644 --- a/.github/workflows/release-web.yml +++ b/.github/workflows/release-web.yml @@ -104,17 +104,17 @@ jobs: echo "DOCKER_CONTENT_TRUST=0" >> $GITHUB_ENV ########## ACR ########## - - name: Login to Azure - QA Subscription + - name: Login to Azure - PROD Subscription uses: Azure/login@ec3c14589bd3e9312b3cc8c41e6860e258df9010 # v1.1 with: - creds: ${{ secrets.AZURE_QA_KV_CREDENTIALS }} + creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }} - name: Login to Azure ACR - run: az acr login -n bitwardenqa + run: az acr login -n bitwardenprod - name: Tag version env: - REGISTRY: bitwardenqa.azurecr.io + REGISTRY: bitwardenprod.azurecr.io run: | if [[ "${{ github.event.inputs.release_type }}" == "Dry Run" ]]; then docker tag bitwarden/web:latest $REGISTRY/web:$_RELEASE_VERSION @@ -129,7 +129,7 @@ jobs: - name: Push version if: ${{ github.event.inputs.release_type != 'Dry Run' }} env: - REGISTRY: bitwardenqa.azurecr.io + REGISTRY: bitwardenprod.azurecr.io run: | docker push $REGISTRY/web:$_RELEASE_VERSION diff --git a/.github/workflows/version-auto-bump.yml b/.github/workflows/version-auto-bump.yml index 5060156114b..88cb606a194 100644 --- a/.github/workflows/version-auto-bump.yml +++ b/.github/workflows/version-auto-bump.yml @@ -44,27 +44,10 @@ jobs: needs: - setup steps: - - name: Login to Azure - uses: Azure/login@ec3c14589bd3e9312b3cc8c41e6860e258df9010 + - name: Bump version to ${{ needs.setup.outputs.version_number }} + uses: ./.github/workflows/version-bump.yml + secrets: + AZURE_PROD_KV_CREDENTIALS: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }} with: - creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }} - - - name: Retrieve secrets - id: retrieve-secrets - uses: bitwarden/gh-actions/get-keyvault-secrets@c3b3285993151c5af47cefcb3b9134c28ab479af - with: - keyvault: "bitwarden-prod-kv" - secrets: "github-pat-bitwarden-devops-bot-repo-scope" - - - name: Call GitHub API to trigger workflow bump - env: - TOKEN: ${{ steps.retrieve-secrets.outputs.github-pat-bitwarden-devops-bot-repo-scope }} - VERSION: ${{ needs.setup.outputs.version_number}} - run: | - JSON_STRING=$(printf '{"ref":"master", "inputs": { "client":"Desktop", "version_number":"%s"}}' "$VERSION") - curl \ - -X POST \ - -i -u bitwarden-devops-bot:$TOKEN \ - -H "Accept: application/vnd.github.v3+json" \ - https://api.github.com/repos/bitwarden/clients/actions/workflows/version-bump.yml/dispatches \ - -d $JSON_STRING + version_number: ${{ needs.setup.outputs.version_number }} + client: "Desktop" diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml index f7ba508c6c3..6d3bd96ea11 100644 --- a/.github/workflows/version-bump.yml +++ b/.github/workflows/version-bump.yml @@ -13,10 +13,23 @@ on: - CLI - Desktop - Web + - All version_number: description: "New Version" required: true + workflow_call: + inputs: + version_number: + required: true + type: string + client: + required: true + type: string + secrets: + AZURE_PROD_KV_CREDENTIALS: + required: true + defaults: run: shell: bash @@ -66,27 +79,27 @@ jobs: ### Browser - name: Bump Browser Version - if: ${{ github.event.inputs.client == 'Browser' }} + if: ${{ github.event.inputs.client == 'Browser' || github.event.inputs.client == 'All' }} env: VERSION: ${{ github.event.inputs.version_number }} run: npm version --workspace=@bitwarden/browser ${VERSION} - name: Bump Browser Version - Manifest - if: ${{ github.event.inputs.client == 'Browser' }} + if: ${{ github.event.inputs.client == 'Browser' || github.event.inputs.client == 'All' }} uses: bitwarden/gh-actions/version-bump@03ad9a873c39cdc95dd8d77dbbda67f84db43945 with: version: ${{ github.event.inputs.version_number }} file_path: "apps/browser/src/manifest.json" - name: Bump Browser Version - Manifest v3 - if: ${{ github.event.inputs.client == 'Browser' }} + if: ${{ github.event.inputs.client == 'Browser' || github.event.inputs.client == 'All' }} uses: bitwarden/gh-actions/version-bump@03ad9a873c39cdc95dd8d77dbbda67f84db43945 with: version: ${{ github.event.inputs.version_number }} file_path: "apps/browser/src/manifest.v3.json" - name: Run Prettier after Browser Version Bump - if: ${{ github.event.inputs.client == 'Browser' }} + if: ${{ github.event.inputs.client == 'Browser' || github.event.inputs.client == 'All' }} run: | npm install -g prettier prettier --write apps/browser/src/manifest.json @@ -94,20 +107,20 @@ jobs: ### CLI - name: Bump CLI Version - if: ${{ github.event.inputs.client == 'CLI' }} + if: ${{ github.event.inputs.client == 'CLI' || github.event.inputs.client == 'All' }} env: VERSION: ${{ github.event.inputs.version_number }} run: npm version --workspace=@bitwarden/cli ${VERSION} ### Desktop - name: Bump Desktop Version - Root - if: ${{ github.event.inputs.client == 'Desktop' }} + if: ${{ github.event.inputs.client == 'Desktop' || github.event.inputs.client == 'All' }} env: VERSION: ${{ github.event.inputs.version_number }} run: npm version --workspace=@bitwarden/desktop ${VERSION} - name: Bump Desktop Version - App - if: ${{ github.event.inputs.client == 'Desktop' }} + if: ${{ github.event.inputs.client == 'Desktop' || github.event.inputs.client == 'All' }} env: VERSION: ${{ github.event.inputs.version_number }} run: npm version ${VERSION} @@ -115,7 +128,7 @@ jobs: ### Web - name: Bump Web Version - if: ${{ github.event.inputs.client == 'Web' }} + if: ${{ github.event.inputs.client == 'Web' || github.event.inputs.client == 'All' }} env: VERSION: ${{ github.event.inputs.version_number }} run: npm version --workspace=@bitwarden/web-vault ${VERSION} diff --git a/README.md b/README.md index f8fb306cfa8..df1f22a0949 100644 --- a/README.md +++ b/README.md @@ -42,91 +42,3 @@ Interested in contributing in a big way? Consider joining our team! We're hiring Code contributions are welcome! Please commit any pull requests against the `master` branch. Learn more about how to contribute by reading the [Contributing Guidelines](https://contributing.bitwarden.com/contributing/). Check out the [Contributing Documentation](https://contributing.bitwarden.com/) for how to get started with your first contribution. Security audits and feedback are welcome. Please open an issue or email us privately if the report is sensitive in nature. You can read our security policy in the [`SECURITY.md`](SECURITY.md) file. - -## Migrate PRs from old repositories - -We recently migrated from individual client repositories. And some PRs were unfortunately left behind in the old repositories. Luckily it's fairly straightforward to sync them up again. Please follow all the instructions below in order to avoid most merge conflicts. - -### Desktop - -``` -# Merge master -git merge master - -# Merge branch mono-repo-prep -git merge 28bc4113b9bbae4dba2b5af14d460764fce79acf - -# Verify files are placed in apps/desktop - -# Add remote -git remote add clients git@github.com:bitwarden/clients.git - -# Merge against clients master -git fetch clients -git merge clients/master - -# Push to clients or your own fork -``` - -### CLI - -``` -# Merge master -git merge master - -# Merge branch mono-repo-prep -git merge 980429f4bdcb178d8d92d8202cbdacfaa45c917e - -# Verify files are placed in apps/cli - -# Add remote -git remote add clients git@github.com:bitwarden/clients.git - -# Merge against clients master -git fetch clients -git merge clients/master - -# Push to clients or your own fork -``` - -### Web - -``` -# Merge master -git merge master - -# Merge branch mono-repo-prep -git merge 02fe7159034b04d763a61fcf0200869e3209fa33 - -# Verify files are placed in apps/web - -# Add remote -git remote add clients git@github.com:bitwarden/clients.git - -# Merge against clients master -git fetch clients -git merge clients/master - -# Push to clients or your own fork -``` - -### Jslib - -``` -# Merge master -git merge master - -# Merge branch mono-repo -git merge d7492e3cf320410e74ebd0e0675ab994e64bd01a - -# Verify files are placed in libs - -# Add remote -git remote add clients git@github.com:bitwarden/clients.git - -# Merge against clients master -git fetch clients -git merge clients/master - -# Push to clients or your own fork -``` diff --git a/apps/browser/gulpfile.js b/apps/browser/gulpfile.js index 26935120ba7..2f672ffcdd4 100644 --- a/apps/browser/gulpfile.js +++ b/apps/browser/gulpfile.js @@ -122,8 +122,8 @@ function distSafariApp(cb, subBuildPath) { "--force", "--sign", subBuildPath === "mas" - ? "3rd Party Mac Developer Application: 8bit Solutions LLC" - : "6B287DD81FF922D86FD836128B0F62F358B38726", + ? "3rd Party Mac Developer Application: Bitwarden Inc" + : "E661AB6249AEB60B0F47ABBD7326B2877D2575B0", "--entitlements", entitlementsPath, ]; diff --git a/apps/browser/package.json b/apps/browser/package.json index d3f64632bc8..e5fc499f061 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/browser", - "version": "2023.1.0", + "version": "2023.3.0", "scripts": { "build": "webpack", "build:mv3": "cross-env MANIFEST_VERSION=3 webpack", diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index 1bfd40aea9d..846f505081e 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "المساعدة والتعليقات" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "المزامنة" }, @@ -430,7 +439,14 @@ "message": "مطلوب إعادة كتابة كلمة المرور الرئيسية." }, "masterPasswordMinlength": { - "message": "يجب أن يكون طول كلمة المرور الرئيسية 8 أحرف على الأقل." + "message": "كلمة المرور الرئيسية يجب أن تكون على الأقل $VALUE$ حرفاً.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "لا يتطابق تأكيد كلمة المرور مع كلمة المرور." @@ -957,70 +973,70 @@ "message": "ملء تلقائي عند تحميل الصفحة" }, "enableAutoFillOnPageLoadDesc": { - "message": "If a login form is detected, auto-fill when the web page loads." + "message": "إذا تم اكتشاف نموذج تسجيل الدخول، يتم التعبئة التلقائية عند تحميل صفحة الويب." }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "مواقع المساومة أو غير الموثوق بها يمكن أن تستغل الملء التلقائي في تحميل الصفحة." }, "learnMoreAboutAutofill": { - "message": "Learn more about auto-fill" + "message": "تعرف على المزيد حول الملء التلقائي" }, "defaultAutoFillOnPageLoad": { - "message": "Default autofill setting for login items" + "message": "الإعداد الافتراضي للملء التلقائي لعناصر تسجيل الدخول" }, "defaultAutoFillOnPageLoadDesc": { - "message": "You can turn off auto-fill on page load for individual login items from the item's Edit view." + "message": "يمكنك إيقاف الملء التلقائي في تحميل الصفحة لعناصر تسجيل الدخول الفردية من عرض تحرير العنصر." }, "itemAutoFillOnPageLoad": { - "message": "Auto-fill on page load (if set up in Options)" + "message": "ملء تلقائي عند تحميل الصفحة (إذا كان الإعداد في الخيارات)" }, "autoFillOnPageLoadUseDefault": { "message": "إستخدم الإعداد الإفتراضي" }, "autoFillOnPageLoadYes": { - "message": "Auto-fill on page load" + "message": "ملء تلقائي عند تحميل الصفحة" }, "autoFillOnPageLoadNo": { - "message": "Do not auto-fill on page load" + "message": "لا تملأ تلقائياً عند تحميل الصفحة" }, "commandOpenPopup": { - "message": "Open vault popup" + "message": "فتح منبثقات المخزن" }, "commandOpenSidebar": { - "message": "Open vault in sidebar" + "message": "فتح المخزن في الشريط الجانبي" }, "commandAutofillDesc": { - "message": "Auto-fill the last used login for the current website" + "message": "ملء تلقائي لآخر تسجيل دخول مستخدم للموقع الحالي" }, "commandGeneratePasswordDesc": { - "message": "Generate and copy a new random password to the clipboard" + "message": "إنشاء واستنساخ كلمة مرور عشوائية جديدة إلى الحافظة" }, "commandLockVaultDesc": { - "message": "Lock the vault" + "message": "قفل المخزن" }, "privateModeWarning": { - "message": "Private mode support is experimental and some features are limited." + "message": "دعم الوضع الخاص تجريبي وبعض الميزات محدودة." }, "customFields": { - "message": "Custom fields" + "message": "الحقول المخصصة" }, "copyValue": { - "message": "Copy value" + "message": "نسخ القيمة" }, "value": { - "message": "Value" + "message": "القيمة" }, "newCustomField": { - "message": "New custom field" + "message": "حقل مخصص جديد" }, "dragToSort": { - "message": "Drag to sort" + "message": "اسحب للفرز" }, "cfTypeText": { - "message": "Text" + "message": "نص" }, "cfTypeHidden": { - "message": "Hidden" + "message": "مخفي" }, "cfTypeBoolean": { "message": "قيمة منطقية" @@ -1299,30 +1315,30 @@ "description": "An entity of multiple related people (ex. a team or business organization)." }, "types": { - "message": "Types" + "message": "أنواع" }, "allItems": { - "message": "All items" + "message": "كافة العناصر" }, "noPasswordsInList": { - "message": "There are no passwords to list." + "message": "لا توجد كلمات مرور للعرض." }, "remove": { - "message": "Remove" + "message": "إزالة" }, "default": { - "message": "Default" + "message": "الافتراضي" }, "dateUpdated": { - "message": "Updated", + "message": "تم التحديث", "description": "ex. Date this item was updated" }, "dateCreated": { - "message": "Created", + "message": "أنشئ", "description": "ex. Date this item was created" }, "datePasswordUpdated": { - "message": "Password updated", + "message": "تحديث كلمة المرور", "description": "ex. Date this password was updated" }, "neverLockWarning": { @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "لا يمكن الوصول للعناصر في المؤسسات المعطلة. اتصل بمدير مؤسستك للحصول على المساعدة." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "جاري تسجيل الدخول إلى $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index e82b5dc0a96..e5bed5d155b 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Kömək və əks əlaqə" }, + "helpCenter": { + "message": "Bitwarden Kömək mərkəzi" + }, + "communityForums": { + "message": "Bitwarden cəmiyyət forumlarını kəşf et" + }, + "contactSupport": { + "message": "Bitwarden dəstəyi ilə əlaqə saxla" + }, "sync": { "message": "Eyniləşdirmə" }, @@ -430,7 +439,14 @@ "message": "Ana parolun yenidən yazılması lazımdır." }, "masterPasswordMinlength": { - "message": "Ana parol ən azı 8 simvol uzunluğunda olmalıdır." + "message": "Ana parol ən azı $VALUE$ simvol uzunluğunda olmalıdır.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Ana parol təsdiqləməsi uyğun gəlmir." @@ -960,7 +976,7 @@ "message": "Giriş formu aşkarlananda, səhifə yüklənən zaman formu avto-doldurma icra edilsin." }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "Təhlükəli və ya güvənilməyən veb saytlar, səhifə yüklənərkən avto-doldurmanı istifadə edə bilər." }, "learnMoreAboutAutofill": { "message": "Avto-doldurma haqqında daha ətraflı" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Sıradan çıxarılmış Təşkilatlardakı elementlərə müraciət edilə bilmir. Kömək üçün Təşkilatınızın sahibi ilə əlaqə saxlayın." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "$DOMAIN$ domeninə giriş edilir", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Təşkilatınızın siyasətləri, səhifə yüklənəndə avto-doldurmanı işə saldı." + }, + "howToAutofill": { + "message": "Avto-doldurma necə edilir" + }, + "autofillSelectInfoWithCommand": { + "message": "Bu səhifədən bir element seçin və ya qısayolu istifadə edin: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Bu səhifədən bir element seçin və ya tənzimləmələrdə bir qısayol tənzimləyin." + }, + "gotIt": { + "message": "Anladım" + }, + "autofillSettings": { + "message": "Avto-doldurma tənzimləmələri" + }, + "autofillShortcut": { + "message": "Avto-doldurma klaviatura qısayolu" + }, + "autofillShortcutNotSet": { + "message": "Avto-doldurma qısayolu tənzimlənməyib. Bunu brauzerin tənzimləmələrində dəyişdirin." + }, + "autofillShortcutText": { + "message": "Avto-doldurma qısayolu: $COMMAND$. Bunu brauzerin tənzimləmələrində dəyişdirin.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "İlkin avto-doldurma qısayolu: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index 416743f74df..2a5190a2c89 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Даведка і зваротная сувязь" }, + "helpCenter": { + "message": "Даведачны цэнтр Bitwarden" + }, + "communityForums": { + "message": "Наведайце форумы супольнасці Bitwarden" + }, + "contactSupport": { + "message": "Звярніцеся ў службу падтрымкі Bitwarden" + }, "sync": { "message": "Сінхранізаваць" }, @@ -430,7 +439,14 @@ "message": "Неабходна паўторна ўвесці асноўны пароль." }, "masterPasswordMinlength": { - "message": "Асноўны пароль павінен быць даўжынёй не менш за 8 сімвалаў." + "message": "Асноўны пароль павінен змяшчаць прынамсі $VALUE$ сімвалаў.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Пацвярджэнне асноўнага пароля не супадае." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Доступ да элементаў у адключаных арганізацыях немагчымы. Звяжыце з уладальнікам арганізацыі для атрымання дапамогі." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Увайсці ў $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Аўтазапаўненне пры загрузцы старонцы было ўключана палітыкамі вашай арганізацыі." + }, + "howToAutofill": { + "message": "Як аўтазапоўніць" + }, + "autofillSelectInfoWithCommand": { + "message": "Выберыце элемент на гэтай старонцы або скарыстайцеся спалучэннем клавіш: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Выберыце элемент на гэтай старонцы або задайце спалучэнне клавіш у наладах." + }, + "gotIt": { + "message": "Зразумела" + }, + "autofillSettings": { + "message": "Налады аўтазапаўнення" + }, + "autofillShortcut": { + "message": "Спалучэнні клавіш аўтазапаўнення" + }, + "autofillShortcutNotSet": { + "message": "Спалучэнні клавіш аўтазапаўнення не зададзены. Змяніце гэта ў наладах браўзера." + }, + "autofillShortcutText": { + "message": "Спалучэнні клавіш аўтазапаўнення: $COMMAND$. Змяніце гэта ў наладах браўзера.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Прадвызначаная спалучэнні клавіш аўтазапаўнення: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index 31980cc7314..4951ad9cff3 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Помощ и обратна връзка" }, + "helpCenter": { + "message": "Помощен център на Битуорден" + }, + "communityForums": { + "message": "Разгледайте обществения форум на Битуорден" + }, + "contactSupport": { + "message": "Свържете се с поддръжката на Битуорден" + }, "sync": { "message": "Синхронизиране" }, @@ -430,7 +439,14 @@ "message": "Повторното въвеждане на главната парола е задължително." }, "masterPasswordMinlength": { - "message": "Главната парола трябва да е дълга поне 8 знака." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Главната парола и потвърждението ѝ не съвпадат." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Записите в изключени организации не са достъпни. Свържете се със собственика на организацията си за помощ." }, - "cardBrandMir": { - "message": "Мир" - }, "loggingInTo": { "message": "Вписване в $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Автоматичното попълване при зареждане на страница е включено в съответствие с политиките на Вашата организация." + }, + "howToAutofill": { + "message": "Как се ползва автоматичното попълване" + }, + "autofillSelectInfoWithCommand": { + "message": "Изберете елемент от тази страница или използвайте следната комбинация: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Изберете елемент от тази страница или задайте клавишна комбинация в настройките." + }, + "gotIt": { + "message": "Разбрано" + }, + "autofillSettings": { + "message": "Настройки за автоматичното попълване" + }, + "autofillShortcut": { + "message": "Клавишна комбинация за автоматично попълване" + }, + "autofillShortcutNotSet": { + "message": "Няма зададена клавишна комбинация за автоматичното попълване. Променете това в настройките на браузъра." + }, + "autofillShortcutText": { + "message": "Клавишната комбинация за автоматично попълване е: $COMMAND$. Може да я промените в настройките на браузъра.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Стандартна клавишна комбинация за автоматично попълване: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json index ef67b6ce478..bbee09ad3e1 100644 --- a/apps/browser/src/_locales/bn/messages.json +++ b/apps/browser/src/_locales/bn/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "সহায়তা এবং প্রতিক্রিয়া" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "সিঙ্ক" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "মূল পাসওয়ার্ড নিশ্চিতকরণ মেলেনি।" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json index 59245840d64..ee072d5c064 100644 --- a/apps/browser/src/_locales/bs/messages.json +++ b/apps/browser/src/_locales/bs/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Help & feedback" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Sync" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Master password confirmation does not match." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index e3619b4ec81..d956e00efb8 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Ajuda i comentaris" }, + "helpCenter": { + "message": "Centre d'ajuda de Bitwarden" + }, + "communityForums": { + "message": "Explora els fòrums de la comunitat de Bitwarden" + }, + "contactSupport": { + "message": "Contacta amb l'assistència de Bitwarden" + }, "sync": { "message": "Sincronització" }, @@ -430,7 +439,14 @@ "message": "Cal tornar a escriure la contrasenya mestra." }, "masterPasswordMinlength": { - "message": "La contrasenya ha de contenir almenys 8 caràcters." + "message": "La contrasenya mestra ha de contenir almenys $VALUE$ caràcters.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "La confirmació de la contrasenya mestra no coincideix." @@ -960,7 +976,7 @@ "message": "Si es detecta un formulari d'inici de sessió, es realitza automàticament un emplenament automàtic quan es carrega la pàgina web." }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "Els llocs web compromesos o no fiables poden aprofitar-se de l'emplenament automàtic en carregar de la pàgina." }, "learnMoreAboutAutofill": { "message": "Obteniu més informació sobre l'emplenament automàtic" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "No es pot accedir als elements de les organitzacions inhabilitades. Poseu-vos en contacte amb el propietari de la vostra organització per obtenir ajuda." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Inici de sessió a $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Les polítiques de l'organització han activat l'emplenament automàtic en carregar la pàgina." + }, + "howToAutofill": { + "message": "Com emplenar automàticament" + }, + "autofillSelectInfoWithCommand": { + "message": "Seleccioneu un element d'aquesta pàgina o utilitzeu la drecera: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Seleccioneu un element d'aquesta pàgina o definiu una drecera a la configuració." + }, + "gotIt": { + "message": "D'acord" + }, + "autofillSettings": { + "message": "Configuració d'emplenament automàtic" + }, + "autofillShortcut": { + "message": "Drecera de teclat d'emplenament automàtic" + }, + "autofillShortcutNotSet": { + "message": "La drecera d'emplenament automàtic no està configurada. Canvieu-ho a la configuració del navegador." + }, + "autofillShortcutText": { + "message": "La drecera d'emplenament automàtic és: $COMMAND$. Canvieu-ho a la configuració del navegador.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Drecera d'emplenament automàtic per defecte: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json index c48af3da257..a8341eca1f1 100644 --- a/apps/browser/src/_locales/cs/messages.json +++ b/apps/browser/src/_locales/cs/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Nápověda a zpětná vazba" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Synchronizace" }, @@ -430,7 +439,14 @@ "message": "Je vyžadováno zopakovat zadání hlavního hesla." }, "masterPasswordMinlength": { - "message": "Hlavní heslo musí obsahovat alespoň 8 znaků." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Potvrzení hlavního hesla se neshoduje." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "K položkám v deaktivované organizaci nemáte přístup. Požádejte o pomoc vlastníka organizace." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Přihlašování do $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Vyberte položku z této stránky nebo použijte zkratku: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Vyberte položku z této stránky nebo nastavte zkratku v nastavení." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index ddc843cb2de..17381195b33 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Hjælp & feedback" }, + "helpCenter": { + "message": "Bitwarden Hjælpecenter" + }, + "communityForums": { + "message": "Tjek Bitwardens fællesskabsfora ud" + }, + "contactSupport": { + "message": "Kontakt Bitwarden-support" + }, "sync": { "message": "Synkronisér" }, @@ -430,7 +439,14 @@ "message": "Hovedadgangskode kræves angivet igen." }, "masterPasswordMinlength": { - "message": "Hovedadgangskode skal være mindst 8 tegn." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "De to adgangskoder matcher ikke." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Elementer i suspenderede organisationer kan ikke tilgås. Kontakt din organisationsejer for at få hjælp." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logger ind på $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Organisationspolitikkerne har aktiveret autoudfyldning ved sideindlæsning." + }, + "howToAutofill": { + "message": "Sådan autoudfyldes" + }, + "autofillSelectInfoWithCommand": { + "message": "Vælg et element fra denne side eller brug genvejen: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Vælg et element fra denne side eller opret en genvej i Indstillinger." + }, + "gotIt": { + "message": "Forstået" + }, + "autofillSettings": { + "message": "Autoudfyldelsesindstillinger" + }, + "autofillShortcut": { + "message": "Autoudfyld-tastaturgenvej" + }, + "autofillShortcutNotSet": { + "message": "Autoudfyldningsgenvejen er ikke opsat. Ændr dette i browserens indstillinger." + }, + "autofillShortcutText": { + "message": "Autoudfyldningsgenvejen er: $COMMAND$. Ændr dette i browserens indstillinger.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Standard autoudfyldningsgenvej: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index 6411e6d076a..84836c42751 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -7,7 +7,7 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "Bitwarden ist ein sicherer und kostenloser Passwortmanager für all Ihre Geräte.", + "message": "Ein sicherer und kostenloser Passwortmanager für all deine Geräte.", "description": "Extension description" }, "loginOrCreateNewAccount": { @@ -20,7 +20,7 @@ "message": "Anmelden" }, "enterpriseSingleSignOn": { - "message": "Enterprise Single Sign-On" + "message": "Enterprise Single-Sign-On" }, "cancel": { "message": "Abbrechen" @@ -80,7 +80,7 @@ "message": "URI kopieren" }, "copyUsername": { - "message": "Nutzernamen kopieren" + "message": "Benutzername kopieren" }, "copyNumber": { "message": "Nummer kopieren" @@ -113,7 +113,7 @@ "message": "Zugangsdaten hinzufügen" }, "addItem": { - "message": "Neuer Eintrag" + "message": "Eintrag hinzufügen" }, "passwordHint": { "message": "Passwort-Hinweis" @@ -131,7 +131,7 @@ "message": "Einen Bestätigungscode an deine E-Mail senden" }, "sendCode": { - "message": "Send Code" + "message": "Code senden" }, "codeSent": { "message": "Code gesendet" @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Hilfe & Feedback" }, + "helpCenter": { + "message": "Bitwarden Hilfezentrum" + }, + "communityForums": { + "message": "Bitwarden Community-Foren erkunden" + }, + "contactSupport": { + "message": "Bitwarden Support kontaktieren" + }, "sync": { "message": "Synchronisierung" }, @@ -258,7 +267,7 @@ "description": "Make the first letter of a work uppercase." }, "includeNumber": { - "message": "Ziffer hinzufügen" + "message": "Ziffern einschließen" }, "minNumbers": { "message": "Mindestanzahl Ziffern" @@ -282,7 +291,7 @@ "message": "Keine Einträge zum Anzeigen vorhanden." }, "itemInformation": { - "message": "Anmeldedaten Information" + "message": "Eintragsinformationen" }, "username": { "message": "Nutzername" @@ -330,7 +339,7 @@ "message": "Sonstige" }, "rateExtension": { - "message": "Bewerte die Erweiterung" + "message": "Erweiterung bewerten" }, "rateExtensionDesc": { "message": "Wir würden uns freuen, wenn du uns mit einer positiven Bewertung helfen könntest!" @@ -342,7 +351,7 @@ "message": "Identität verifizieren" }, "yourVaultIsLocked": { - "message": "Ihr Tresor ist gesperrt. Bestätigen Sie Ihre Identität um fortzufahren." + "message": "Dein Tresor ist gesperrt. Verifiziere deine Identität, um fortzufahren." }, "unlock": { "message": "Entsperren" @@ -430,7 +439,14 @@ "message": "Erneute Eingabe des Master-Passworts ist erforderlich." }, "masterPasswordMinlength": { - "message": "Das Master-Passwort muss mindestens 8 Zeichen lang sein." + "message": "Das Master-Passwort muss mindestens $VALUE$ Zeichen lang sein.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Die Master-Passwort-Wiederholung stimmt nicht überein." @@ -491,10 +507,10 @@ "message": "Du kannst dein Master-Passwort im Bitwarden.com Web-Tresor ändern. Möchtest du die Seite jetzt öffnen?" }, "twoStepLoginConfirmation": { - "message": "Mit der Zwei-Faktor-Authentifizierung wird dein Account zusätzlich abgesichert, da jede Anmeldung durch einen Sicherheitscode, eine Authentifizierungs-App, eine SMS, einen Anruf oder eine E-Mail verifiziert werden muss. Die Zwei-Faktor-Authentifizierung kann im bitwarden.com Web-Tresor aktiviert werden. Möchtest du die Seite jetzt öffnen?" + "message": "Mit der Zwei-Faktor-Authentifizierung wird dein Konto zusätzlich abgesichert, da jede Anmeldung mit einem anderen Gerät wie einem Sicherheitsschlüssel, einer Authentifizierungs-App, einer SMS, einem Anruf oder einer E-Mail verifiziert werden muss. Die Zwei-Faktor-Authentifizierung kann im bitwarden.com Web-Tresor aktiviert werden. Möchtest du die Website jetzt öffnen?" }, "editedFolder": { - "message": "Ordner bearbeitet" + "message": "Ordner gespeichert" }, "deleteFolderConfirmation": { "message": "Soll dieser Ordner wirklich gelöscht werden?" @@ -503,7 +519,7 @@ "message": "Ordner gelöscht" }, "gettingStartedTutorial": { - "message": "Erste Schritte Anleitung" + "message": "Erste Schritte" }, "gettingStartedTutorialVideo": { "message": "Sieh dir unser Tutorial an, um hilfreiche Tipps zum Umgang mit der Browser-Erweiterung zu erfahren." @@ -534,10 +550,10 @@ "message": "Neue URL" }, "addedItem": { - "message": "Neuer Eintrag" + "message": "Eintrag hinzugefügt" }, "editedItem": { - "message": "Eintrag bearbeitet" + "message": "Eintrag gespeichert" }, "deleteItemConfirmation": { "message": "Soll dieser Eintrag wirklich in den Papierkorb verschoben werden?" @@ -552,7 +568,7 @@ "message": "Sind Sie sicher, dass Sie das aktuelle Passwort ersetzen möchten?" }, "overwriteUsername": { - "message": "Benutzername überschreiben" + "message": "Benutzername ersetzen" }, "overwriteUsernameConfirmation": { "message": "Bist du sicher, dass du den aktuellen Benutzernamen überschreiben möchtest?" @@ -571,10 +587,10 @@ "description": "This is the folder for uncategorized items" }, "enableAddLoginNotification": { - "message": "Danach fragen Zugangsdaten hinzuzufügen" + "message": "Nach dem Hinzufügen von Zugangsdaten fragen" }, "addLoginNotificationDesc": { - "message": "Die \"Login hinzufügen\" Benachrichtigung fragt dich automatisch, ob du neue Zugangsdaten im Tresor speichern möchtest, wenn du dich zum ersten Mal mit ihnen anmeldest." + "message": "Nach dem Hinzufügen eines Eintrags fragen, wenn dieser nicht in deinem Tresor gefunden wurde." }, "showCardsCurrentTab": { "message": "Karten auf Tab Seite anzeigen" @@ -603,10 +619,10 @@ "message": "Ja, jetzt speichern" }, "enableChangedPasswordNotification": { - "message": "Danach fragen bestehende Zugangsdaten zu aktualisieren" + "message": "Nach dem Aktualisieren bestehender Zugangsdaten fragen" }, "changedPasswordNotificationDesc": { - "message": "Danach fragen das Passwort der Zugangsdaten zu aktualisieren, wenn eine Änderung auf einer Webseite erkannt wird." + "message": "Nach dem Aktualisieren eines Passworts fragen, wenn eine Änderung auf einer Website erkannt wird." }, "notificationChangeDesc": { "message": "Möchtest du dieses Passwort in Bitwarden aktualisieren?" @@ -723,16 +739,16 @@ "message": "Möchtest du diesen Anhang wirklich löschen?" }, "deletedAttachment": { - "message": "Gelöschter Anhang" + "message": "Anhang gelöscht" }, "newAttachment": { - "message": "Anhang hinzufügen" + "message": "Neuen Anhang hinzufügen" }, "noAttachments": { "message": "Keine Anhänge." }, "attachmentSaved": { - "message": "Der Anhang wurde gespeichert." + "message": "Anhang gespeichert" }, "file": { "message": "Datei" @@ -765,7 +781,7 @@ "message": "Du bist derzeit kein Premium-Mitglied." }, "premiumSignUpAndGet": { - "message": "Werde Premium-Mitglied und erhalte dafür:" + "message": "Melde dich für eine Premium-Mitgliedschaft an und erhalte dafür:" }, "ppremiumSignUpStorage": { "message": "1 GB verschlüsselter Speicherplatz für Dateianhänge." @@ -789,7 +805,7 @@ "message": "Premium-Mitgliedschaft kaufen" }, "premiumPurchaseAlert": { - "message": "Du kannst deine Premium-Mitgliedschaft im Bitwarden.com Web-Tresor kaufen. Möchtest du die Webseite jetzt besuchen?" + "message": "Du kannst deine Premium-Mitgliedschaft im Bitwarden.com Web-Tresor kaufen. Möchtest du die Website jetzt besuchen?" }, "premiumCurrentMember": { "message": "Du bist jetzt Premium-Mitglied!" @@ -813,13 +829,13 @@ "message": "TOTP automatisch kopieren" }, "disableAutoTotpCopyDesc": { - "message": "Ist ein Authentifizierungsschlüssel mit Ihren Zugangsdaten verknüpft, wird der TOTP Verifizierungscode automatisch in die Zwischenablage kopiert, wenn Sie die Zugangsdaten automatisch ausfüllen lassen." + "message": "Ist ein Authentifizierungsschlüssel mit deinen Zugangsdaten verknüpft, wird der TOTP Verifizierungscode in die Zwischenablage kopiert, wenn du die Zugangsdaten automatisch einfügen lässt." }, "enableAutoBiometricsPrompt": { "message": "Beim Start nach biometrischen Daten fragen" }, "premiumRequired": { - "message": "Erweiterte Mitgliedschaft wird benötigt" + "message": "Premium-Mitgliedschaft benötigt" }, "premiumRequiredDesc": { "message": "Eine Premium-Mitgliedschaft ist für diese Funktion notwendig." @@ -873,22 +889,22 @@ "message": "Anmeldung nicht verfügbar" }, "noTwoStepProviders": { - "message": "Dieses Konto hat eine aktive Zwei-Faktor Authentifizierung, allerdings wird keiner der konfigurierten Zwei-Faktor Anbieter von diesem Browser unterstützt." + "message": "Für dieses Konto ist eine Zwei-Faktor-Authentifizierung eingerichtet, allerdings wird keiner der konfigurierten Zwei-Faktor-Anbieter von diesem Browser unterstützt." }, "noTwoStepProviders2": { "message": "Bitte benutze einen unterstützten Browser (z.B. Chrome) und / oder füge zusätzliche Anbieter hinzu, die von mehr Browsern unterstützt werden (wie eine Authentifizierungs-App)." }, "twoStepOptions": { - "message": "Optionen für Zwei-Faktor Authentifizierung" + "message": "Optionen für Zwei-Faktor-Authentifizierung" }, "recoveryCodeDesc": { - "message": "Zugang zu allen Zwei-Faktor-Anbietern verloren? Benutzen Sie Ihren Wiederherstellungscode, um alle Zwei-Faktor-Anbieter in Ihrem Konto zu deaktivieren." + "message": "Zugang zu allen Zwei-Faktor Anbietern verloren? Benutze deinen Wiederherstellungscode, um alle Zwei-Faktor Anbieter in deinem Konto zu deaktivieren." }, "recoveryCodeTitle": { "message": "Wiederherstellungscode" }, "authenticatorAppTitle": { - "message": "Authentifizierungs-App" + "message": "Authenticator App" }, "authenticatorAppDesc": { "message": "Verwende eine Authentifizierungs-App (wie zum Beispiel Authy oder Google Authenticator), um zeitbasierte Verifizierungscodes zu generieren.", @@ -912,7 +928,7 @@ "message": "FIDO2 WebAuthn" }, "webAuthnDesc": { - "message": "Benutze einen WebAuthn-kompatiblen Sicherheitsschlüssel, um auf dein Konto zuzugreifen." + "message": "Benutze einen beliebigen WebAuthn-kompatiblen Sicherheitsschlüssel, um auf dein Konto zuzugreifen." }, "emailTitle": { "message": "E-Mail" @@ -921,7 +937,7 @@ "message": "Bestätigungscodes werden Ihnen per E-Mail zugesandt." }, "selfHostedEnvironment": { - "message": "Selbstgehostete Umgebung" + "message": "Selbst gehostete Umgebung" }, "selfHostedEnvironmentFooter": { "message": "Bitte gib die Basis-URL deiner selbst gehosteten Bitwarden-Installation an." @@ -939,28 +955,28 @@ "message": "API Server URL" }, "webVaultUrl": { - "message": "Web-Tresor Server URL" + "message": "URL des Web-Tresor-Servers" }, "identityUrl": { "message": "URL des Identitätsservers" }, "notificationsUrl": { - "message": "URL des Benachrichtigungsserver" + "message": "URL des Benachrichtigungsservers" }, "iconsUrl": { - "message": "Icons Server URL" + "message": "URL des Icons-Servers" }, "environmentSaved": { - "message": "Die URLs der Umgebung wurden gespeichert." + "message": "URLs der Umgebung gespeichert" }, "enableAutoFillOnPageLoad": { "message": "Auto-Ausfüllen beim Laden einer Seite aktivieren" }, "enableAutoFillOnPageLoadDesc": { - "message": "Wenn eine Zugangsmaske erkannt wird, füge automatisch die Zugangsdaten ein während die Webseite lädt." + "message": "Wenn eine Anmeldemaske erkannt wird, die Zugangsdaten automatisch ausfüllen während die Webseite lädt." }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "Kompromittierte oder nicht vertrauenswürdige Websites können Auto-Ausfüllen beim Laden der Seite ausnutzen." }, "learnMoreAboutAutofill": { "message": "Erfahre mehr über Auto-Ausfüllen" @@ -969,10 +985,10 @@ "message": "Standard Auto-Ausfüllen Einstellung für Login-Einträge" }, "defaultAutoFillOnPageLoadDesc": { - "message": "Nachdem du das automatische Ausfüllen beim Laden der Seite aktiviert hast, kannst du die Funktion für einzelne Login-Einträge aktivieren oder deaktivieren. Dies ist die Standardeinstellung für Login-Einträge, die nicht separat konfiguriert wurden." + "message": "Du kannst Auto-Ausfüllen beim Laden der Seite für einzelne Zugangsdaten-Einträge in der Bearbeiten-Ansicht des Eintrags deaktivieren." }, "itemAutoFillOnPageLoad": { - "message": "Automatisches Ausfüllen beim Laden der Seite (wenn in Optionen aktiviert)" + "message": "Auto-Ausfüllen beim Laden der Seite (wenn in Optionen aktiviert)" }, "autoFillOnPageLoadUseDefault": { "message": "Nutze Standardeinstellung" @@ -1040,16 +1056,16 @@ "message": "Dieser Browser kann U2F-Anfragen in diesem Popup-Fenster nicht verarbeiten. Möchtest du dieses Popup in einem neuen Fenster öffnen, damit du dich mit U2F anmelden kannst?" }, "enableFavicon": { - "message": "Zeige Webseiten-Icons" + "message": "Website-Symbole anzeigen" }, "faviconDesc": { "message": "Ein wiedererkennbares Bild neben jeden Zugangsdaten anzeigen." }, "enableBadgeCounter": { - "message": "Zeige Badge-Zähler" + "message": "Badge-Zähler anzeigen" }, "badgeCounterDesc": { - "message": "Gebe an, wie viele Zugangsdaten du für die aktuelle Webseite besitzt." + "message": "Zeigt an, wie viele Zugangsdaten du für die aktuelle Webseite besitzt." }, "cardholderName": { "message": "Name des Karteninhabers" @@ -1205,7 +1221,7 @@ "message": "Identität" }, "passwordHistory": { - "message": "Kennwort-Historie" + "message": "Passwortverlauf" }, "back": { "message": "Zurück" @@ -1232,7 +1248,7 @@ "message": "Zugangsdaten" }, "secureNotes": { - "message": "Sichere Notiz" + "message": "Sichere Notizen" }, "clear": { "message": "Löschen", @@ -1284,10 +1300,10 @@ "description": "Default URI match detection for auto-fill." }, "toggleOptions": { - "message": "Umschaltoptionen" + "message": "Optionen umschalten" }, "toggleCurrentUris": { - "message": "Aktuelle URIs ändern", + "message": "Aktuelle URIs umschalten", "description": "Toggle the display of the URIs of the currently open tabs in the browser." }, "currentUri": { @@ -1381,7 +1397,7 @@ "message": "Warte auf Bestätigung vom Desktop" }, "awaitDesktopDesc": { - "message": "Bitte bestätige die Verwendung von Biometrie in der Bitwarden Desktop-Anwendung, um Biometrie für den Browser zu aktivieren." + "message": "Bitte bestätige die Verwendung von Biometrie in der Bitwarden Desktop-Anwendung, um Biometrie für den Browser einzurichten." }, "lockWithMasterPassOnRestart": { "message": "Bei Neustart des Browsers mit Master-Passwort sperren" @@ -1437,13 +1453,13 @@ "message": "Bestätigung der Timeout-Aktion" }, "autoFillAndSave": { - "message": "Automatisch ausfüllen und speichern" + "message": "Auto-Ausfüllen und speichern" }, "autoFillSuccessAndSavedUri": { - "message": "Auto-Ausgefüllter Eintrag und gespeicherte URI" + "message": "Eintrag automatisch ausgefüllt und URI gespeichert" }, "autoFillSuccess": { - "message": "Automatisch ausgefüllter Eintrag" + "message": "Eintrag automatisch ausgefüllt " }, "setMasterPassword": { "message": "Master-Passwort festlegen" @@ -1512,22 +1528,22 @@ "message": "Desktop-Sync-Überprüfung" }, "desktopIntegrationVerificationText": { - "message": "Bitte bestätigen Sie, dass die Desktop-Anwendung diesen Prüfschlüssel anzeigt: " + "message": "Bitte überprüfe, dass die Desktop-Anwendung diesen Fingerabdruck anzeigt: " }, "desktopIntegrationDisabledTitle": { - "message": "Browser-Einbindung ist nicht aktiviert" + "message": "Browser-Integration ist nicht aktiviert" }, "desktopIntegrationDisabledDesc": { - "message": "Die Browser-Einbindung ist in der Bitwarden Desktop-Anwendung nicht aktiviert. Bitte aktivieren Sie diese in den Einstellungen innerhalb der Desktop-Anwendung." + "message": "Die Browser-Integration ist in der Bitwarden Desktop-Anwendung nicht eingerichtet. Bitte richte diese in den Einstellungen der Desktop-Anwendung ein." }, "startDesktopTitle": { "message": "Bitwarden Desktop-Anwendung starten" }, "startDesktopDesc": { - "message": "Die Bitwarden Desktop-Anwendung muss gestartet werden, bevor diese Funktion verwendet werden kann." + "message": "Die Bitwarden Desktop-Anwendung muss gestartet werden, bevor Entsperren mit Biometrie verwendet werden kann." }, "errorEnableBiometricTitle": { - "message": "Biometrie kann nicht aktiviert werden" + "message": "Biometrie konnte nicht eingerichtet werden" }, "errorEnableBiometricDesc": { "message": "Die Aktion wurde von der Desktop-Anwendung abgebrochen" @@ -1545,10 +1561,10 @@ "message": "Konten stimmen nicht überein" }, "biometricsNotEnabledTitle": { - "message": "Biometrie ist nicht aktiviert" + "message": "Biometrie ist nicht eingerichtet" }, "biometricsNotEnabledDesc": { - "message": "Biometrie im Browser setzt voraus, dass Biometrie zuerst in den Einstellungen der Desktop-Anwendung aktiviert ist." + "message": "Biometrie im Browser setzt voraus, dass Biometrie zuerst in den Einstellungen der Desktop-Anwendung eingerichtet wird." }, "biometricsNotSupportedTitle": { "message": "Biometrie wird nicht unterstützt" @@ -1581,7 +1597,7 @@ "message": "Bitwarden wird keine Login-Daten für diese Domäne speichern. Du musst die Seite aktualisieren, damit die Änderungen wirksam werden." }, "excludedDomainsInvalidDomain": { - "message": "$DOMAIN$ ist keine gültige Domäne", + "message": "$DOMAIN$ ist keine gültige Domain", "placeholders": { "domain": { "content": "$1", @@ -1737,14 +1753,14 @@ "message": "Aktuelle Zugriffsanzahl" }, "createSend": { - "message": "Neues Send erstellen", + "message": "Neues Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "newPassword": { "message": "Neues Passwort" }, "sendDisabled": { - "message": "Send deaktiviert", + "message": "Send gelöscht", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendDisabledWarning": { @@ -1756,7 +1772,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editedSend": { - "message": "Bearbeitetes Send", + "message": "Send gespeichert", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendLinuxChromiumFileWarning": { @@ -1826,7 +1842,7 @@ "message": "Master-Passwort aktualisieren" }, "updateMasterPasswordWarning": { - "message": "Dein Master-Passwort wurde kürzlich von einem Administrator Ihrer Organisation geändert. Um auf den Tresor zuzugreifen, musst du es jetzt aktualisieren. Wenn du fortfährst, wirst du aus der aktuellen Sitzung abgemeldet, eine erneute Anmeldung wird erforderlich. Aktive Sitzungen auf anderen Geräten können bis zu einer Stunde weiterhin aktiv bleiben." + "message": "Dein Master-Passwort wurde kürzlich von einem Administrator deiner Organisation geändert. Um auf den Tresor zuzugreifen, musst du es jetzt aktualisieren. Wenn du fortfährst, wirst du aus der aktuellen Sitzung abgemeldet und musst dich erneut anmelden. Aktive Sitzungen auf anderen Geräten können bis zu einer Stunde weiterhin aktiv bleiben." }, "resetPasswordPolicyAutoEnroll": { "message": "Automatische Registrierung" @@ -1863,7 +1879,7 @@ "message": "Dein Tresor-Timeout überschreitet die von deinem Unternehmen festgelegten Beschränkungen." }, "vaultExportDisabled": { - "message": "Tresor-Export deaktiviert" + "message": "Tresor-Export nicht verfügbar" }, "personalVaultExportPolicyInEffect": { "message": "Eine oder mehrere Unternehmensrichtlinien hindern dich daran, deinen persönlichen Tresor zu exportieren." @@ -1890,7 +1906,7 @@ "message": "Master-Passwort entfernen" }, "removedMasterPassword": { - "message": "Master-Passwort entfernt." + "message": "Master-Passwort entfernt" }, "leaveOrganizationConfirmation": { "message": "Bist du sicher, dass du diese Organisation verlassen möchtest?" @@ -1902,13 +1918,13 @@ "message": "Zeichenzählung ein-/ausschalten" }, "sessionTimeout": { - "message": "Deine Sitzung ist abgelaufen. Bitte gehe zurück und versuche dich erneut einzuloggen." + "message": "Deine Sitzung ist abgelaufen. Bitte gehe zurück und versuche dich erneut anzumelden." }, "exportingPersonalVaultTitle": { - "message": "Persönlichen Tresor exportieren" + "message": "Persönlicher Tresor wird exportiert" }, "exportingPersonalVaultDescription": { - "message": "Nur die persönlichen Tresoreinträge, die mit $EMAIL$ verbunden sind, werden exportiert. Tresoreinträge der Organisation werden nicht berücksichtigt.", + "message": "Nur die einzelnen Tresor-Einträge, die mit $EMAIL$ verbunden sind, werden exportiert. Tresor-Einträge der Organisation werden nicht berücksichtigt.", "placeholders": { "email": { "content": "$1", @@ -1923,13 +1939,13 @@ "message": "Benutzername neu generieren" }, "generateUsername": { - "message": "Benutzernamen generieren" + "message": "Benutzername generieren" }, "usernameType": { - "message": "Benutzernamentyp" + "message": "Benutzernamenstyp" }, "plusAddressedEmail": { - "message": "Mit Plus adressierte E-Mail", + "message": "Plus-adressierte E-Mail-Adresse", "description": "Username generator option that appends a random sub-address to the username. For example: address+subaddress@email.com" }, "plusAddressedEmailDesc": { @@ -1948,7 +1964,7 @@ "message": "Zufälliges Wort" }, "websiteName": { - "message": "Webseiten-Name" + "message": "Websitename" }, "whatWouldYouLikeToGenerate": { "message": "Was möchtest du generieren?" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Auf Einträge in deaktivierten Organisationen kann nicht zugegriffen werden. Kontaktiere deinen Organisationseigentümer für Unterstützung." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Anmelden bei $DOMAIN$", "placeholders": { @@ -2012,7 +2025,7 @@ "message": "Server-Version" }, "selfHosted": { - "message": "Selbst-gehostet" + "message": "Selbst gehostet" }, "thirdParty": { "message": "Drittanbieter" @@ -2027,7 +2040,7 @@ } }, "lastSeenOn": { - "message": "zuletzt am $DATE$ gesehen", + "message": "zuletzt gesehen am: $DATE$", "placeholders": { "date": { "content": "$1", @@ -2039,7 +2052,7 @@ "message": "Mit Master-Passwort anmelden" }, "loggingInAs": { - "message": "Einloggen als" + "message": "Anmelden als" }, "notYou": { "message": "Nicht du?" @@ -2054,7 +2067,7 @@ "message": "Mit Gerät anmelden" }, "loginWithDeviceEnabledInfo": { - "message": "Mit Gerät anmelden muss in den Einstellungen der Bitwarden App eingerichtet werden. Benötigst du eine andere Option?" + "message": "Die Anmeldung über ein Gerät muss in den Einstellungen der Bitwarden App eingerichtet werden. Benötigst du eine andere Option?" }, "fingerprintPhraseHeader": { "message": "Fingerabdruck-Phrase" @@ -2066,13 +2079,13 @@ "message": "Benachrichtigung erneut senden" }, "viewAllLoginOptions": { - "message": "Alle Anmelde-Optionen anzeigen" + "message": "Alle Anmeldeoptionen anzeigen" }, "notificationSentDevice": { "message": "Eine Benachrichtigung wurde an dein Gerät gesendet." }, "logInInitiated": { - "message": "Anmeldung initiiert" + "message": "Anmeldung eingeleitet" }, "exposedMasterPassword": { "message": "Kompromittiertes Master-Passwort" @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Deine Organisationsrichtlinien haben Auto-Ausfüllen beim Laden von Seiten aktiviert." + }, + "howToAutofill": { + "message": "So funktioniert Auto-Ausfüllen" + }, + "autofillSelectInfoWithCommand": { + "message": "Wähle einen Eintrag von dieser Seite aus oder verwende das Tastaturkürzel: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Wähle einen Eintrag von dieser Seite aus oder lege ein Tastaturkürzel in den Einstellungen fest." + }, + "gotIt": { + "message": "Verstanden" + }, + "autofillSettings": { + "message": "Auto-Ausfüllen Einstellungen" + }, + "autofillShortcut": { + "message": "Auto-Ausfüllen Tastaturkürzel" + }, + "autofillShortcutNotSet": { + "message": "Das Auto-Ausfüllen Tastaturkürzel ist nicht gesetzt. Du kannst eines in den Browser-Einstellungen festlegen." + }, + "autofillShortcutText": { + "message": "Das Auto-Ausfüllen Tastaturkürzel ist: $COMMAND$. Du kannst es in den Browser-Einstellungen ändern.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Standard-Auto-Ausfüllen Tastaturkürzel: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index 17d2b4c14a0..fe8b651dced 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Βοήθεια & Σχόλια" }, + "helpCenter": { + "message": "Κέντρο βοήθειας Bitwarden" + }, + "communityForums": { + "message": "Εξερευνήστε τα φόρουμ της κοινότητας του Bitwarden" + }, + "contactSupport": { + "message": "Επικοινωνία με την υποστήριξη Bitwarden" + }, "sync": { "message": "Συγχρονισμός" }, @@ -430,7 +439,14 @@ "message": "Απαιτείται ξανά ο κύριος κωδικός πρόσβασης." }, "masterPasswordMinlength": { - "message": "Ο κύριος κωδικός πρέπει να έχει μήκος τουλάχιστον 8 χαρακτήρες." + "message": "Ο κύριος κωδικός πρέπει να έχει μήκος τουλάχιστον $VALUE$ χαρακτήρες.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Η επιβεβαίωση κύριου κωδικού δεν ταιριάζει." @@ -873,7 +889,7 @@ "message": "Μη διαθέσιμη σύνδεση" }, "noTwoStepProviders": { - "message": "Αυτός ο λογαριασμός έχει ενεργοποιημένη τη σύνδεση δύο βημάτων, ωστόσο, κανένας από τους καθορισμένους παρόχους δύο βημάτων δεν υποστηρίζεται από αυτό το πρόγραμμα περιήγησης." + "message": "Αυτός ο λογαριασμός έχει ενεργοποιημένη τη σύνδεση σε δύο βήματα, ωστόσο, κανένας από τους καθορισμένους παρόχους δύο βημάτων δεν υποστηρίζεται από αυτό το πρόγραμμα περιήγησης." }, "noTwoStepProviders2": { "message": "Παρακαλούμε χρησιμοποιήστε ένα υποστηριζόμενο πρόγραμμα περιήγησης (όπως το Chrome) και/ή προσθέστε επιπλέον ή/και προσθέστε άλλους παρόχους που υποστηρίζονται καλύτερα σε προγράμματα περιήγησης (όπως μια εφαρμογή επαλήθευσης)." @@ -1127,7 +1143,7 @@ "message": "Dr" }, "mx": { - "message": "Mx" + "message": "Κ@" }, "firstName": { "message": "Όνομα" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Δεν είναι δυνατή η πρόσβαση σε αντικείμενα σε απενεργοποιημένους οργανισμούς. Επικοινωνήστε με τον ιδιοκτήτη του Οργανισμού για βοήθεια." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Σύνδεση στο $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Οι πολιτικές του οργανισμού σας έχουν ενεργοποιήσει την αυτόματη συμπλήρωση με φόρτωση σελίδας." + }, + "howToAutofill": { + "message": "Πώς να συμπληρώσετε αυτόματα" + }, + "autofillSelectInfoWithCommand": { + "message": "Επιλέξτε ένα στοιχείο από αυτή τη σελίδα ή χρησιμοποιήστε τη συντόμευση: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Επιλέξτε ένα στοιχείο από αυτή τη σελίδα ή ορίστε μια συντόμευση στις ρυθμίσεις." + }, + "gotIt": { + "message": "Το κατάλαβα" + }, + "autofillSettings": { + "message": "Ρυθμίσεις αυτόματης συμπλήρωσης" + }, + "autofillShortcut": { + "message": "Συντόμευση πληκτρολογίου αυτόματης συμπλήρωσης" + }, + "autofillShortcutNotSet": { + "message": "Η συντόμευση αυτόματης συμπλήρωσης δεν έχει οριστεί. Αλλάξτε τη στις ρυθμίσεις του περιηγητή." + }, + "autofillShortcutText": { + "message": "Η συντόμευση αυτόματης συμπλήρωσης είναι: $COMMAND$. Αλλάξτε τη στις ρυθμίσεις του προγράμματος περιήγησης.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Προεπιλεγμένη συντόμευση αυτόματης συμπλήρωσης: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index e6ad0549c84..6366aafd0f5 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Help & feedback" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Sync" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Master password confirmation does not match." @@ -1990,9 +2006,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2116,25 +2129,52 @@ } } }, - "tryAutofillPageLoad": { - "message": "Try auto-fill on page load?" + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." }, - "tryAutofill": { + "howToAutofill": { "message": "How to auto-fill" }, - "autofillPageLoadInfo": { - "message": "Login forms will automatically fill in matching credentials if you turn on auto-fill on page load." + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } }, - "autofillSelectInfo": { - "message": "Select an item from this page to auto-fill the active tab's form." + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." }, - "autofillTurnedOn": { - "message": "Auto-fill on page load turned on" + "gotIt": { + "message": "Got it" }, - "turnOn": { - "message": "Turn on" + "autofillSettings": { + "message": "Auto-fill settings" }, - "notNow": { - "message": "Not now" + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json index 86c433b4576..4d399f76c2d 100644 --- a/apps/browser/src/_locales/en_GB/messages.json +++ b/apps/browser/src/_locales/en_GB/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Help & feedback" }, + "helpCenter": { + "message": "Bitwarden Help centre" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Sync" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Master password confirmation does not match." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organisations cannot be accessed. Contact your Organisation owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json index 46c260914fa..19879475c2a 100644 --- a/apps/browser/src/_locales/en_IN/messages.json +++ b/apps/browser/src/_locales/en_IN/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Help & feedback" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Sync" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Master password confirmation does not match." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in disabled Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index 85002e8d14d..c1fdb8448a7 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Ayuda y comentarios" }, + "helpCenter": { + "message": "Centro de ayuda de Bitwarden" + }, + "communityForums": { + "message": "Explorar los foros de la comunidad Bitwarden" + }, + "contactSupport": { + "message": "Contactar al soporte de Bitwarden" + }, "sync": { "message": "Sincronizar" }, @@ -430,7 +439,14 @@ "message": "Se requiere volver a teclear la contraseña maestra." }, "masterPasswordMinlength": { - "message": "La contraseña maestra debe tener al menos 8 caracteres." + "message": "La contraseña maestra debe tener al menos $VALUE$ caracteres.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "La confirmación de contraseña maestra no coincide." @@ -960,7 +976,7 @@ "message": "Si se detecta un formulario, realizar automáticamente un autorellenado cuando la web cargue." }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "Los sitios web vulnerados o no confiables pueden explotar el autorelleno al cargar la página." }, "learnMoreAboutAutofill": { "message": "Más información sobre el relleno automático" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "No se puede acceder a los elementos de las organizaciones desactivadas. Póngase en contacto con el personal propietario de la organización para obtener ayuda." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Iniciando sesión en $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Las políticas de su organización han activado autocompletar al cargar la página." + }, + "howToAutofill": { + "message": "Cómo autorellenar" + }, + "autofillSelectInfoWithCommand": { + "message": "Seleccione un elemento de esta página o utilice el acceso directo: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Seleccione un elemento de esta página o establezca un acceso directo en los ajustes." + }, + "gotIt": { + "message": "Entendido" + }, + "autofillSettings": { + "message": "Ajustes de autocompletar" + }, + "autofillShortcut": { + "message": "Atajo de teclado para autocompletar" + }, + "autofillShortcutNotSet": { + "message": "El atajo de autocompletar no está establecido. Cambie esto en los ajustes del navegador." + }, + "autofillShortcutText": { + "message": "El atajo de autocompletar es $COMMAND$. Cambie esto en los ajustes del navegador.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Atajo de autocompletar predeterminado: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json index 5aec0a3c841..da3f9a8abff 100644 --- a/apps/browser/src/_locales/et/messages.json +++ b/apps/browser/src/_locales/et/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Abi ja tagasiside" }, + "helpCenter": { + "message": "Bitwardeni abikeskus" + }, + "communityForums": { + "message": "Ava Bitwardeni foorum" + }, + "contactSupport": { + "message": "Võta Bitwardeniga ühendust" + }, "sync": { "message": "Sünkroniseeri" }, @@ -430,7 +439,14 @@ "message": "Vajalik on ülemparooli uuesti sisestamine." }, "masterPasswordMinlength": { - "message": "Ülemparool peab olema vähemalt 8 tähemärgi pikkune." + "message": "Ülemparool peab olema vähemalt $VALUE$ tähemärgi pikkune.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Ülemparoolid ei ühti." @@ -798,7 +814,7 @@ "message": "Täname, et toetad Bitwardenit." }, "premiumPrice": { - "message": "Kõik see ainult %price% aastas!", + "message": "Kõik see ainult $PRICE$ / aastas!", "placeholders": { "price": { "content": "$1", @@ -828,7 +844,7 @@ "message": "Sisesta autentimise rakendusest 6 kohaline number." }, "enterVerificationCodeEmail": { - "message": "Sisesta 6 kohaline number, mis saadeti e-posti aadressile", + "message": "Sisesta 6 kohaline number, mis saadeti e-posti aadressile $EMAIL$.", "placeholders": { "email": { "content": "$1", @@ -960,10 +976,10 @@ "message": "Sisselogimise vormi tuvastamisel sisestatakse sinna kontoandmed automaatselt." }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "Häkitud või ebausaldusväärsed veebilehed võivad lehe laadimisel automaatset sisestamist kuritarvitada." }, "learnMoreAboutAutofill": { - "message": "Learn more about auto-fill" + "message": "Rohkem infot automaattäite kohta" }, "defaultAutoFillOnPageLoad": { "message": "Vaikevalik kontoandmete täitmiseks" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Organisatsiooni alla kuuluvatele kirjetele ei ole ligipääsu. Kontakteeru oma organisatsiooni omanikuga." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Sisselogimine läbi $DOMAIN$", "placeholders": { @@ -2075,33 +2088,81 @@ "message": "Sisselogimine on käivitatud" }, "exposedMasterPassword": { - "message": "Exposed Master Password" + "message": "Ülemparool on haavatav" }, "exposedMasterPasswordDesc": { - "message": "Password found in a data breach. Use a unique password to protect your account. Are you sure you want to use an exposed password?" + "message": "Ülemparool on varasemalt lekkinud. Kasuta konto kaitsmiseks unikaalset parooli. Oled kindel, et soovid kasutada varem lekkinud parooli?" }, "weakAndExposedMasterPassword": { - "message": "Weak and Exposed Master Password" + "message": "Nõrk ja haavatav ülemparool" }, "weakAndBreachedMasterPasswordDesc": { - "message": "Weak password identified and found in a data breach. Use a strong and unique password to protect your account. Are you sure you want to use this password?" + "message": "Tuvastati nõrk ning andmelekkes lekkinud ülemparool. Kasuta konto paremaks turvamiseks tugevamat parooli. Oled kindel, et soovid nõrga parooliga jätkata?" }, "checkForBreaches": { - "message": "Check known data breaches for this password" + "message": "Otsi seda parooli teadaolevatest andmeleketest" }, "important": { - "message": "Important:" + "message": "Tähtis:" }, "masterPasswordHint": { - "message": "Your master password cannot be recovered if you forget it!" + "message": "Ülemparooli ei saa taastada, kui sa selle unustama peaksid!" }, "characterMinimum": { - "message": "$LENGTH$ character minimum", + "message": "Minimaalselt $LENGTH$ tähemärki", "placeholders": { "length": { "content": "$1", "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Sinu organisatsioon ei võimalda lehe laadimisel automaatset kontoandmete täitmist kasutada." + }, + "howToAutofill": { + "message": "Kuidas automaatselt täita" + }, + "autofillSelectInfoWithCommand": { + "message": "Vali sellele lehelt kirje või kasuta otseteed: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Vali sellelt lehelt kirje või määra seadetes otsetee." + }, + "gotIt": { + "message": "Selge" + }, + "autofillSettings": { + "message": "Automaattäite seaded" + }, + "autofillShortcut": { + "message": "Automaattäite klaviatuuri otseteed" + }, + "autofillShortcutNotSet": { + "message": "Automaattäite otsetee pole määratud. Muuda seda brauseri seadetes." + }, + "autofillShortcutText": { + "message": "Automaattäite otsetee on: $COMMAND$. Saad seda brauseri seadetes muuta.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Vaike automaattäite otsetee on: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index 9586eeb4657..c78a06f4695 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Laguntza eta iritziak" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Sinkronizatu" }, @@ -430,7 +439,14 @@ "message": "Pasahitz nagusia berridaztea derrigorrezkoa da." }, "masterPasswordMinlength": { - "message": "Pasahitz nagusiak gutxienez 8 karaktere izan behar ditu." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Pasahitz nagusiaren egiaztatzea ez dator bat." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Ezin da sartu desgaitutako erakundeetako elementuetara. Laguntza lortzeko, jarri harremanetan zure erakundearekin." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "$DOMAIN$-en saioa hasten", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index 9e8981b18cb..b6de4e918db 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "کمک و بازخورد" }, + "helpCenter": { + "message": "مرکز راهنمایی Bitwarden" + }, + "communityForums": { + "message": "انجمن‌های Bitwarden را کاوش کنید" + }, + "contactSupport": { + "message": "پیام به پشتیبانیBitwarden" + }, "sync": { "message": "همگام‌سازی" }, @@ -430,7 +439,14 @@ "message": "نوشتن مجدد کلمه عبور اصلی ضروری است." }, "masterPasswordMinlength": { - "message": "طول کلمه عبور اصلی باید حداقل ۸ کاراکتر باشد." + "message": "طول کلمه عبور اصلی باید حداقل $VALUE$ کاراکتر باشد.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "کلمه عبور اصلی با تکرار آن مطابقت ندارد." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "موارد موجود در سازمان‌های غیرفعال، قابل دسترسی نیستند. برای دریافت کمک با مالک سازمان خود تماس بگیرید." }, - "cardBrandMir": { - "message": "میر" - }, "loggingInTo": { "message": "ورود به $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "خط مشی‌های سازمان شما پر کردن خودکار هنگام بارگیری صفحه را روشن کرده است." + }, + "howToAutofill": { + "message": "نحوه پر کردن خودکار" + }, + "autofillSelectInfoWithCommand": { + "message": "یک مورد را از این صفحه انتخاب کنید یا از میانبر استفاده کنید: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "یک مورد را از این صفحه انتخاب کنید یا یک میانبر در تنظیمات تنظیم کنید." + }, + "gotIt": { + "message": "متوجه شدم" + }, + "autofillSettings": { + "message": "تنظیمات پر کردن خودکار" + }, + "autofillShortcut": { + "message": "میانبر صفحه کلید پر کردن خودکار" + }, + "autofillShortcutNotSet": { + "message": "میانبر پر کردن خودکار تنظیم نشده است. این را در تنظیمات مرورگر تغییر دهید." + }, + "autofillShortcutText": { + "message": "میانبر پر کردن خودکار: $COMMAND$ است. این را در تنظیمات مرورگر تغییر دهید.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "میانبر پر کردن خودکار پیش‌فرض: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index b634fb09f48..2416012882c 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Tuki ja palaute" }, + "helpCenter": { + "message": "Bitwardenin Tukikeskus" + }, + "communityForums": { + "message": "Tutustu Bitwardenin keskustelualueeseen" + }, + "contactSupport": { + "message": "Ota yhteyttä Bitwardenin asiakaspalveluun" + }, "sync": { "message": "Synkronointi" }, @@ -430,7 +439,14 @@ "message": "Pääsalasanan uudelleensyöttö vaaditaan." }, "masterPasswordMinlength": { - "message": "Pääsalasanan tulee sisältää ainakin 8 merkkiä." + "message": "Pääsalasanan tulee sisältää vähintään $VALUE$ merkkiä.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Pääsalasanan vahvistus ei täsmää." @@ -458,7 +474,7 @@ } }, "autofillError": { - "message": "Valitttua kohdetta ei voitu täyttää tälle sivulle automaattisesti. Kopioi ja liitä tiedot itse." + "message": "Valittua kohdetta ei voitu täyttää tälle sivulle automaattisesti. Kopioi ja liitä tiedot itse." }, "loggedOut": { "message": "Kirjauduttu ulos" @@ -780,7 +796,7 @@ "message": "Kaksivaiheisen kirjautumisen (2FA) TOTP-todennuskoodien generaattori holvisi kirjautumistiedoille." }, "ppremiumSignUpSupport": { - "message": "Ensisijainen asiakastuki." + "message": "Ensisijainen asiakaspalvelu." }, "ppremiumSignUpFuture": { "message": "Kaikki tulossa olevat Premium-toiminnot. Lisää tulossa pian!" @@ -963,7 +979,7 @@ "message": "Vaarantuneet tai epäluotettavat sivustot voivat väärinkäyttää sivun avautuessa suoritettavaa automaattista täyttöä." }, "learnMoreAboutAutofill": { - "message": "Lue lisää automaattisesta täytöstä" + "message": "Lisätietoja automaattisesta täytöstä" }, "defaultAutoFillOnPageLoad": { "message": "Automaattisen täytön oletusasetus kirjautumistiedoille" @@ -1847,7 +1863,7 @@ "message": "Minuuttia" }, "vaultTimeoutPolicyInEffect": { - "message": "Organisaatiokäytännöt vaikuttavat holvin aikakatkaisuun. Suurin sallittu aika on $HOURS$ tunti(a) ja $MINUTES$ minuutti(a)", + "message": "Organisaatiokäytännöt vaikuttavat holvisi aikakatkaisuun. Suurin sallittu aika on $HOURS$ tunti(a) ja $MINUTES$ minuutti(a).", "placeholders": { "hours": { "content": "$1", @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Käytöstä poistettujen organisaatioiden kohteet eivät ole käytettävissä. Ole yhteydessä organisaation omistajaan saadaksesi apua." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Kirjaudutaan palveluun $DOMAIN$", "placeholders": { @@ -2093,7 +2106,7 @@ "message": "Tärkeää:" }, "masterPasswordHint": { - "message": "Pääsalasanan palautus ei ole mahdollista, jos unohdat sen!" + "message": "Pääsalasanasi palauttaminen ei ole mahdollista, jos unohdat sen!" }, "characterMinimum": { "message": "Vähintään $LENGTH$ merkkiä", @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Organisaatiokäytännöt ovat poistaneet käytöstä automaattisen täytön sivun avautuessa." + }, + "howToAutofill": { + "message": "Miten täytetään automaattisesti" + }, + "autofillSelectInfoWithCommand": { + "message": "Valitse tälle sivulle sopiva kohde tai käytä pikanäppäintä $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Valitse tälle sivulle sopiva kohde tai määritä pikanäppäin asetuksista." + }, + "gotIt": { + "message": "Selvä" + }, + "autofillSettings": { + "message": "Täytön asetukset" + }, + "autofillShortcut": { + "message": "Automaattisen täytön pikanäppäin" + }, + "autofillShortcutNotSet": { + "message": "Automaattisen täytön pikanäppäintä ei ole määritetty. Määritä se selaimen asetuksista." + }, + "autofillShortcutText": { + "message": "Automaattisen täytön pikanäppäin on $COMMAND$. Vaihda se selaimen asetuksista.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Automaattisen täytön oletuspikanäppäin on $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json index 49bdbb26b7a..115086b5df4 100644 --- a/apps/browser/src/_locales/fil/messages.json +++ b/apps/browser/src/_locales/fil/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Tulong at Mga Feedback" }, + "helpCenter": { + "message": "Bitwarden Tulong sentro" + }, + "communityForums": { + "message": "I-eksplorang Bitwarden komunidad na mga forum" + }, + "contactSupport": { + "message": "Kontakin ang Bitwarden suporta" + }, "sync": { "message": "Ikintal" }, @@ -430,7 +439,14 @@ "message": "Kinakailangan ang ulitin ang master password." }, "masterPasswordMinlength": { - "message": "Ang master password ay dapat hindi bababa sa 8 na mga character." + "message": "Ang master password ay dapat na hindi bababa sa $VALUE$ na mga character.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Hindi tumutugma ang kumpirmasyon ng master password." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Mga item sa mga naka-suspindong Organisasyon ay hindi ma-access. Mangyaring makipag-ugnayan sa may-ari ng iyong Organisasyon para sa tulong." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Nag-lolog in sa $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Ang mga patakaran ng iyong organisasyon ay nagbigay ng pag-automatikong pag-load sa pahina." + }, + "howToAutofill": { + "message": "Paano mag-auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Nakuha ko" + }, + "autofillSettings": { + "message": "Mga setting ng auto-fill" + }, + "autofillShortcut": { + "message": "Keyboard shortcut para sa auto-fill" + }, + "autofillShortcutNotSet": { + "message": "Hindi naka-set ang shortcut ng auto-fill. Baguhin ito sa mga setting ng browser." + }, + "autofillShortcutText": { + "message": "Ang shortcut ng auto-fill ay: $COMMAND$. Baguhin ito sa mga setting ng browser.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default shortcut ng auto-fill: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json index 91afabda3f8..0282662a4a7 100644 --- a/apps/browser/src/_locales/fr/messages.json +++ b/apps/browser/src/_locales/fr/messages.json @@ -110,7 +110,7 @@ "message": "Il n'y a pas d'identifiants disponibles à saisir automatiquement pour l'onglet actuel du navigateur." }, "addLogin": { - "message": "Ajouter un site" + "message": "Ajouter un identifiant" }, "addItem": { "message": "Ajouter un élément" @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Aide et commentaires" }, + "helpCenter": { + "message": "Centre d'aide Bitwarden" + }, + "communityForums": { + "message": "Explorez les forums de la communauté Bitwarden" + }, + "contactSupport": { + "message": "Contacter le support Bitwarden" + }, "sync": { "message": "Synchroniser" }, @@ -215,7 +224,7 @@ "message": "Générer automatiquement des mots de passe robustes et uniques pour vos identifiants." }, "bitWebVault": { - "message": "Coffre en ligne de bitwarden" + "message": "Coffre web bitwarden" }, "importItems": { "message": "Importer des éléments" @@ -339,7 +348,7 @@ "message": "Votre navigateur web ne supporte pas la copie rapide depuis le presse-papier. Copiez-le manuellement à la place." }, "verifyIdentity": { - "message": "Confirmer votre identité" + "message": "Vérifier l'identité" }, "yourVaultIsLocked": { "message": "Votre coffre est verrouillé. Vérifiez votre identité pour continuer." @@ -430,7 +439,14 @@ "message": "Une nouvelle saisie du mot de passe principal est nécessaire." }, "masterPasswordMinlength": { - "message": "Le mot de passe principal doit comporter au moins 8 caractères." + "message": "Le mot de passe principal doit comporter au moins $VALUE$ caractères.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "La confirmation du mot de passe principal ne correspond pas." @@ -552,7 +568,7 @@ "message": "Êtes-vous sûr de vouloir écraser le mot de passe actuel ?" }, "overwriteUsername": { - "message": "Remplacer le nom d'utilisateur" + "message": "Écraser le nom d'utilisateur" }, "overwriteUsernameConfirmation": { "message": "Êtes-vous sûr(e) de vouloir remplacer le nom d'utilisateur actuel ?" @@ -567,7 +583,7 @@ "message": "Rechercher dans le type" }, "noneFolder": { - "message": "Pas de dossier", + "message": "Aucun dossier", "description": "This is the folder for uncategorized items" }, "enableAddLoginNotification": { @@ -873,7 +889,7 @@ "message": "Identifiant non disponible" }, "noTwoStepProviders": { - "message": "Ce compte dispose d'une authentification à deux facteurs mise en place, mais aucun des fournisseurs d'authentification à deux facteurs configurés ne sont pris en charge par ce navigateur web." + "message": "Ce compte dispose d'une authentification à deux facteurs de configurée, cependant, aucun des fournisseurs à deux facteurs configurés n'est pris en charge par ce navigateur web." }, "noTwoStepProviders2": { "message": "Merci d'utiliser un navigateur web compatible (comme Chrome) et/ou d'ajouter des services additionnels d'identification en deux étapes qui sont mieux supportés par les navigateurs web (comme par exemple une application d'authentification)." @@ -1136,7 +1152,7 @@ "message": "Deuxième prénom" }, "lastName": { - "message": "Nom" + "message": "Nom de famille" }, "fullName": { "message": "Nom et prénom" @@ -1396,7 +1412,7 @@ "message": "Cloner" }, "passwordGeneratorPolicyInEffect": { - "message": "Une ou plusieurs politiques d'organisation affectent les paramètres de votre générateur." + "message": "Une ou plusieurs politiques de sécurité de l'organisation affectent les paramètres de votre générateur." }, "vaultTimeoutAction": { "message": "Action après délai d'expiration du coffre" @@ -1449,7 +1465,7 @@ "message": "Définir le mot de passe principal" }, "masterPasswordPolicyInEffect": { - "message": "Une ou plusieurs politiques de l'organisation exigent que votre mot de passe principal réponde aux exigences suivantes :" + "message": "Une ou plusieurs politiques de sécurité de l'organisation exigent que votre mot de passe principal réponde aux exigences suivantes :" }, "policyInEffectMinComplexity": { "message": "Score de complexité minimum de $SCORE$", @@ -1491,10 +1507,10 @@ "message": "Votre nouveau mot de passe principal ne répond pas aux exigences en matière de politique de sécurité." }, "acceptPolicies": { - "message": "En cochant cette case, vous acceptez les éléments suivants :" + "message": "En cochant cette case vous acceptez ce qui suit :" }, "acceptPoliciesRequired": { - "message": "Les Conditions d'Utilisation et la Politique de Confidentialité n'ont pas été acceptées." + "message": "Les conditions d'utilisation et la politique de confidentialité n'ont pas été acceptées." }, "termsOfService": { "message": "Conditions d'utilisation" @@ -1802,7 +1818,7 @@ "message": "Masquer mon adresse électronique aux destinataires." }, "sendOptionsPolicyInEffect": { - "message": "Une ou plusieurs politiques d'organisation affectent vos options Send." + "message": "Une ou plusieurs politiques de sécurité de l'organisation affectent vos options Send." }, "passwordPrompt": { "message": "Ressaisir le mot de passe principal" @@ -1847,7 +1863,7 @@ "message": "Minutes" }, "vaultTimeoutPolicyInEffect": { - "message": "Les politiques de votre organisation affectent le délai d'expiration de votre coffre-fort. Le délai d'expiration maximal autorisé est de $HOURS$ heure(s) et $MINUTES$ minute(s)", + "message": "Les politiques de sécurité de votre organisation affectent le délai d'expiration de votre coffre. Le délai d'expiration autorisé du coffre est de $HOURS$ heure(s) et $MINUTES$ minute(s) maximum", "placeholders": { "hours": { "content": "$1", @@ -1866,7 +1882,7 @@ "message": "Export du coffre désactivé" }, "personalVaultExportPolicyInEffect": { - "message": "Une ou plusieurs politiques d'organisation vous empêchent d'exporter votre coffre personnel." + "message": "Une ou plusieurs politiques de sécurité de l'organisation vous empêchent d'exporter votre coffre individuel." }, "copyCustomFieldNameInvalidElement": { "message": "Aucun élément de formulaire valide n'a pu être identifié. Essayez plutôt d'inspecter le HTML." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Les éléments des organisations suspendues ne sont pas accessibles. Contactez le propriétaire de votre organisation pour obtenir de l'aide." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Connexion à $DOMAIN$", "placeholders": { @@ -2051,28 +2064,28 @@ "message": "Se souvenir du courriel" }, "loginWithDevice": { - "message": "Log in with device" + "message": "Se connecter avec l'appareil" }, "loginWithDeviceEnabledInfo": { - "message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?" + "message": "La connexion avec l'appareil doit être configurée dans les paramètres de l'application Bitwarden. Besoin d'une autre option ?" }, "fingerprintPhraseHeader": { - "message": "Fingerprint phrase" + "message": "Phrase d'empreinte" }, "fingerprintMatchInfo": { - "message": "Please make sure your vault is unlocked and the Fingerprint phrase matches on the other device." + "message": "Veuillez vous assurer que votre coffre est déverrouillé et que la phrase d'empreinte correspond à celle de l'autre appareil." }, "resendNotification": { - "message": "Resend notification" + "message": "Renvoyer la notification" }, "viewAllLoginOptions": { - "message": "View all log in options" + "message": "Afficher toutes les options de connexion" }, "notificationSentDevice": { - "message": "A notification has been sent to your device." + "message": "Une notification a été envoyée à votre appareil." }, "logInInitiated": { - "message": "Log in initiated" + "message": "Connexion initiée" }, "exposedMasterPassword": { "message": "Mot de passe principal exposé" @@ -2096,12 +2109,60 @@ "message": "Votre mot de passe principal ne peut pas être récupéré si vous l'oubliez !" }, "characterMinimum": { - "message": "Caractère minimum $LENGTH$", + "message": "$LENGTH$ caractère minimum", "placeholders": { "length": { "content": "$1", "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Les politiques de sécurité de votre organisation ont activé la saisie automatique lors du chargement de la page." + }, + "howToAutofill": { + "message": "Comment saisir automatiquement" + }, + "autofillSelectInfoWithCommand": { + "message": "Sélectionnez un élément depuis cette page ou utilisez le raccourci : $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Sélectionnez un élément depuis cette page ou définissez un raccourci dans les paramètres." + }, + "gotIt": { + "message": "Compris" + }, + "autofillSettings": { + "message": "Paramètres de saisie automatique" + }, + "autofillShortcut": { + "message": "Raccourci clavier de saisie automatique" + }, + "autofillShortcutNotSet": { + "message": "Le raccourci de saisie automatique n'est pas défini. Changez-le dans les paramètres du navigateur." + }, + "autofillShortcutText": { + "message": "Le raccourci de saisie automatique est : $COMMAND$. Changez-le dans les paramètres du navigateur.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Raccourci de saisie automatique par défaut : $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/gl/messages.json b/apps/browser/src/_locales/gl/messages.json index 9c228a74174..8f6d3d0da96 100644 --- a/apps/browser/src/_locales/gl/messages.json +++ b/apps/browser/src/_locales/gl/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Help & feedback" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Sync" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Master password confirmation does not match." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json index 969d7017bdb..1d9d9f58817 100644 --- a/apps/browser/src/_locales/he/messages.json +++ b/apps/browser/src/_locales/he/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "עזרה ומשוב" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "סנכרן" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "שדה אימות סיסמה ראשית לא תואם." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json index f11f2caa553..26f585f2c56 100644 --- a/apps/browser/src/_locales/hi/messages.json +++ b/apps/browser/src/_locales/hi/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Help & Feedback" }, + "helpCenter": { + "message": "बिटवॉर्डेन सहायता केंद्र" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "बिटवॉर्डेन सहायता से संपर्क करें" + }, "sync": { "message": "सिंक" }, @@ -348,7 +357,7 @@ "message": "ताला खोलें" }, "loggedInAsOn": { - "message": "पर के रूप में लॉग इन किया ।", + "message": "$HOSTNAME$ पर $EMAIL$ के रूप में लॉग इन किया है।", "placeholders": { "email": { "content": "$1", @@ -430,7 +439,14 @@ "message": "मास्टर पासवर्ड पुनः डालने की आवश्यकता है।" }, "masterPasswordMinlength": { - "message": "मास्टर पासवर्ड कम से कम 8 वर्ण लंबा होना चाहिए।" + "message": "मास्टर पासवर्ड कम से कम $VALUE$ अक्षर लंबा होना चाहिए।", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "मास्टर पासवर्ड पुष्टि मेल नहीं खाती है।" @@ -448,7 +464,7 @@ "message": "सत्यापन कोड अवैध है" }, "valueCopied": { - "message": " copied", + "message": "$VALUE$ कॉपी हो गया है।", "description": "Value has been copied to the clipboard.", "placeholders": { "value": { @@ -798,7 +814,7 @@ "message": "Thank you for supporting bitwarden." }, "premiumPrice": { - "message": "All for just %price% /year!", + "message": "All for just $PRICE$ /year!", "placeholders": { "price": { "content": "$1", @@ -828,7 +844,7 @@ "message": "अपने ऑथेंटिकेटर ऐप से 6 डिजिट वेरिफिकेशन कोड डालें।" }, "enterVerificationCodeEmail": { - "message": "Enter the 6 digit verification code that was emailed to", + "message": "Enter the 6 digit verification code that was emailed to $EMAIL$.", "placeholders": { "email": { "content": "$1", @@ -1242,7 +1258,7 @@ "message": "चेक करें कि पासवर्ड सामने आ गया है या नहीं।" }, "passwordExposed": { - "message": "This password has been exposed in data breaches. You should change it.", + "message": "This password has been exposed $VALUE$ time(s) in data breaches. You should change it.", "placeholders": { "value": { "content": "$1", @@ -1581,7 +1597,7 @@ "message": "बिटवर्डन इन डोमेन के लिए लॉगिन विवरण सहेजने के लिए नहीं कहेगा।परिवर्तनों को प्रभावी बनाने के लिए आपको पृष्ठ को ताज़ा करना होगा |" }, "excludedDomainsInvalidDomain": { - "message": "$DOMAIN $ एक वैध डोमेन नहीं है", + "message": "$DOMAIN$ is not a valid domain", "placeholders": { "domain": { "content": "$1", @@ -1692,7 +1708,7 @@ "message": "1 दिन" }, "days": { - "message": "#DAYS# दिन", + "message": "$DAYS$ days", "placeholders": { "days": { "content": "$1", @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "ऑटो-फ़िल कैसे करें" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json index e85047bceaa..6bd20c6c997 100644 --- a/apps/browser/src/_locales/hr/messages.json +++ b/apps/browser/src/_locales/hr/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Pomoć i povratne informacije" }, + "helpCenter": { + "message": "Bitwarden centar za pomoć" + }, + "communityForums": { + "message": "Istraži forume zajednice Bitwarden" + }, + "contactSupport": { + "message": "Kontaktiraj Bitwarden pomoć" + }, "sync": { "message": "Sinkronizacija" }, @@ -430,7 +439,14 @@ "message": "Potreban je ponovni unos glavne lozinke." }, "masterPasswordMinlength": { - "message": "Glavna lozinka mora imati najmanje 8 znakova." + "message": "Glavna lozinka mora imati najmanje $VALUE$ znakova.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Potvrda glavne lozinke se ne podudara." @@ -960,10 +976,10 @@ "message": "Nakon učitavanja web stranice, ako je otkriven obrazac za prijavu, auto-ispuni." }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "Ugrožene ili nepouzdane web stranice mogu iskoristiti auto-ispunu prilikom učitavanja stranice." }, "learnMoreAboutAutofill": { - "message": "Learn more about auto-fill" + "message": "Saznaj više o auto-ispuni" }, "defaultAutoFillOnPageLoad": { "message": "Zadana postvaka Auto-ispune za prijave" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Stavkama u suspendiranoj Organizaciji se ne može pristupiti. Kontaktiraj vlasnika Organizacije za pomoć." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Prijava u $DOMAIN$", "placeholders": { @@ -2051,57 +2064,105 @@ "message": "Zapamti adresu e-pošte" }, "loginWithDevice": { - "message": "Log in with device" + "message": "Prijava uređajem" }, "loginWithDeviceEnabledInfo": { - "message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?" + "message": "Prijava uređajem mora biti namještena u postavka Bitwarden mobilne aplikacije. Trebaš drugu opciju?" }, "fingerprintPhraseHeader": { - "message": "Fingerprint phrase" + "message": "Jedinstvena fraza" }, "fingerprintMatchInfo": { - "message": "Please make sure your vault is unlocked and the Fingerprint phrase matches on the other device." + "message": "Provjeri je li trezor otključan i slaže li se jedinstvena fraza s drugim uređajem." }, "resendNotification": { - "message": "Resend notification" + "message": "Ponovno pošalji obavijest" }, "viewAllLoginOptions": { - "message": "View all log in options" + "message": "Pogledaj sve mogućnosti prijave" }, "notificationSentDevice": { - "message": "A notification has been sent to your device." + "message": "Obavijest je poslana na tvoj uređaj." }, "logInInitiated": { - "message": "Log in initiated" + "message": "Pokrenuta prijava" }, "exposedMasterPassword": { - "message": "Exposed Master Password" + "message": "Ukradena glavna lozinka" }, "exposedMasterPasswordDesc": { - "message": "Password found in a data breach. Use a unique password to protect your account. Are you sure you want to use an exposed password?" + "message": "Lozinka je nađena među ukradenima tijekom krađa podataka. Za zaštitu svog računa koristi jedinstvenu lozinku. Želiš li svejedno korisiti ukradenu lozinku?" }, "weakAndExposedMasterPassword": { - "message": "Weak and Exposed Master Password" + "message": "Slaba i ukradena glavna lozinka" }, "weakAndBreachedMasterPasswordDesc": { - "message": "Weak password identified and found in a data breach. Use a strong and unique password to protect your account. Are you sure you want to use this password?" + "message": "Slaba lozinka je nađena među ukradenima tijekom krađa podataka. Za zaštitu svog računa koristi jaku i jedinstvenu lozinku. Želiš li svejedno korisiti slabu, ukradenu lozinku?" }, "checkForBreaches": { - "message": "Check known data breaches for this password" + "message": "Provjeri je li lozinka ukradena prilikom krađe podataka" }, "important": { - "message": "Important:" + "message": "Važno:" }, "masterPasswordHint": { - "message": "Your master password cannot be recovered if you forget it!" + "message": "Glavnu lozinku nije moguće oporaviti ako ju zaboraviš!" }, "characterMinimum": { - "message": "$LENGTH$ character minimum", + "message": "najmanje $LENGTH$ znakova", "placeholders": { "length": { "content": "$1", "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Prema pravilima tvoje organizacije uključena je auto-ispuna prilikom učitavanja stranice." + }, + "howToAutofill": { + "message": "Kako auto-ispuniti" + }, + "autofillSelectInfoWithCommand": { + "message": "Odaberi stavku s ove stranice ili koristi prečac $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Odaberi stavku s ove stranice ili namjesti prečac u postavkama." + }, + "gotIt": { + "message": "U redu" + }, + "autofillSettings": { + "message": "Postavke auto-ispune" + }, + "autofillShortcut": { + "message": "Tipkovnički precač auto-ispune" + }, + "autofillShortcutNotSet": { + "message": "Prečac auto-ispune nije postavljen. Promijeni u postavkama preglednika." + }, + "autofillShortcutText": { + "message": "Prečac auto-ispune je: $COMMAND$. Promijeni u postavkama preglednika.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Zadani prečac auto-ispune: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json index 0ee4ea3a5cc..53d55539dc1 100644 --- a/apps/browser/src/_locales/hu/messages.json +++ b/apps/browser/src/_locales/hu/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Súgó és visszajelzés" }, + "helpCenter": { + "message": "Bitwardsn Segítségközpont" + }, + "communityForums": { + "message": "Bitwarden közösségi fórum felfedezése" + }, + "contactSupport": { + "message": "Kapcsolatfelvétel a Bitwarden támogatással" + }, "sync": { "message": "Szinkronizálás" }, @@ -430,7 +439,14 @@ "message": "A mesterjelszó ismételt megadása kötelező." }, "masterPasswordMinlength": { - "message": "Mesterjelszónak legalább 8 karakter hosszúnak kell lennie." + "message": "A mesterjelszónak legalább $VALUE$ karakter hosszúnak kell lennie.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "A megadott két jelszó nem egyezik meg." @@ -960,7 +976,7 @@ "message": "Ha egy bejelentkezési űrlap észlelésre került, az adatok automatikus kitöltése az oldal betöltésekor." }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "Az oldalbetöltésnél automatikus kitöltést a feltört vagy nem megbízhatató weboldalak kihasználhatják." }, "learnMoreAboutAutofill": { "message": "További információk az automatikus kitöltésről" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "A letiltott szervezetek elemei nem érhetők el. Vegyük fel a kapcsolatot a szervezet tulajdonosával segítségért." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Bejelentkezés $DOMAIN$ területre", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "A szervezeti szabályzat bekapcsolta az automatikus kitöltést az oldalbetöltéskor." + }, + "howToAutofill": { + "message": "Az automatikus kitöltés működése" + }, + "autofillSelectInfoWithCommand": { + "message": "Válasszunk egy elemet ezen az oldalon vagy használjuk a parancsikont: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Válasszunk egy elemet ezen az oldalon vagy állítsunk be parancsikont a beállításokban." + }, + "gotIt": { + "message": "Rendben" + }, + "autofillSettings": { + "message": "Automatikus kitöltés beállítások" + }, + "autofillShortcut": { + "message": "Automatikus kitöltés billentyűparancs" + }, + "autofillShortcutNotSet": { + "message": "Az automatikus kitöltés billentyűzetparancs nincs beállítva. Módosítsuk ezt a böngésző beállításaiban." + }, + "autofillShortcutText": { + "message": "Az automatikus kitöltés billentyűparancsa: $COMMAND$. Módosítsuk ezt a böngésző beállításaiban.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Alapértelmezett automatikus kitöltési billenytűparancs: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json index 4a7a6cedc68..55e2e9cab74 100644 --- a/apps/browser/src/_locales/id/messages.json +++ b/apps/browser/src/_locales/id/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Bantuan & Umpan Balik" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Sinkronisasi" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Kata sandi utama harus memiliki panjang setidaknya 8 karakter." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Konfirmasi sandi utama tidak cocok." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index a05d1e9dff1..025fcba0923 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -3,7 +3,7 @@ "message": "Bitwarden" }, "extName": { - "message": "Bitwarden - Gestore di password gratuito", + "message": "Bitwarden - Gestore di Password Gratuito", "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { @@ -38,16 +38,16 @@ "message": "Password principale" }, "masterPassDesc": { - "message": "La password principale è la password che utilizzi per accedere alla tua cassaforte. È molto importante che tu non la dimentichi. Non c'è modo di recuperare questa password nel caso che tu la dimenticassi." + "message": "La password principale ti serve per accedere alla tua cassaforte. È molto importante non dimenticarla. Non possiamo aiutarti a recuperare questa password se la dimentichi." }, "masterPassHintDesc": { - "message": "Un suggerimento per la password principale può aiutarti a ricordarla nel caso la dimenticassi." + "message": "Un suggerimento per la password principale può aiutarti a ricordarla se la dimentichi." }, "reTypeMasterPass": { - "message": "Ri-digita la tua password principale" + "message": "Digita nuovamente la password" }, "masterPassHint": { - "message": "Suggerimento password principale (facoltativo)" + "message": "Suggerimento per la password principale (facoltativo)" }, "tab": { "message": "Scheda" @@ -56,7 +56,7 @@ "message": "Cassaforte" }, "myVault": { - "message": "Cassaforte" + "message": "La mia cassaforte" }, "allVaults": { "message": "Tutte le casseforti" @@ -68,7 +68,7 @@ "message": "Impostazioni" }, "currentTab": { - "message": "Scheda attuale" + "message": "Scheda corrente" }, "copyPassword": { "message": "Copia password" @@ -86,19 +86,19 @@ "message": "Copia numero" }, "copySecurityCode": { - "message": "Copia il codice di sicurezza" + "message": "Copia codice di sicurezza" }, "autoFill": { - "message": "Auto-riempimento" + "message": "Riempimento automatico" }, "generatePasswordCopied": { - "message": "Genera password (copiata)" + "message": "Genera password e copiala" }, "copyElementIdentifier": { "message": "Copia nome campo personalizzato" }, "noMatchingLogins": { - "message": "Nessun accesso corrispondente." + "message": "Nessun login corrispondente" }, "unlockVaultMenu": { "message": "Sblocca la tua cassaforte" @@ -107,7 +107,7 @@ "message": "Accedi alla tua cassaforte" }, "autoFillInfo": { - "message": "Non ci sono login disponibili per completare la scheda attuale del browser." + "message": "Non ci sono login disponibili per riempire automaticamente questa scheda del browser." }, "addLogin": { "message": "Aggiungi un login" @@ -119,10 +119,10 @@ "message": "Suggerimento password" }, "enterEmailToGetHint": { - "message": "Inserisci l'indirizzo email del tuo account per ricevere il suggerimento della password principale." + "message": "Inserisci l'indirizzo email del tuo account per ricevere il suggerimento per la password principale." }, "getMasterPasswordHint": { - "message": "Ottieni il suggerimento della password principale" + "message": "Ottieni suggerimento della password principale" }, "continue": { "message": "Continua" @@ -146,14 +146,14 @@ "message": "Account" }, "changeMasterPassword": { - "message": "Modifica password principale" + "message": "Cambia password principale" }, "fingerprintPhrase": { "message": "Frase impronta", "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "yourAccountsFingerprint": { - "message": "Frase impronta dell'account", + "message": "Frase impronta del tuo account", "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "twoStepLogin": { @@ -190,10 +190,19 @@ "message": "Cartelle" }, "noFolders": { - "message": "Non ci sono cartelle da elencare." + "message": "Non ci sono cartelle da mostrare." }, "helpFeedback": { - "message": "Aiuto e segnalazioni" + "message": "Aiuto e feedback" + }, + "helpCenter": { + "message": "Centro assistenza Bitwarden" + }, + "communityForums": { + "message": "Esplora i forum della comunità Bitwarden" + }, + "contactSupport": { + "message": "Contatta assistenza Bitwarden" }, "sync": { "message": "Sincronizza" @@ -279,10 +288,10 @@ "message": "Visualizza" }, "noItemsInList": { - "message": "Non ci sono elementi da elencare." + "message": "Non ci sono elementi da mostrare." }, "itemInformation": { - "message": "Informazioni sull'elemento" + "message": "Informazioni elemento" }, "username": { "message": "Nome utente" @@ -321,7 +330,7 @@ "message": "Sito web" }, "toggleVisibility": { - "message": "Mostra/Nascondi" + "message": "Mostra/nascondi" }, "manage": { "message": "Gestisci" @@ -333,16 +342,16 @@ "message": "Valuta l'estensione" }, "rateExtensionDesc": { - "message": "Prendi in considerazione l'idea di lasciarci una buona recensione!" + "message": "Aiutaci lasciando una buona recensione!" }, "browserNotSupportClipboard": { - "message": "Il tuo browser non supporta la copia dagli appunti. Copiala manualmente." + "message": "Il tuo browser non supporta copiare dagli appunti. Copialo manualmente." }, "verifyIdentity": { - "message": "Verifica l'identità." + "message": "Verifica identità" }, "yourVaultIsLocked": { - "message": "La tua cassaforte è bloccata. Inserisci la tua password principale per continuare." + "message": "La tua cassaforte è bloccata. Verifica la tua identità per continuare." }, "unlock": { "message": "Sblocca" @@ -367,7 +376,7 @@ "message": "Timeout cassaforte" }, "lockNow": { - "message": "Blocca" + "message": "Blocca ora" }, "immediately": { "message": "Immediatamente" @@ -418,22 +427,29 @@ "message": "Si è verificato un errore" }, "emailRequired": { - "message": "L'indirizzo email è obbligatorio." + "message": "Indirizzo email obbligatorio." }, "invalidEmail": { "message": "Indirizzo email non valido." }, "masterPasswordRequired": { - "message": "È necessario inserire la password principale." + "message": "Password principale obbligatoria." }, "confirmMasterPasswordRequired": { - "message": "È necessario reinserire la password principale." + "message": "Reinserire la password principale è obbligatorio." }, "masterPasswordMinlength": { - "message": "La password principale deve essere lunga almeno 8 caratteri." + "message": "La password principale deve essere lunga almeno $VALUE$ caratteri.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { - "message": "La conferma della password principale non corrisponde." + "message": "Le password principali non corrispondono." }, "newAccountCreated": { "message": "Il tuo nuovo account è stato creato! Ora puoi eseguire l'accesso." @@ -445,7 +461,7 @@ "message": "Il codice di verifica è obbligatorio." }, "invalidVerificationCode": { - "message": "Codice di verifica non valido." + "message": "Codice di verifica non valido" }, "valueCopied": { "message": "$VALUE$ copiata", @@ -458,7 +474,7 @@ } }, "autofillError": { - "message": "Impossibile completare automaticamente il login selezionato per questa pagina. Copia e incolla manualmente le tue credenziali." + "message": "Impossibile riempire automaticamente questo elemento nella pagina. Copia e incolla le credenziali." }, "loggedOut": { "message": "Disconnesso" @@ -485,19 +501,19 @@ "message": "Cartella aggiunta" }, "changeMasterPass": { - "message": "Modifica password principale" + "message": "Cambia password principale" }, "changeMasterPasswordConfirmation": { "message": "Puoi cambiare la tua password principale sulla cassaforte online di bitwarden.com. Vuoi visitare ora il sito?" }, "twoStepLoginConfirmation": { - "message": "L'autenticazione in due passaggi rende il tuo account più sicuro richiedendo di verificare il login con un altro dispositivo come una chiave di sicurezza, applicazione di autenticazione, SMS, telefonata o email. Può essere abilitata sulla cassaforte online di bitwarden.com. Vuoi visitare il sito ora?" + "message": "La verifica in due passaggi rende il tuo account più sicuro richiedendoti di verificare il tuo login usando un altro dispositivo come una chiave di sicurezza, applicazione di autenticazione, SMS, telefonata, o email. Può essere abilitata nella cassaforte web su bitwarden.com. Vuoi visitare il sito?" }, "editedFolder": { - "message": "Cartella modificata" + "message": "Cartella salvata" }, "deleteFolderConfirmation": { - "message": "Sei sicuro di voler modificare questa cartella?" + "message": "Sei sicuro di voler eliminare questa cartella?" }, "deletedFolder": { "message": "Cartella eliminata" @@ -537,13 +553,13 @@ "message": "Elemento aggiunto" }, "editedItem": { - "message": "Elemento modificato" + "message": "Elemento salvato" }, "deleteItemConfirmation": { - "message": "Sei sicuro di voler cestinare questo elemento?" + "message": "Sei sicuro di voler eliminare questo elemento?" }, "deletedItem": { - "message": "Elemento cestinato" + "message": "Elemento eliminato" }, "overwritePassword": { "message": "Sovrascrivi password" @@ -555,7 +571,7 @@ "message": "Sovrascrivi nome utente" }, "overwriteUsernameConfirmation": { - "message": "Sei sicuro di voler sovrascrivere il nome utente attuale?" + "message": "Sei sicuro di voler sovrascrivere il nome utente corrente?" }, "searchFolder": { "message": "Cerca nella cartella" @@ -564,68 +580,68 @@ "message": "Cerca nella raccolta" }, "searchType": { - "message": "Cerca tipo" + "message": "Cerca in questo tipo" }, "noneFolder": { "message": "Nessuna cartella", "description": "This is the folder for uncategorized items" }, "enableAddLoginNotification": { - "message": "Chiedi di aggiungere il login" + "message": "Chiedi di aggiungere nuovi login" }, "addLoginNotificationDesc": { - "message": "\"Aggiungi notifica di login\" richiede automaticamente di salvare i nuovi login nella tua cassaforte ogni volta che accedi per la prima volta." + "message": "Chiedi di aggiungere un nuovo elemento se non ce n'è uno nella tua cassaforte." }, "showCardsCurrentTab": { - "message": "Mostra le carte nella pagina delle schede" + "message": "Mostra le carte nella sezione Scheda" }, "showCardsCurrentTabDesc": { - "message": "Elenca le carte nella pagina della scheda per un facile completamento automatico." + "message": "Mostra le carte nella sezione Scheda per riempirle automaticamente." }, "showIdentitiesCurrentTab": { - "message": "Mostra le identità nella pagina della scheda" + "message": "Mostra le identità nella sezione Scheda" }, "showIdentitiesCurrentTabDesc": { - "message": "Elenca le carte nella pagina della scheda per un facile completamento automatico." + "message": "Mostra le identità nella sezione Scheda per riempirle automaticamente." }, "clearClipboard": { "message": "Cancella appunti", "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "clearClipboardDesc": { - "message": "Cancella automaticamente dagli appunti i valori copiati.", + "message": "Cancella automaticamente i valori copiati dagli appunti.", "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "notificationAddDesc": { "message": "Vuoi che Bitwarden ricordi questa password per te?" }, "notificationAddSave": { - "message": "Sì, salva ora" + "message": "Salva" }, "enableChangedPasswordNotification": { "message": "Chiedi di aggiornare il login esistente" }, "changedPasswordNotificationDesc": { - "message": "Chiedi di aggiornare la password di accesso quando viene rilevato un cambiamento su un sito web." + "message": "Chiedi di aggiornare la password di un login quando viene cambiata su un sito web." }, "notificationChangeDesc": { "message": "Vuoi aggiornare questa password in Bitwarden?" }, "notificationChangeSave": { - "message": "Sì, aggiorna ora" + "message": "Aggiorna" }, "enableContextMenuItem": { - "message": "Mostra le opzioni del menu contestuale" + "message": "Mostra opzioni nel menu contestuale" }, "contextMenuItemDesc": { - "message": "Utilizza un clic secondario per accedere alla generazione di password e login per il sito web. " + "message": "Utilizza un secondo clic per accedere alla generazione di password e login corrispondenti per il sito web. " }, "defaultUriMatchDetection": { "message": "Rilevamento corrispondenza URI predefinito", "description": "Default URI match detection for auto-fill." }, "defaultUriMatchDetectionDesc": { - "message": "Scegli il modo predefinito in cui il rilevamento della corrispondenza URI viene gestito per gli accessi quando si eseguono azioni come il riempimento automatico." + "message": "Scegli il modo predefinito in cui il rilevamento della corrispondenza URI viene gestito per i login quando si eseguono azioni come il riempimento automatico." }, "theme": { "message": "Tema" @@ -642,7 +658,7 @@ "description": "Light color" }, "solarizedDark": { - "message": "Solarizzato scuro", + "message": "Scuro solarizzato", "description": "'Solarized' is a noun and the name of a color scheme. It should not be translated." }, "exportVault": { @@ -662,10 +678,10 @@ "message": "Questa esportazione contiene i dati della tua cassaforte in un formato non cifrato. Non salvare o inviare il file esportato su canali non protetti (come la posta elettronica). Eliminalo immediatamente dopo l'utilizzo." }, "encExportKeyWarningDesc": { - "message": "Questa esportazione cifra i tuoi dati utilizzando la chiave di cifratura del tuo account. Se cambi la chiave di cifratura del tuo account, non sarai più in grado di decifrare il file esportato e sarà necessario eseguire una nuova esportazione." + "message": "Questa esportazione cripta i tuoi dati usando la chiave di criptografia del tuo account. Se cambi la chiave di criptografia del tuo account, non sarai più in grado di decifrare il file esportato dovrai eseguire una nuova esportazione." }, "encExportAccountWarningDesc": { - "message": "Le chiavi di cifratura dell'account sono uniche per ogni account utente Bitwarden, quindi non è possibile importare un'esportazione cifrata in un account diverso." + "message": "Le chiavi di criptografia dell'account sono uniche per ogni account Bitwarden, quindi non puoi importare un file di esportazione criptato in un account diverso." }, "exportMasterPassword": { "message": "Inserisci la tua password principale per esportare i dati della tua cassaforte." @@ -674,7 +690,7 @@ "message": "Condiviso" }, "learnOrg": { - "message": "Scopri le organizzazioni" + "message": "Ulteriori informazioni sulle organizzazioni" }, "learnOrgConfirmation": { "message": "Bitwarden ti permette di condividere gli elementi della tua cassaforte con altri usando un'organizzazione. Vuoi visitare il sito bitwarden.com per saperne di più?" @@ -699,10 +715,10 @@ } }, "moveToOrgDesc": { - "message": "Scegli un'organizzazione in cui desideri spostare questo elemento. Spostare in un'organizzazione trasferisce la proprietà dell'elemento all'organizzazione. Non sarai più il proprietario diretto di questo elemento una volta spostato." + "message": "Scegli un'organizzazione in cui vuoi spostare questo elemento. Spostare in un'organizzazione trasferisce la proprietà dell'elemento all'organizzazione. Non sarai più il proprietario diretto di questo elemento una volta spostato." }, "learnMore": { - "message": "Per saperne di più" + "message": "Ulteriori informazioni" }, "authenticatorKeyTotp": { "message": "Chiave di autenticazione (TOTP)" @@ -711,7 +727,7 @@ "message": "Codice di verifica (TOTP)" }, "copyVerificationCode": { - "message": "Copia il codice di verifica" + "message": "Copia codice di verifica" }, "attachments": { "message": "Allegati" @@ -732,49 +748,49 @@ "message": "Nessun allegato." }, "attachmentSaved": { - "message": "L'allegato è stato salvato." + "message": "Allegato salvato" }, "file": { "message": "File" }, "selectFile": { - "message": "Seleziona un file." + "message": "Seleziona un file" }, "maxFileSize": { "message": "La dimensione massima del file è 500 MB." }, "featureUnavailable": { - "message": "Funzione non disponibile" + "message": "Funzionalità non disponibile" }, "updateKey": { - "message": "Non puoi utilizzare questa funzione finché non aggiorni la tua chiave di cifratura." + "message": "Non puoi usare questa funzionalità finché non aggiorni la tua chiave di criptografia." }, "premiumMembership": { - "message": "Abbonamento premium" + "message": "Abbonamento Premium" }, "premiumManage": { "message": "Gestisci abbonamento" }, "premiumManageAlert": { - "message": "Puoi gestire il tuo abbonamento premium online su bitwarden.com. Vuoi visitare ora il sito?" + "message": "Puoi gestire il tuo abbonamento Premium usando la cassaforte web su bitwarden.com. Vuoi visitare il sito?" }, "premiumRefresh": { "message": "Aggiorna abbonamento" }, "premiumNotCurrentMember": { - "message": "Al momento non sei un membro premium." + "message": "Al momento non sei un membro Premium." }, "premiumSignUpAndGet": { - "message": "Iscriviti ad un abbonamento premium e ottieni:" + "message": "Passa a Premium e ottieni:" }, "ppremiumSignUpStorage": { - "message": "1 GB di spazio di archiviazione cifrato per gli allegati." + "message": "1 GB di spazio di archiviazione criptato per gli allegati." }, "ppremiumSignUpTwoStep": { - "message": "Opzioni addizionali di login in due passaggi come YubiKey, FIDO U2F, e Duo." + "message": "Più opzioni di verifica in due passaggi come YubiKey, FIDO U2F, e Duo." }, "ppremiumSignUpReports": { - "message": "Sicurezza delle password, integrità dell'account e resoconti sulla violazione di dati per mantenere sicura la tua cassaforte." + "message": "Sicurezza delle password, integrità dell'account, e rapporti su violazioni di dati per mantenere sicura la tua cassaforte." }, "ppremiumSignUpTotp": { "message": "Generatore di codice di verifica TOTP (2FA) per i login nella tua cassaforte." @@ -783,16 +799,16 @@ "message": "Supporto clienti prioritario." }, "ppremiumSignUpFuture": { - "message": "Tutte le funzioni Premium future. Nuove in arrivo!" + "message": "Tutte le prossime funzioni Premium. Nuove in arrivo!" }, "premiumPurchase": { - "message": "Acquista Premium" + "message": "Passa a Premium" }, "premiumPurchaseAlert": { - "message": "Puoi acquistare il tuo abbonamento premium online su bitwarden.com. Vuoi visitare ora il sito?" + "message": "Puoi acquistare il un abbonamento Premium dalla cassaforte web su bitwarden.com. Vuoi visitare il sito?" }, "premiumCurrentMember": { - "message": "Sei un membro premium!" + "message": "Sei un membro Premium!" }, "premiumCurrentMemberThanks": { "message": "Grazie per il tuo supporto a Bitwarden." @@ -813,22 +829,22 @@ "message": "Copia TOTP automaticamente" }, "disableAutoTotpCopyDesc": { - "message": "Se il login ha una chiave di autenticazione, il codice di verifica TOTP viene automaticamente copiato negli appunti ogni volta che si compila automaticamente l'accesso." + "message": "Se un login ha una chiave di autenticazione, copia automaticamente il codice di verifica TOTP negli appunti quando riempi automaticamente il login." }, "enableAutoBiometricsPrompt": { "message": "Richiedi dati biometrici all'avvio" }, "premiumRequired": { - "message": "Premium richiesto" + "message": "Premium necessario" }, "premiumRequiredDesc": { - "message": "Un abbonamento Premium è richiesto per utilizzare questa funzionalità." + "message": "Passa a Premium per utilizzare questa funzionalità." }, "enterVerificationCodeApp": { "message": "Inserisci il codice di verifica a 6 cifre dalla tua applicazione di autenticazione." }, "enterVerificationCodeEmail": { - "message": "Inserisci il codice di verifica a 6 cifrato inviato a $EMAIL$.", + "message": "Inserisci il codice di verifica a 6 cifre inviato a $EMAIL$.", "placeholders": { "email": { "content": "$1", @@ -852,7 +868,7 @@ "message": "Invia nuovamente l'email con il codice di verifica" }, "useAnotherTwoStepMethod": { - "message": "Usa un altro metodo di login in due passaggi" + "message": "Usa un altro metodo di verifica in due passaggi" }, "insertYubiKey": { "message": "Inserisci la tua YubiKey nella porta USB del computer, poi premi il suo pulsante." @@ -861,7 +877,7 @@ "message": "Inserisci la tua chiave di sicurezza nella porta USB del tuo computer. Se dispone di un pulsante, premilo." }, "webAuthnNewTab": { - "message": "Per avviare la verifica WebAuthn 2FA. Fare clic sul pulsante in basso per aprire una nuova scheda e seguire le istruzioni fornite nella nuova scheda. " + "message": "Per avviare la verifica WebAuthn 2FA. Clicca il pulsante qui sotto per aprire una nuova scheda e segui le istruzioni fornite nella nuova scheda." }, "webAuthnNewTabOpen": { "message": "Apri nuova scheda" @@ -873,16 +889,16 @@ "message": "Login non disponibile" }, "noTwoStepProviders": { - "message": "Questo account ha abilitato il login in due passaggi, ma nessuno dei provider configurati è supportato da questo browser web." + "message": "La verifica in due passaggi è abilitata per il tuo account, ma nessuno dei metodi configurati è supportato da questo browser." }, "noTwoStepProviders2": { - "message": "Utilizzare un browser web supportato (come Chrome) e/o aggiungere altri provider che sono supportati meglio da tutti i browser web (ad esempio un'applicazione di autenticazione)." + "message": "Usa un browser web supportato (come Chrome) e/o aggiungi altri metodi che sono supportati meglio da tutti i browser web (come un'applicazione di autenticazione)." }, "twoStepOptions": { - "message": "Opzioni di login in due passaggi" + "message": "Opzioni di verifica in due passaggi" }, "recoveryCodeDesc": { - "message": "Hai perso l'accesso a tutti i tuoi provider a due passaggi? Usa il tuo codice di recupero per disattivarli dal tuo account." + "message": "Hai perso l'accesso a tutti i tuoi metodi di verifica in due passaggi? Usa il tuo codice di recupero per disattivarli tutti dal tuo account." }, "recoveryCodeTitle": { "message": "Codice di recupero" @@ -891,7 +907,7 @@ "message": "Applicazione di autenticazione" }, "authenticatorAppDesc": { - "message": "Usa un'applicazione di autenticazione (come Authy o Google Authenticator) per generare codici di verifica a tempo.", + "message": "Usa un'applicazione di autenticazione (come Authy o Google Authenticator) per generare codici di verifica basati sul tempo.", "description": "'Authy' and 'Google Authenticator' are product names and should not be translated." }, "yubiKeyTitle": { @@ -924,7 +940,7 @@ "message": "Ambiente self-hosted" }, "selfHostedEnvironmentFooter": { - "message": "Specifica l'URL principale della tua installazione Bitwarden self-hosted." + "message": "Specifica l'URL principale della tua installazione self-hosted di Bitwarden." }, "customEnvironment": { "message": "Ambiente personalizzato" @@ -951,46 +967,46 @@ "message": "URL del server di icone" }, "environmentSaved": { - "message": "Gli URL dell'ambiente sono stati salvati." + "message": "URL dell'ambiente salvati" }, "enableAutoFillOnPageLoad": { - "message": "Abilita l'auto-completamento al caricamento della pagina" + "message": "Riempi automaticamente al caricamento della pagina" }, "enableAutoFillOnPageLoadDesc": { - "message": "Se viene rilevato un modulo di accesso, effettua un auto-completamento quando la pagina web si carica." + "message": "Se sono rilevati campi di login, riempili automaticamente quando la pagina si carica." }, "experimentalFeature": { - "message": "I siti web compromessi o non attendibili possono sfruttare l'autorizzazione all'inserimento automatico all'avvio della pagina." + "message": "Siti compromessi potrebbero sfruttare il riempimento automatico al caricamento della pagina." }, "learnMoreAboutAutofill": { - "message": "Ulteriori informazioni sul completamento automatico" + "message": "Ulteriori informazioni" }, "defaultAutoFillOnPageLoad": { - "message": "Impostazioni di completamento automatico predefinito per i login" + "message": "Impostazioni di riempimento automatico predefinito per i login" }, "defaultAutoFillOnPageLoadDesc": { - "message": "Dopo aver abilitato il completamento automatico al caricamento della pagina, è possibile abilitare o disabilitare la funzione per singoli login. Questa è l'impostazione predefinita per i login che non sono configurati separatamente." + "message": "Puoi disattivare il riempimento automatico al caricamento della pagina per singoli login dalla sezione Modifica elemento." }, "itemAutoFillOnPageLoad": { - "message": "Autocompletamento al caricamento della pagina (se abilitato nelle opzioni)" + "message": "Riempi automaticamente al caricamento della pagina (se abilitato in Impostazioni)" }, "autoFillOnPageLoadUseDefault": { "message": "Usa impostazione predefinita" }, "autoFillOnPageLoadYes": { - "message": "Autocompletamento al caricamento della pagina" + "message": "Riempi automaticamente al caricamento della pagina" }, "autoFillOnPageLoadNo": { - "message": "Non completare automaticamente al caricamento della pagina" + "message": "Non riempire automaticamente al caricamento della pagina" }, "commandOpenPopup": { - "message": "Apri popup cassaforte" + "message": "Apri cassaforte in un pop-up" }, "commandOpenSidebar": { - "message": "Apri la cassaforte nella barra laterale" + "message": "Apri cassaforte nella barra laterale" }, "commandAutofillDesc": { - "message": "Auto-completa con l'ultimo accesso utilizzato sul sito corrente" + "message": "Riempi automaticamente con l'ultimo login utilizzato sul sito corrente" }, "commandGeneratePasswordDesc": { "message": "Genera e copia una nuova password casuale negli appunti" @@ -1034,22 +1050,22 @@ "description": "This describes a value that is 'linked' (tied) to another value." }, "popup2faCloseMessage": { - "message": "Facendo clic all'esterno della finestra popup per controllare la mail con il codice di verifica chiuderà la finestra di popup. Vuoi aprire questo popup in una nuova finestra?" + "message": "Cliccare fuori del pop-up per controllare il codice di verifica nella tua email chiuderà questo pop-up. Vuoi aprire questo pop-up in una nuova finestra in modo che non si chiuda?" }, "popupU2fCloseMessage": { - "message": "Questo browser non può elaborare richieste U2F in questa finestra a comparsa. Vuoi aprire questo popup in una nuova finestra in modo da poter accedere usando U2F?" + "message": "Questo browser non può elaborare richieste U2F in questo pop-up. Aprire questo pop-up in una nuova finestra per accedere usando U2F?" }, "enableFavicon": { - "message": "Mostra icone del sito" + "message": "Mostra icone dei siti" }, "faviconDesc": { - "message": "Mostra un'immagine riconoscibile accanto a ogni login." + "message": "Mostra un piccolo logo riconoscibile accanto a ogni login." }, "enableBadgeCounter": { - "message": "Mostra contatore" + "message": "Mostra badge contatore" }, "badgeCounterDesc": { - "message": "Indica quanti login hai per la pagina web corrente." + "message": "Mostra il numero di login salvati per il sito web corrente nell'icona dell'estensione." }, "cardholderName": { "message": "Titolare della carta" @@ -1124,7 +1140,7 @@ "message": "Sig.ra" }, "dr": { - "message": "Dottore" + "message": "Dr." }, "mx": { "message": "Mx" @@ -1139,7 +1155,7 @@ "message": "Cognome" }, "fullName": { - "message": "Nome completo" + "message": "Nome e cognome" }, "identityName": { "message": "Nome dell'identità" @@ -1151,10 +1167,10 @@ "message": "Codice fiscale/Previdenza sociale" }, "passportNumber": { - "message": "Numero del passaporto" + "message": "Numero passaporto" }, "licenseNumber": { - "message": "Numero della patente" + "message": "Numero patente" }, "email": { "message": "Email" @@ -1242,7 +1258,7 @@ "message": "Verifica se la password è stata esposta." }, "passwordExposed": { - "message": "Questa password è presente $VALUE$ volta/e in database di violazioni. Dovresti cambiarla.", + "message": "Questa password è stata esposta $VALUE$ volte nei database di violazioni dei dati. Dovresti cambiarla.", "placeholders": { "value": { "content": "$1", @@ -1284,14 +1300,14 @@ "description": "Default URI match detection for auto-fill." }, "toggleOptions": { - "message": "Attiva/Disattiva opzioni" + "message": "Mostra/nascondi" }, "toggleCurrentUris": { - "message": "Mostra/Nascondi URI attuale", + "message": "Mostra/nascondi URI corrente", "description": "Toggle the display of the URIs of the currently open tabs in the browser." }, "currentUri": { - "message": "URI attuale", + "message": "URI corrente", "description": "The URI of one of the current open tabs in the browser." }, "organization": { @@ -1305,7 +1321,7 @@ "message": "Tutti gli elementi" }, "noPasswordsInList": { - "message": "Non ci sono password da elencare." + "message": "Non ci sono password da mostrare." }, "remove": { "message": "Rimuovi" @@ -1326,13 +1342,13 @@ "description": "ex. Date this password was updated" }, "neverLockWarning": { - "message": "Sei sicuro di voler usare l'opzione \"Mai\"? Impostando le opzioni di blocco su \"Mai\", la chiave di cifratura della cassaforte sarà salvata sul tuo dispositivo. Se utilizzi questa opzione, assicurati di mantenere il dispositivo adeguatamente protetto." + "message": "Sei sicuro di voler usare l'opzione \"Mai\"? Impostare le opzioni di blocco su \"Mai\" salverà la chiave di criptografia della cassaforte sul tuo dispositivo. Se utilizzi questa opzione, assicurati di mantenere il tuo dispositivo adeguatamente protetto." }, "noOrganizationsList": { - "message": "Non appartieni ad alcuna organizzazione. Le organizzazioni ti consentono di condividere oggetti in modo sicuro con altri utenti." + "message": "Non appartieni a nessuna organizzazione. Le organizzazioni ti consentono di condividere elementi con altri in modo sicuro." }, "noCollectionsInList": { - "message": "Nessuna raccolta da elencare." + "message": "Nessuna raccolta da mostrare." }, "ownership": { "message": "Proprietà" @@ -1356,7 +1372,7 @@ "message": "Password principale debole" }, "weakMasterPasswordDesc": { - "message": "La password principale che hai scelto è debole. È necessario utilizzare una password principale forte (o una frase segreta) per proteggere adeguatamente il tuo account Bitwarden. Sei sicuro di voler utilizzare questa password principale?" + "message": "La password principale che hai scelto è debole. Usa una password principale (o una frase segreta) forte per proteggere adeguatamente il tuo account Bitwarden. Sei sicuro di voler utilizzare questa password principale?" }, "pin": { "message": "PIN", @@ -1366,10 +1382,10 @@ "message": "Sblocca con PIN" }, "setYourPinCode": { - "message": "Imposta il tuo codice PIN per sbloccare Bitwarden. Le impostazioni PIN saranno reimpostate se eseguirai una disconnessione completa dall'applicazione." + "message": "Imposta il tuo codice PIN per sbloccare Bitwarden. Le tue impostazioni PIN saranno resettate se esci completamente dall'applicazione." }, "pinRequired": { - "message": "È richiesto il PIN." + "message": "Codice PIN obbligatorio." }, "invalidPin": { "message": "Codice PIN non valido." @@ -1381,7 +1397,7 @@ "message": "In attesa di conferma dal desktop" }, "awaitDesktopDesc": { - "message": "Si prega di confermare utilizzando l'autenticazione biometrica nell'applicazione Bitwarden Desktop per abilitare l'autenticazione biometrica per il browser." + "message": "Conferma utilizzando l'autenticazione biometrica nell'applicazione Bitwarden Desktop per abilitare l'autenticazione biometrica per il browser." }, "lockWithMasterPassOnRestart": { "message": "Blocca con la password principale al riavvio del browser" @@ -1396,7 +1412,7 @@ "message": "Clona" }, "passwordGeneratorPolicyInEffect": { - "message": "Una o più policy dell'organizzazione controllano le impostazioni del tuo generatore." + "message": "Una o più politiche dell'organizzazione controllano le tue impostazioni del generatore." }, "vaultTimeoutAction": { "message": "Azione timeout cassaforte" @@ -1413,7 +1429,7 @@ "message": "Cerca nel cestino" }, "permanentlyDeleteItem": { - "message": "Elimina definitivamente l'elemento" + "message": "Elimina elemento definitivamente" }, "permanentlyDeleteItemConfirmation": { "message": "Sei sicuro di voler eliminare definitivamente questo elemento?" @@ -1431,7 +1447,7 @@ "message": "Elemento ripristinato" }, "vaultTimeoutLogOutConfirmation": { - "message": "La disconnessione rimuove tutti gli accessi alla cassaforte e richiede l'autenticazione online dopo il periodo di timeout. Sei sicuro di voler utilizzare questa impostazione?" + "message": "Uscire rimuoverà tutti gli accessi alla tua cassaforte e richiede l'autenticazione online dopo il periodo di timeout. Sei sicuro di voler usare questa opzione?" }, "vaultTimeoutLogOutConfirmationTitle": { "message": "Conferma azione di timeout" @@ -1443,13 +1459,13 @@ "message": "Elemento riempito automaticamente e URI salvato" }, "autoFillSuccess": { - "message": "Elemento riempito automaticamente" + "message": "Elemento riempito automaticamente " }, "setMasterPassword": { - "message": "Imposta la password principale" + "message": "Imposta password principale" }, "masterPasswordPolicyInEffect": { - "message": "La password principale deve avere i seguenti requisiti, stabiliti da una o più regole dell'organizzazione:" + "message": "La password principale deve avere i seguenti requisiti, stabiliti dalle politiche dell'organizzazione:" }, "policyInEffectMinComplexity": { "message": "Punteggio minimo di complessità di $SCORE$", @@ -1476,7 +1492,7 @@ "message": "Contiene almeno un carattere minuscolo" }, "policyInEffectNumbers": { - "message": "Contiene almeno una cifra" + "message": "Contiene uno o più numeri" }, "policyInEffectSpecial": { "message": "Contiene almeno uno dei seguenti caratteri speciali $CHARS$", @@ -1488,19 +1504,19 @@ } }, "masterPasswordPolicyRequirementsNotMet": { - "message": "La tua nuova password principale non soddisfa i parametri di sicurezza." + "message": "La tua nuova password principale non soddisfa i requisiti di sicurezza." }, "acceptPolicies": { - "message": "Selezionando la casella accetti quanto segue:" + "message": "Selezionando questa casella accetti quanto segue:" }, "acceptPoliciesRequired": { "message": "I termini di servizio e l'informativa sulla privacy non sono stati accettati." }, "termsOfService": { - "message": "Termini del servizio" + "message": "Termini di Servizio" }, "privacyPolicy": { - "message": "Informativa sulla privacy" + "message": "Informativa sulla Privacy" }, "hintEqualsPassword": { "message": "Il suggerimento della password non può essere uguale alla password." @@ -1512,7 +1528,7 @@ "message": "Verifica sincronizzazione desktop" }, "desktopIntegrationVerificationText": { - "message": "Verifica che l'applicazione desktop mostri questa impronta digitale: " + "message": "Verifica che l'applicazione desktop mostri questa impronta: " }, "desktopIntegrationDisabledTitle": { "message": "L'integrazione del browser non è abilitata" @@ -1524,16 +1540,16 @@ "message": "Avvia l'applicazione desktop Bitwarden" }, "startDesktopDesc": { - "message": "L'applicazione Bitwarden Desktop deve essere avviata prima che questa funzione possa essere utilizzata." + "message": "L'applicazione Bitwarden Desktop deve essere avviata prima che l'autenticazione biometrica possa essere usata." }, "errorEnableBiometricTitle": { - "message": "Impossibile abilitare l'autenticazione biometrica" + "message": "Impossibile abilitare autenticazione biometrica" }, "errorEnableBiometricDesc": { "message": "L'azione è stata annullata dall'applicazione desktop" }, "nativeMessagingInvalidEncryptionDesc": { - "message": "L'applicazione desktop ha invalidato il canale di comunicazione sicuro. Ritenta l'operazione" + "message": "L'applicazione desktop ha invalidato il canale di comunicazione sicuro. Riprova di nuovo" }, "nativeMessagingInvalidEncryptionTitle": { "message": "Comunicazione desktop interrotta" @@ -1542,13 +1558,13 @@ "message": "L'applicazione desktop è collegata a un account diverso. Assicurati che entrambe le applicazioni siano collegate allo stesso account." }, "nativeMessagingWrongUserTitle": { - "message": "Account non corrispondente" + "message": "Account non corrispondono" }, "biometricsNotEnabledTitle": { "message": "Autenticazione biometrica non abilitata" }, "biometricsNotEnabledDesc": { - "message": "L'autenticazione biometrica del browser richiede che l'autenticazione biometrica del desktop sia prima abilitata nelle impostazioni." + "message": "L'autenticazione biometrica del browser richiede che l'autenticazione biometrica sia già abilitata anche nelle impostazioni del desktop." }, "biometricsNotSupportedTitle": { "message": "Autenticazione biometrica non supportata" @@ -1566,19 +1582,19 @@ "message": "Errore richiesta di autorizzazione" }, "nativeMessaginPermissionSidebarDesc": { - "message": "Questa azione non può essere eseguita nella barra laterale, riprova l'azione nel popup o nella finestra." + "message": "Questa azione non può essere eseguita nella barra laterale, riprova l'azione nel pop-up o nella finestra." }, "personalOwnershipSubmitError": { - "message": "A causa di una policy aziendale, non è possibile salvare elementi nella tua cassaforte personale. Cambia l'opzione proprietà in un'organizzazione e scegli tra le raccolte disponibili." + "message": "A causa di una politica aziendale, non puoi salvare elementi nella tua cassaforte personale. Cambia l'opzione di proprietà in un'organizzazione e scegli tra le raccolte disponibili." }, "personalOwnershipPolicyInEffect": { - "message": "Una policy dell'organizzazione controlla le opzioni di proprietà." + "message": "Una politica dell'organizzazione sta influenzando le tue opzioni di proprietà." }, "excludedDomains": { "message": "Domini esclusi" }, "excludedDomainsDesc": { - "message": "Bitwarden non chiederà di salvare i dettagli di accesso per questi domini. È necessario aggiornare la pagina perché le modifiche abbiano effetto." + "message": "Bitwarden non ti chiederà di aggiungere nuovi login per questi domini. Ricorda di ricaricare la pagina perché le modifiche abbiano effetto." }, "excludedDomainsInvalidDomain": { "message": "$DOMAIN$ non è un dominio valido", @@ -1642,7 +1658,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendLink": { - "message": "Collegamento del Send", + "message": "Link del Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "disabled": { @@ -1664,7 +1680,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendTypeHeader": { - "message": "Di quale tipo di Send si tratta?", + "message": "Che tipo di Send è questo?", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendNameDesc": { @@ -1678,14 +1694,14 @@ "message": "Data di eliminazione" }, "deletionDateDesc": { - "message": "Il Send sarà definitivamente eliminato alla data e ora specificate.", + "message": "Il Send sarà eliminato definitivamente alla data e ora specificate.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "expirationDate": { "message": "Data di scadenza" }, "expirationDateDesc": { - "message": "Se impostato, l'accesso a questo Send scadrà alla data e all'ora specificate.", + "message": "Se impostato, l'accesso a questo Send scadrà alla data e ora specificate.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "oneDay": { @@ -1707,11 +1723,11 @@ "message": "Numero massimo di accessi" }, "maximumAccessCountDesc": { - "message": "Se impostata, gli utenti non saranno più in grado di accedere a questo Send una volta raggiunto il numero massimo di accessi.", + "message": "Se impostata, gli utenti potranno più accedere a questo Send una volta raggiunto il numero massimo di accessi.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendPasswordDesc": { - "message": "Facoltativamente, richiedi una password agli utenti per accedere al Send.", + "message": "Richiedi una password agli utenti per accedere a questo Send (facoltativo).", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendNotesDesc": { @@ -1719,11 +1735,11 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendDisableDesc": { - "message": "Disabilita il Send per renderlo inaccessibile.", + "message": "Disattiva il Send per renderlo inaccessibile.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendShareDesc": { - "message": "Copia il collegamento del Send negli appunti dopo aver salvato.", + "message": "Copia il link al Send negli appunti dopo averlo salvato.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendTextDesc": { @@ -1734,21 +1750,21 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "currentAccessCount": { - "message": "Numero di accessi attuale" + "message": "Numero di accessi correnti" }, "createSend": { - "message": "Crea nuovo Send", + "message": "Nuovo Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "newPassword": { "message": "Nuova password" }, "sendDisabled": { - "message": "Send disabilitato", + "message": "Send rimosso", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendDisabledWarning": { - "message": "A causa di una policy aziendale, è possibile eliminare solo un Send esistente.", + "message": "A causa di una politica aziendale, puoi eliminare solo Send esistenti.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "createdSend": { @@ -1756,17 +1772,17 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editedSend": { - "message": "Send modificato", + "message": "Send salvato", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendLinuxChromiumFileWarning": { - "message": "Per scegliere un file, apri l'estensione nella barra laterale (se possibile) o apri una nuova finestra facendo clic su questo banner." + "message": "Per scegliere un file, apri l'estensione nella barra laterale (se possibile) o apri una nuova finestra cliccando questo banner." }, "sendFirefoxFileWarning": { - "message": "Per scegliere un file utilizzando Firefox, apri l'estensione nella barra laterale o apri una nuova finestra facendo clic sul banner." + "message": "Per scegliere un file usando Firefox, apri l'estensione nella barra laterale o apri una nuova finestra cliccando questo banner." }, "sendSafariFileWarning": { - "message": "Per scegliere un file utilizzando Safari, apri una nuova finestra facendo clic sul banner." + "message": "Per scegliere un file usando Safari, apri una nuova finestra cliccando questo banner." }, "sendFileCalloutHeader": { "message": "Prima di iniziare" @@ -1776,7 +1792,7 @@ "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read '**To use a calendar style date picker ** click here to pop out your window.'" }, "sendFirefoxCustomDatePopoutMessage2": { - "message": "fai clic qui", + "message": "clicca qui", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'To use a calendar style date picker **click here** to pop out your window.'" }, "sendFirefoxCustomDatePopoutMessage3": { @@ -1790,10 +1806,10 @@ "message": "La data di eliminazione fornita non è valida." }, "expirationDateAndTimeRequired": { - "message": "È necessario inserire data e ora di scadenza." + "message": "La data e ora di scadenza sono obbligatorie." }, "deletionDateAndTimeRequired": { - "message": "È necessario inserire data e ora di eliminazione." + "message": "La data e ora di eliminazione sono obbligatorie." }, "dateParsingError": { "message": "Si è verificato un errore durante il salvataggio delle date di eliminazione e scadenza." @@ -1802,7 +1818,7 @@ "message": "Nascondi il mio indirizzo email dai destinatari." }, "sendOptionsPolicyInEffect": { - "message": "Una o più policy dell'organizzazione influenzano le opzioni dei Send." + "message": "Una o più politiche dell'organizzazione stanno influenzando le tue opzioni di Send." }, "passwordPrompt": { "message": "Nuova richiesta della password principale" @@ -1814,10 +1830,10 @@ "message": "Questa azione è protetta. Per continuare, inserisci nuovamente la tua password principale per verificare la tua identità." }, "emailVerificationRequired": { - "message": "Verifica email richiesta" + "message": "Verifica email obbligatoria" }, "emailVerificationRequiredDesc": { - "message": "Devi verificare la tua email per utilizzare questa funzionalità. Puoi verificare la tua email nella cassaforte web." + "message": "Devi verificare la tua email per usare questa funzionalità. Puoi verificare la tua email nella cassaforte web." }, "updatedMasterPassword": { "message": "Password principale aggiornata" @@ -1826,13 +1842,13 @@ "message": "Aggiorna password principale" }, "updateMasterPasswordWarning": { - "message": "La tua password principale è stata recentemente modificata da un amministratore nella tua organizzazione. Per accedere alla cassaforte, aggiorna ora la password. Procedendo sarai disconnesso dalla sessione attuale e ti sarà richiesto di effettuare nuovamente l'accesso. Le sessioni attive su altri dispositivi potrebbero continuare a rimanere attive per un massimo di un'ora." + "message": "La tua password principale è stata recentemente modificata da un amministratore nella tua organizzazione. Per accedere alla cassaforte, devi aggiornarla ora. Procedendo sarai disconnesso dalla sessione attuale, richiedendo di effettuare nuovamente l'accesso. Le sessioni attive su altri dispositivi possono continuare a rimanere attive per un massimo di un'ora." }, "resetPasswordPolicyAutoEnroll": { "message": "Iscrizione automatica" }, "resetPasswordAutoEnrollInviteWarning": { - "message": "Questa organizzazione ha una policy aziendale che ti iscriverà automaticamente al ripristino della password. Ciò permetterà agli amministratori dell'organizzazione di cambiare la tua password principale." + "message": "Questa organizzazione ha una politica aziendale che ti iscriverà automaticamente al ripristino della password. Questo permetterà agli amministratori dell'organizzazione di cambiare la tua password principale." }, "selectFolder": { "message": "Seleziona cartella..." @@ -1847,7 +1863,7 @@ "message": "Minuti" }, "vaultTimeoutPolicyInEffect": { - "message": "Le policy dell'organizzazione stanno influenzando il timeout della tua cassaforte. Il tempo massimo consentito è di $HOURS$ ore e $MINUTES$ minuti", + "message": "Le politiche della tua organizzazione stanno influenzando il timeout della tua cassaforte. Il tempo massimo consentito è di $HOURS$ ore e $MINUTES$ minuti", "placeholders": { "hours": { "content": "$1", @@ -1863,19 +1879,19 @@ "message": "Il timeout della tua cassaforte supera i limiti impostati dalla tua organizzazione." }, "vaultExportDisabled": { - "message": "Esportazione cassaforte disabilitata" + "message": "Esportazione della cassaforte non disponibile" }, "personalVaultExportPolicyInEffect": { - "message": "Una o più policy dell'organizzazione ti impediscono di esportare la tua cassaforte personale." + "message": "Una o più politiche dell'organizzazione ti impediscono di esportare la tua cassaforte personale." }, "copyCustomFieldNameInvalidElement": { - "message": "Impossibile identificare un elemento del form valido. Prova a ispezionare l'HTML." + "message": "Impossibile identificare un elemento del modulo valido. Prova a ispezionare l'HTML." }, "copyCustomFieldNameNotUnique": { "message": "Nessun identificatore univoco trovato." }, "convertOrganizationEncryptionDesc": { - "message": "$ORGANIZATION$ sta usando SSO con un server \"self-hosted\". Non è più richiesta una password principale per accedere per i membri di questa organizzazione.", + "message": "$ORGANIZATION$ sta usando SSO con un server self-hosted. Una password principale non è più necessaria per accedere per i membri di questa organizzazione.", "placeholders": { "organization": { "content": "$1", @@ -1884,13 +1900,13 @@ } }, "leaveOrganization": { - "message": "Lascia l'organizzazione" + "message": "Lascia organizzazione" }, "removeMasterPassword": { - "message": "Rimuovi la password principale" + "message": "Rimuovi password principale" }, "removedMasterPassword": { - "message": "Password principale rimossa." + "message": "Password principale rimossa" }, "leaveOrganizationConfirmation": { "message": "Sei sicuro di voler lasciare questa organizzazione?" @@ -1902,13 +1918,13 @@ "message": "Attiva/Disattiva conteggio dei caratteri" }, "sessionTimeout": { - "message": "La tua sessione è scaduta. Torna indietro e riprova ad accedere." + "message": "La tua sessione è scaduta. Torna indietro e prova ad accedere di nuovo." }, "exportingPersonalVaultTitle": { "message": "Esportazione cassaforte personale" }, "exportingPersonalVaultDescription": { - "message": "Saranno esportati solo gli oggetti della cassaforte personale associati a $EMAIL$. Gli oggetti della cassaforte dell'organizzazione non saranno inclusi.", + "message": "Solo gli elementi della cassaforte personale associati a $EMAIL$ saranno esportati. Gli elementi della cassaforte dell'organizzazione non saranno inclusi.", "placeholders": { "email": { "content": "$1", @@ -1933,7 +1949,7 @@ "description": "Username generator option that appends a random sub-address to the username. For example: address+subaddress@email.com" }, "plusAddressedEmailDesc": { - "message": "Usa le funzionalità di sub-indirizzamento del tuo fornitore di posta elettronica." + "message": "Usa le funzionalità di sub-indirizzamento del tuo fornitore di email." }, "catchallEmail": { "message": "Email catch-all" @@ -1951,7 +1967,7 @@ "message": "Nome sito web" }, "whatWouldYouLikeToGenerate": { - "message": "Cosa vorresti generare?" + "message": "Cosa vuoi generare?" }, "passwordType": { "message": "Tipo di password" @@ -1982,16 +1998,13 @@ "message": "È richiesto un abbonamento Premium" }, "organizationIsDisabled": { - "message": "L'organizzazione è disabilitata." + "message": "Organizzazione disabilitata." }, "disabledOrganizationFilterError": { - "message": "Non è possibile accedere agli oggetti nelle organizzazioni disabilitate. Contatta il proprietario della tua organizzazione per ricevere assistenza." - }, - "cardBrandMir": { - "message": "Mir" + "message": "Non è possibile accedere a elementi da organizzazioni disabilitate. Contatta il proprietario della tua organizzazione." }, "loggingInTo": { - "message": "Accedo a $DOMAIN$", + "message": "Accedendo a $DOMAIN$", "placeholders": { "domain": { "content": "$1", @@ -2000,7 +2013,7 @@ } }, "settingsEdited": { - "message": "Le impostazioni sono state cambiate" + "message": "Impostazioni modificate" }, "environmentEditedClick": { "message": "Clicca qui" @@ -2012,7 +2025,7 @@ "message": "Versione Server" }, "selfHosted": { - "message": "Self-Hosted" + "message": "Self-hosted" }, "thirdParty": { "message": "Terze parti" @@ -2036,10 +2049,10 @@ } }, "loginWithMasterPassword": { - "message": "Accedi con la password principale" + "message": "Accedi con password principale" }, "loggingInAs": { - "message": "Accesso eseguito come" + "message": "Accedendo come" }, "notYou": { "message": "Non sei tu?" @@ -2051,16 +2064,16 @@ "message": "Ricorda email" }, "loginWithDevice": { - "message": "Accedi con il dispositivo" + "message": "Accedi con dispositivo" }, "loginWithDeviceEnabledInfo": { - "message": "Il login con il dispositivo deve essere abilitato nelle impostazioni dell'app Bitwarden. Hai bisogno di un'altra opzione?" + "message": "L'accesso con dispositivo deve essere abilitato nelle impostazioni dell'app Bitwarden. Ti serve un'altra opzione?" }, "fingerprintPhraseHeader": { "message": "Frase impronta" }, "fingerprintMatchInfo": { - "message": "Assicurati che la tua cassaforte sia sbloccata e che la \"frase impronta\" corrisponda sull'altro dispositivo." + "message": "Assicurati che la tua cassaforte sia sbloccata e che la frase impronta corrisponda sull'altro dispositivo." }, "resendNotification": { "message": "Invia nuova notifica" @@ -2078,16 +2091,16 @@ "message": "Password principale violata" }, "exposedMasterPasswordDesc": { - "message": "Password trovata in un database di data breach noto. Usa una password esclusiva per proteggere il tuo account. Sei sicuro di voler usare una password violata?" + "message": "Password trovata una violazione dei dati. Usa una password unica per proteggere il tuo account. Sei sicuro di voler usare una password violata?" }, "weakAndExposedMasterPassword": { "message": "Password principale debole e violata" }, "weakAndBreachedMasterPasswordDesc": { - "message": "Password debole trovata in un database di data breach noto. Usa una password forte ed esclusiva per proteggere il tuo account. Sei sicuro di voler utilizzare questa password?" + "message": "Password debole e trovata una violazione dei dati. Usa una password forte e unica per proteggere il tuo account. Sei sicuro di voler usare questa password?" }, "checkForBreaches": { - "message": "Controlla se la tua password è presente nei database dei data breach noti" + "message": "Controlla se la tua password è presente in una violazione dei dati" }, "important": { "message": "Importante:" @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Le politiche della tua organizzazione hanno abilitato il riempimento automatico al caricamento della pagina." + }, + "howToAutofill": { + "message": "Come riempire automaticamente" + }, + "autofillSelectInfoWithCommand": { + "message": "Seleziona un elemento da questa pagina o usa la scorciatoia: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Seleziona un elemento da questa pagina o imposta una scorciatoia nelle impostazioni." + }, + "gotIt": { + "message": "Ok" + }, + "autofillSettings": { + "message": "Impostazioni di riempimento automatico" + }, + "autofillShortcut": { + "message": "Scorciatoia da tastiera per riempire automaticamente" + }, + "autofillShortcutNotSet": { + "message": "Non è stata impostata nessuna scorciatoia da tastiera per riempire automaticamente. Impostala nelle impostazioni del browser." + }, + "autofillShortcutText": { + "message": "La scorciatoia da tastiera per riempire automaticamente è: $COMMAND$. Cambiala nelle impostazioni del browser.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Scorciatoia da tastiera predefinita per riempire automaticamente: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index 2b9be9dd017..ef943374bfd 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "ヘルプ&フィードバック" }, + "helpCenter": { + "message": "Bitwarden ヘルプセンター" + }, + "communityForums": { + "message": "Bitwarden コミュニティフォーラムを探索" + }, + "contactSupport": { + "message": "Bitwarden サポートへの問い合わせ" + }, "sync": { "message": "同期" }, @@ -430,7 +439,14 @@ "message": "マスターパスワードの再入力が必要です。" }, "masterPasswordMinlength": { - "message": "マスターパスワードは、少なくとも8文字以上で設定してください。" + "message": "マスターパスワードは少なくとも $VALUE$ 文字以上でなければなりません。", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "マスターパスワードが一致しません。" @@ -960,7 +976,7 @@ "message": "ページ読み込み時にログインフォームを検出したとき、ログイン情報を自動入力します。" }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "ウイルス感染したり信頼できないウェブサイトは、ページの読み込み時の自動入力を悪用できてしまいます。" }, "learnMoreAboutAutofill": { "message": "自動入力についての詳細" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "無効な組織のアイテムにアクセスすることはできません。組織の所有者に連絡してください。" }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "$DOMAIN$ にログイン中", "placeholders": { @@ -2084,7 +2097,7 @@ "message": "脆弱で流出済みのマスターパスワード" }, "weakAndBreachedMasterPasswordDesc": { - "message": "入力されたパスワードは脆弱かつすでに流出済みです。アカウントを守るためより強力で一意なパスワードを使用してください。本当にこの脆弱なパスワードを使用しますか?" + "message": "入力されたパスワードは脆弱かつ流出済みです。アカウントを守るためより強力で一意なパスワードを使用してください。本当にこの脆弱なパスワードを使用しますか?" }, "checkForBreaches": { "message": "このパスワードの既知のデータ流出を確認" @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "組織のポリシーはページ読み込み時の自動入力をオンにしました。" + }, + "howToAutofill": { + "message": "自動入力する方法" + }, + "autofillSelectInfoWithCommand": { + "message": "このページからアイテムを選択するか、ショートカットを使用してください: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "このページからアイテムを選択するか、設定でショートカットを設定してください。" + }, + "gotIt": { + "message": "了解" + }, + "autofillSettings": { + "message": "自動入力の設定" + }, + "autofillShortcut": { + "message": "自動入力キーボードショートカット" + }, + "autofillShortcutNotSet": { + "message": "自動入力のショートカットが設定されていません。ブラウザの設定で変更してください。" + }, + "autofillShortcutText": { + "message": "自動入力のショートカットは $COMMAND$ です。ブラウザの設定でこれを変更してください。", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "デフォルトの自動入力ショートカットは $COMMAND$ です。", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json index 3be83354972..3c05c161553 100644 --- a/apps/browser/src/_locales/ka/messages.json +++ b/apps/browser/src/_locales/ka/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "დახმარება & გამოხმაურება" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "სინქრონიზაცია" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Master password confirmation does not match." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json index 9c228a74174..8f6d3d0da96 100644 --- a/apps/browser/src/_locales/km/messages.json +++ b/apps/browser/src/_locales/km/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Help & feedback" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Sync" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Master password confirmation does not match." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json index 0214db30186..85cfdfeda0e 100644 --- a/apps/browser/src/_locales/kn/messages.json +++ b/apps/browser/src/_locales/kn/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "ಸಹಾಯ ಪ್ರತಿಕ್ರಿಯೆ\n" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "ಸಿಂಕ್" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "ಮಾಸ್ಟರ್ ಪಾಸ್‌ವರ್ಡ್ ದೃಢೀಕರಣವು ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index 0a9102a28ae..426004d8241 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "도움말 및 의견" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "동기화" }, @@ -430,7 +439,14 @@ "message": "마스터 비밀번호를 재입력해야 합니다." }, "masterPasswordMinlength": { - "message": "마스터 비밀번호는 최소 8자 이상이어야 합니다." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "마스터 비밀번호 확인과 마스터 비밀번호가 일치하지 않습니다." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json index ec989f7c610..6424e29853a 100644 --- a/apps/browser/src/_locales/lt/messages.json +++ b/apps/browser/src/_locales/lt/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Pagalba ir atsiliepimai" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Sinchronizuoti" }, @@ -430,7 +439,14 @@ "message": "Būtinas prisijungimo slaptažodžio patvirtinimas." }, "masterPasswordMinlength": { - "message": "Pagrindinis slaptažodis turi būti bent 8 simbolių ilgio." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Pagrindinio slaptažodžio patvirtinimas nesutampa." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index 30f76765c45..1d1c8fb61f3 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -11,7 +11,7 @@ "description": "Extension description" }, "loginOrCreateNewAccount": { - "message": "Jāpiesakās vai jāizveido jauns konts, lai piekļūdu drošajai glabātavai." + "message": "Jāpiesakās vai jāizveido jauns konts, lai piekļūtu drošajai glabātavai." }, "createAccount": { "message": "Izveidot kontu" @@ -20,7 +20,7 @@ "message": "Pieteikties" }, "enterpriseSingleSignOn": { - "message": "Uzņēmuma vienotā pierakstīšanās" + "message": "Uzņēmuma vienotā pieteikšanās" }, "cancel": { "message": "Atcelt" @@ -77,7 +77,7 @@ "message": "Ievietot piezīmi starpliktuvē" }, "copyUri": { - "message": "Ievietot URI starpliktuvē" + "message": "Ievietot vietrādi starpliktuvē" }, "copyUsername": { "message": "Ievietot lietotājvārdu starpliktuvē" @@ -89,7 +89,7 @@ "message": "Ievietot drošības kodu starpliktuvē" }, "autoFill": { - "message": "Automātiskā aizpilde" + "message": "Automātiskā aizpildīšana" }, "generatePasswordCopied": { "message": "Veidot paroli (ievietota starpliktuvē)" @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Palīdzība un atsauksmes" }, + "helpCenter": { + "message": "Bitwarden palīdzības centrs" + }, + "communityForums": { + "message": "Izpētīt Bitwarden kopienas forumus" + }, + "contactSupport": { + "message": "Sazināties ar Bitwarden atbalstu" + }, "sync": { "message": "Sinhronizēt" }, @@ -221,7 +230,7 @@ "message": "Ievietot vienumus" }, "select": { - "message": "Atlasīt" + "message": "Izvēlēties" }, "generatePassword": { "message": "Veidot paroli" @@ -333,10 +342,10 @@ "message": "Novērtēt paplašinājumu" }, "rateExtensionDesc": { - "message": "Lūdzu, apsver palīdzēt mums ar labu atsauksmi!" + "message": "Lūgums apsvērt palīdzēt mums ar labu atsauksmi." }, "browserNotSupportClipboard": { - "message": "Tavs tīmekļa pārlūks neatbalsta vienkāršu starpliktuves kopēšanu. Nokopē to pašrocīgi!" + "message": "Tīmekļa pārlūks neatbalsta vienkāršu starpliktuves kopēšanu. Tā vietā tas pašrocīgi jāievieto starpliktuvē." }, "verifyIdentity": { "message": "Apstiprināt identitāti" @@ -430,7 +439,14 @@ "message": "Ir nepieciešama galvenās paroles atkārtota ievadīšana." }, "masterPasswordMinlength": { - "message": "Galvenajai parolei ir jābūt vismaz 8 rakstzīmes garai." + "message": "Galvenajai parolei ir jābūt vismaz $VALUE$ rakstzīmes garai.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Galvenās paroles apstiprinājums nesakrīt." @@ -458,7 +474,7 @@ } }, "autofillError": { - "message": "Neizdevās automātiski aizpildīt izvēlēto vienumu šajā lapā. Tā vietā kopē un ielīmē to! " + "message": "Neizdevās automātiski aizpildīt izvēlēto vienumu šajā lapā. Tā vietā informācija ir jāievieto starpliktuvē un jāielīmē pašrocīgi." }, "loggedOut": { "message": "Atteicies" @@ -738,7 +754,7 @@ "message": "Datne" }, "selectFile": { - "message": "Atlasīt datni." + "message": "Atlasīt datni" }, "maxFileSize": { "message": "Lielākais pieļaujamais datnes izmērs ir 500 MB." @@ -774,7 +790,7 @@ "message": "Tādas papildu divpakāpju pieteikšanās iespējas kā YubiKey, FIDO U2F un Duo." }, "ppremiumSignUpReports": { - "message": "Paroļu higiēnas, kontu veselības un datu pārkāpumu pārskati, lai uzturētu glabātavu drošu." + "message": "Paroļu higiēnas, konta veselības un datu noplūžu pārskati, lai uzturētu glabātavu drošu." }, "ppremiumSignUpTotp": { "message": "TOTP apstiprinājuma koda (2FA) veidotājs glabātavas pieteikšanās vienumiem." @@ -960,7 +976,7 @@ "message": "Ja tiek noteikta pieteikšanās veidne, tā tiks aizpildīta lapas ielādes brīdī." }, "experimentalFeature": { - "message": "Kompromitētas vai neuzticamas vietnes var izmantot automātisko aizpildīšanu lapas ielādes laikā." + "message": "Pārveidotās vai neuzticamās vietnēs automātiskā aizpildīšana lapas ielādes laikā var tikt ļaunprātīgi izmantota." }, "learnMoreAboutAutofill": { "message": "Uzzināt vairāk par automātisko aizpildīšanu" @@ -1242,7 +1258,7 @@ "message": "Pārbaudīt, vai parole ir bijusi nopludināta." }, "passwordExposed": { - "message": "Šī parole datu pārkāpumos ir atklāta $VALUE$ reizi(es). To vajag mainīt.", + "message": "Šī parole datu noplūdēs ir atklāta $VALUE$ reizi(es). To vajadzētu nomainīt.", "placeholders": { "value": { "content": "$1", @@ -1251,7 +1267,7 @@ } }, "passwordSafe": { - "message": "Šī parole netika atrasta nevienā no zināmajiem datu pārkāpumiem. Tai vajadzētu būt droši izmantojamai." + "message": "Šī parole netika atrasta nevienā zināmā datu noplūdē. Tai vajadzētu būt droši izmantojamai." }, "baseDomain": { "message": "Pamata domēns", @@ -1366,7 +1382,7 @@ "message": "Atslēgt ar PIN" }, "setYourPinCode": { - "message": "Uzstādīt PIN kodu Bitwarden atslēgšanai. PIN iestatījumi tiks atiestatīti, ja jebkad tiks veikta pilnīga izrakstīšanās no lietotnes." + "message": "Iestatīt PIN kodu Bitwarden atslēgšanai. PIN iestatījumi tiks atiestatīti pēc pilnīgas izrakstīšanās no lietotnes." }, "pinRequired": { "message": "Ir nepieciešams PIN kods." @@ -1625,7 +1641,7 @@ "message": "Aizsargāts ar paroli" }, "copySendLink": { - "message": "Kopēt Sūtījuma saiti", + "message": "Ievietot \"Send\" saiti starpliktuvē", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "removePassword": { @@ -1723,7 +1739,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendShareDesc": { - "message": "Saglabājot, kopējiet šī Sūtījuma saiti starpliktuvē.", + "message": "Saglabāšanas brīdī ievietot šī \"Send\" saiti starpliktuvē.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendTextDesc": { @@ -1748,7 +1764,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendDisabledWarning": { - "message": "Organizācijas politikas dēļ jūs varat dzēst tikai esošu Sūtījumu.", + "message": "Uzņēmuma nosacījumu dēļ ir iespējams izdzēst tikai esošu \"Send\".", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "createdSend": { @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Atspējotu apvienību vienumiem nevar piekļūt. Jāsazinās ar apvienības īpašnieku, lai iegūtu palīdzību." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Piesakās $DOMAIN$", "placeholders": { @@ -2078,16 +2091,16 @@ "message": "Noplūdusi galvenā parole" }, "exposedMasterPasswordDesc": { - "message": "Parole ir atrasta datu noplūdē. Jāizmanto spēcīga parole, lai aizsargātu savu kontu. Vai tiešām izmantot noplūdušu paroli?" + "message": "Parole atrasta datu noplūdē. Jāizmanto neatkārtojama parole, lai aizsargātu savu kontu. Vai tiešām izmantot noplūdušu paroli?" }, "weakAndExposedMasterPassword": { "message": "Vāja un noplūdusi galvenā parole" }, "weakAndBreachedMasterPasswordDesc": { - "message": "Noteikta vāja parole, un tā ir atrasta datu noplūdē. Jāizmanto spēcīga parole, lai aizsargātu savu kontu. Vai tiešām izmantot šo paroli?" + "message": "Noteikta vāja parole, un tā ir atrasta datu noplūdē. Jāizmanto spēcīga un neatkārtojama parole, lai aizsargātu savu kontu. Vai tiešām izmantot šo paroli?" }, "checkForBreaches": { - "message": "Pārbaudīt šo paroli pret zināmām datu noplūdēm" + "message": "Meklēt šo paroli zināmās datu noplūdēs" }, "important": { "message": "Svarīgi:" @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Tavas apvienības nosacījumos ir ieslēgta automātiskā aizpildīšana lapas ielādes brīdī." + }, + "howToAutofill": { + "message": "Kā automātiski aizpildīt" + }, + "autofillSelectInfoWithCommand": { + "message": "Jāatlasa vienums šai lapai vai jāizmanto īsceļš: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Jāatlasa vienums šai lapai vai iestatījumos jāuzstāda īsceļš." + }, + "gotIt": { + "message": "Sapratu" + }, + "autofillSettings": { + "message": "Automātiskās aizpildes iestatījumi" + }, + "autofillShortcut": { + "message": "Automātiskās aizpildes īsinājumtaustiņi" + }, + "autofillShortcutNotSet": { + "message": "Automātiskās aizpildes īsceļš nav uzstādīts. To var izdarīt pārlūka iestatījumos." + }, + "autofillShortcutText": { + "message": "Automātiskās aizpildes īsceļš ir: $COMMAND$. To var mainīt pārlūka iestatījumos.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Automātiskās aizpildes noklusējuma īsceļš: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json index c1305859268..fcf60ff1ef3 100644 --- a/apps/browser/src/_locales/ml/messages.json +++ b/apps/browser/src/_locales/ml/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "സഹായവും അഭിപ്രായവും" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "സമന്വയിപ്പിക്കുക" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "പ്രാഥമിക പാസ്‌വേഡ് സ്ഥിരീകരണം പൊരുത്തപ്പെടുന്നില്ല." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/my/messages.json b/apps/browser/src/_locales/my/messages.json new file mode 100644 index 00000000000..8f6d3d0da96 --- /dev/null +++ b/apps/browser/src/_locales/my/messages.json @@ -0,0 +1,2168 @@ +{ + "appName": { + "message": "Bitwarden" + }, + "extName": { + "message": "Bitwarden - Free Password Manager", + "description": "Extension name, MUST be less than 40 characters (Safari restriction)" + }, + "extDesc": { + "message": "A secure and free password manager for all of your devices.", + "description": "Extension description" + }, + "loginOrCreateNewAccount": { + "message": "Log in or create a new account to access your secure vault." + }, + "createAccount": { + "message": "Create account" + }, + "login": { + "message": "Log in" + }, + "enterpriseSingleSignOn": { + "message": "Enterprise single sign-on" + }, + "cancel": { + "message": "Cancel" + }, + "close": { + "message": "Close" + }, + "submit": { + "message": "Submit" + }, + "emailAddress": { + "message": "Email address" + }, + "masterPass": { + "message": "Master password" + }, + "masterPassDesc": { + "message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it." + }, + "masterPassHintDesc": { + "message": "A master password hint can help you remember your password if you forget it." + }, + "reTypeMasterPass": { + "message": "Re-type master password" + }, + "masterPassHint": { + "message": "Master password hint (optional)" + }, + "tab": { + "message": "Tab" + }, + "vault": { + "message": "Vault" + }, + "myVault": { + "message": "My vault" + }, + "allVaults": { + "message": "All vaults" + }, + "tools": { + "message": "Tools" + }, + "settings": { + "message": "Settings" + }, + "currentTab": { + "message": "Current tab" + }, + "copyPassword": { + "message": "Copy password" + }, + "copyNote": { + "message": "Copy note" + }, + "copyUri": { + "message": "Copy URI" + }, + "copyUsername": { + "message": "Copy username" + }, + "copyNumber": { + "message": "Copy number" + }, + "copySecurityCode": { + "message": "Copy security code" + }, + "autoFill": { + "message": "Auto-fill" + }, + "generatePasswordCopied": { + "message": "Generate password (copied)" + }, + "copyElementIdentifier": { + "message": "Copy custom field name" + }, + "noMatchingLogins": { + "message": "No matching logins" + }, + "unlockVaultMenu": { + "message": "Unlock your vault" + }, + "loginToVaultMenu": { + "message": "Log in to your vault" + }, + "autoFillInfo": { + "message": "There are no logins available to auto-fill for the current browser tab." + }, + "addLogin": { + "message": "Add a login" + }, + "addItem": { + "message": "Add item" + }, + "passwordHint": { + "message": "Password hint" + }, + "enterEmailToGetHint": { + "message": "Enter your account email address to receive your master password hint." + }, + "getMasterPasswordHint": { + "message": "Get master password hint" + }, + "continue": { + "message": "Continue" + }, + "sendVerificationCode": { + "message": "Send a verification code to your email" + }, + "sendCode": { + "message": "Send code" + }, + "codeSent": { + "message": "Code sent" + }, + "verificationCode": { + "message": "Verification code" + }, + "confirmIdentity": { + "message": "Confirm your identity to continue." + }, + "account": { + "message": "Account" + }, + "changeMasterPassword": { + "message": "Change master password" + }, + "fingerprintPhrase": { + "message": "Fingerprint phrase", + "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." + }, + "yourAccountsFingerprint": { + "message": "Your account's fingerprint phrase", + "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." + }, + "twoStepLogin": { + "message": "Two-step login" + }, + "logOut": { + "message": "Log out" + }, + "about": { + "message": "About" + }, + "version": { + "message": "Version" + }, + "save": { + "message": "Save" + }, + "move": { + "message": "Move" + }, + "addFolder": { + "message": "Add folder" + }, + "name": { + "message": "Name" + }, + "editFolder": { + "message": "Edit folder" + }, + "deleteFolder": { + "message": "Delete folder" + }, + "folders": { + "message": "Folders" + }, + "noFolders": { + "message": "There are no folders to list." + }, + "helpFeedback": { + "message": "Help & feedback" + }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, + "sync": { + "message": "Sync" + }, + "syncVaultNow": { + "message": "Sync vault now" + }, + "lastSync": { + "message": "Last sync:" + }, + "passGen": { + "message": "Password generator" + }, + "generator": { + "message": "Generator", + "description": "Short for 'Password Generator'." + }, + "passGenInfo": { + "message": "Automatically generate strong, unique passwords for your logins." + }, + "bitWebVault": { + "message": "Bitwarden web vault" + }, + "importItems": { + "message": "Import items" + }, + "select": { + "message": "Select" + }, + "generatePassword": { + "message": "Generate password" + }, + "regeneratePassword": { + "message": "Regenerate password" + }, + "options": { + "message": "Options" + }, + "length": { + "message": "Length" + }, + "uppercase": { + "message": "Uppercase (A-Z)" + }, + "lowercase": { + "message": "Lowercase (a-z)" + }, + "numbers": { + "message": "Numbers (0-9)" + }, + "specialCharacters": { + "message": "Special characters (!@#$%^&*)" + }, + "numWords": { + "message": "Number of words" + }, + "wordSeparator": { + "message": "Word separator" + }, + "capitalize": { + "message": "Capitalize", + "description": "Make the first letter of a work uppercase." + }, + "includeNumber": { + "message": "Include number" + }, + "minNumbers": { + "message": "Minimum numbers" + }, + "minSpecial": { + "message": "Minimum special" + }, + "avoidAmbChar": { + "message": "Avoid ambiguous characters" + }, + "searchVault": { + "message": "Search vault" + }, + "edit": { + "message": "Edit" + }, + "view": { + "message": "View" + }, + "noItemsInList": { + "message": "There are no items to list." + }, + "itemInformation": { + "message": "Item information" + }, + "username": { + "message": "Username" + }, + "password": { + "message": "Password" + }, + "passphrase": { + "message": "Passphrase" + }, + "favorite": { + "message": "Favorite" + }, + "notes": { + "message": "Notes" + }, + "note": { + "message": "Note" + }, + "editItem": { + "message": "Edit item" + }, + "folder": { + "message": "Folder" + }, + "deleteItem": { + "message": "Delete item" + }, + "viewItem": { + "message": "View item" + }, + "launch": { + "message": "Launch" + }, + "website": { + "message": "Website" + }, + "toggleVisibility": { + "message": "Toggle visibility" + }, + "manage": { + "message": "Manage" + }, + "other": { + "message": "Other" + }, + "rateExtension": { + "message": "Rate the extension" + }, + "rateExtensionDesc": { + "message": "Please consider helping us out with a good review!" + }, + "browserNotSupportClipboard": { + "message": "Your web browser does not support easy clipboard copying. Copy it manually instead." + }, + "verifyIdentity": { + "message": "Verify identity" + }, + "yourVaultIsLocked": { + "message": "Your vault is locked. Verify your identity to continue." + }, + "unlock": { + "message": "Unlock" + }, + "loggedInAsOn": { + "message": "Logged in as $EMAIL$ on $HOSTNAME$.", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "hostname": { + "content": "$2", + "example": "bitwarden.com" + } + } + }, + "invalidMasterPassword": { + "message": "Invalid master password" + }, + "vaultTimeout": { + "message": "Vault timeout" + }, + "lockNow": { + "message": "Lock now" + }, + "immediately": { + "message": "Immediately" + }, + "tenSeconds": { + "message": "10 seconds" + }, + "twentySeconds": { + "message": "20 seconds" + }, + "thirtySeconds": { + "message": "30 seconds" + }, + "oneMinute": { + "message": "1 minute" + }, + "twoMinutes": { + "message": "2 minutes" + }, + "fiveMinutes": { + "message": "5 minutes" + }, + "fifteenMinutes": { + "message": "15 minutes" + }, + "thirtyMinutes": { + "message": "30 minutes" + }, + "oneHour": { + "message": "1 hour" + }, + "fourHours": { + "message": "4 hours" + }, + "onLocked": { + "message": "On system lock" + }, + "onRestart": { + "message": "On browser restart" + }, + "never": { + "message": "Never" + }, + "security": { + "message": "Security" + }, + "errorOccurred": { + "message": "An error has occurred" + }, + "emailRequired": { + "message": "Email address is required." + }, + "invalidEmail": { + "message": "Invalid email address." + }, + "masterPasswordRequired": { + "message": "Master password is required." + }, + "confirmMasterPasswordRequired": { + "message": "Master password retype is required." + }, + "masterPasswordMinlength": { + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } + }, + "masterPassDoesntMatch": { + "message": "Master password confirmation does not match." + }, + "newAccountCreated": { + "message": "Your new account has been created! You may now log in." + }, + "masterPassSent": { + "message": "We've sent you an email with your master password hint." + }, + "verificationCodeRequired": { + "message": "Verification code is required." + }, + "invalidVerificationCode": { + "message": "Invalid verification code" + }, + "valueCopied": { + "message": "$VALUE$ copied", + "description": "Value has been copied to the clipboard.", + "placeholders": { + "value": { + "content": "$1", + "example": "Password" + } + } + }, + "autofillError": { + "message": "Unable to auto-fill the selected item on this page. Copy and paste the information instead." + }, + "loggedOut": { + "message": "Logged out" + }, + "loginExpired": { + "message": "Your login session has expired." + }, + "logOutConfirmation": { + "message": "Are you sure you want to log out?" + }, + "yes": { + "message": "Yes" + }, + "no": { + "message": "No" + }, + "unexpectedError": { + "message": "An unexpected error has occurred." + }, + "nameRequired": { + "message": "Name is required." + }, + "addedFolder": { + "message": "Folder added" + }, + "changeMasterPass": { + "message": "Change master password" + }, + "changeMasterPasswordConfirmation": { + "message": "You can change your master password on the bitwarden.com web vault. Do you want to visit the website now?" + }, + "twoStepLoginConfirmation": { + "message": "Two-step login makes your account more secure by requiring you to verify your login with another device such as a security key, authenticator app, SMS, phone call, or email. Two-step login can be set up on the bitwarden.com web vault. Do you want to visit the website now?" + }, + "editedFolder": { + "message": "Folder saved" + }, + "deleteFolderConfirmation": { + "message": "Are you sure you want to delete this folder?" + }, + "deletedFolder": { + "message": "Folder deleted" + }, + "gettingStartedTutorial": { + "message": "Getting started tutorial" + }, + "gettingStartedTutorialVideo": { + "message": "Watch our getting started tutorial to learn how to get the most out of the browser extension." + }, + "syncingComplete": { + "message": "Syncing complete" + }, + "syncingFailed": { + "message": "Syncing failed" + }, + "passwordCopied": { + "message": "Password copied" + }, + "uri": { + "message": "URI" + }, + "uriPosition": { + "message": "URI $POSITION$", + "description": "A listing of URIs. Ex: URI 1, URI 2, URI 3, etc.", + "placeholders": { + "position": { + "content": "$1", + "example": "2" + } + } + }, + "newUri": { + "message": "New URI" + }, + "addedItem": { + "message": "Item added" + }, + "editedItem": { + "message": "Item saved" + }, + "deleteItemConfirmation": { + "message": "Do you really want to send to the trash?" + }, + "deletedItem": { + "message": "Item sent to trash" + }, + "overwritePassword": { + "message": "Overwrite password" + }, + "overwritePasswordConfirmation": { + "message": "Are you sure you want to overwrite the current password?" + }, + "overwriteUsername": { + "message": "Overwrite username" + }, + "overwriteUsernameConfirmation": { + "message": "Are you sure you want to overwrite the current username?" + }, + "searchFolder": { + "message": "Search folder" + }, + "searchCollection": { + "message": "Search collection" + }, + "searchType": { + "message": "Search type" + }, + "noneFolder": { + "message": "No folder", + "description": "This is the folder for uncategorized items" + }, + "enableAddLoginNotification": { + "message": "Ask to add login" + }, + "addLoginNotificationDesc": { + "message": "Ask to add an item if one isn't found in your vault." + }, + "showCardsCurrentTab": { + "message": "Show cards on Tab page" + }, + "showCardsCurrentTabDesc": { + "message": "List card items on the Tab page for easy auto-fill." + }, + "showIdentitiesCurrentTab": { + "message": "Show identities on Tab page" + }, + "showIdentitiesCurrentTabDesc": { + "message": "List identity items on the Tab page for easy auto-fill." + }, + "clearClipboard": { + "message": "Clear clipboard", + "description": "Clipboard is the operating system thing where you copy/paste data to on your device." + }, + "clearClipboardDesc": { + "message": "Automatically clear copied values from your clipboard.", + "description": "Clipboard is the operating system thing where you copy/paste data to on your device." + }, + "notificationAddDesc": { + "message": "Should Bitwarden remember this password for you?" + }, + "notificationAddSave": { + "message": "Save" + }, + "enableChangedPasswordNotification": { + "message": "Ask to update existing login" + }, + "changedPasswordNotificationDesc": { + "message": "Ask to update a login's password when a change is detected on a website." + }, + "notificationChangeDesc": { + "message": "Do you want to update this password in Bitwarden?" + }, + "notificationChangeSave": { + "message": "Update" + }, + "enableContextMenuItem": { + "message": "Show context menu options" + }, + "contextMenuItemDesc": { + "message": "Use a secondary click to access password generation and matching logins for the website. " + }, + "defaultUriMatchDetection": { + "message": "Default URI match detection", + "description": "Default URI match detection for auto-fill." + }, + "defaultUriMatchDetectionDesc": { + "message": "Choose the default way that URI match detection is handled for logins when performing actions such as auto-fill." + }, + "theme": { + "message": "Theme" + }, + "themeDesc": { + "message": "Change the application's color theme." + }, + "dark": { + "message": "Dark", + "description": "Dark color" + }, + "light": { + "message": "Light", + "description": "Light color" + }, + "solarizedDark": { + "message": "Solarized dark", + "description": "'Solarized' is a noun and the name of a color scheme. It should not be translated." + }, + "exportVault": { + "message": "Export vault" + }, + "fileFormat": { + "message": "File format" + }, + "warning": { + "message": "WARNING", + "description": "WARNING (should stay in capitalized letters if the language permits)" + }, + "confirmVaultExport": { + "message": "Confirm vault export" + }, + "exportWarningDesc": { + "message": "This export contains your vault data in an unencrypted format. You should not store or send the exported file over unsecure channels (such as email). Delete it immediately after you are done using it." + }, + "encExportKeyWarningDesc": { + "message": "This export encrypts your data using your account's encryption key. If you ever rotate your account's encryption key you should export again since you will not be able to decrypt this export file." + }, + "encExportAccountWarningDesc": { + "message": "Account encryption keys are unique to each Bitwarden user account, so you can't import an encrypted export into a different account." + }, + "exportMasterPassword": { + "message": "Enter your master password to export your vault data." + }, + "shared": { + "message": "Shared" + }, + "learnOrg": { + "message": "Learn about organizations" + }, + "learnOrgConfirmation": { + "message": "Bitwarden allows you to share your vault items with others by using an organization. Would you like to visit the bitwarden.com website to learn more?" + }, + "moveToOrganization": { + "message": "Move to organization" + }, + "share": { + "message": "Share" + }, + "movedItemToOrg": { + "message": "$ITEMNAME$ moved to $ORGNAME$", + "placeholders": { + "itemname": { + "content": "$1", + "example": "Secret Item" + }, + "orgname": { + "content": "$2", + "example": "Company Name" + } + } + }, + "moveToOrgDesc": { + "message": "Choose an organization that you wish to move this item to. Moving to an organization transfers ownership of the item to that organization. You will no longer be the direct owner of this item once it has been moved." + }, + "learnMore": { + "message": "Learn more" + }, + "authenticatorKeyTotp": { + "message": "Authenticator key (TOTP)" + }, + "verificationCodeTotp": { + "message": "Verification code (TOTP)" + }, + "copyVerificationCode": { + "message": "Copy verification code" + }, + "attachments": { + "message": "Attachments" + }, + "deleteAttachment": { + "message": "Delete attachment" + }, + "deleteAttachmentConfirmation": { + "message": "Are you sure you want to delete this attachment?" + }, + "deletedAttachment": { + "message": "Attachment deleted" + }, + "newAttachment": { + "message": "Add new attachment" + }, + "noAttachments": { + "message": "No attachments." + }, + "attachmentSaved": { + "message": "Attachment saved" + }, + "file": { + "message": "File" + }, + "selectFile": { + "message": "Select a file" + }, + "maxFileSize": { + "message": "Maximum file size is 500 MB." + }, + "featureUnavailable": { + "message": "Feature unavailable" + }, + "updateKey": { + "message": "You cannot use this feature until you update your encryption key." + }, + "premiumMembership": { + "message": "Premium membership" + }, + "premiumManage": { + "message": "Manage membership" + }, + "premiumManageAlert": { + "message": "You can manage your membership on the bitwarden.com web vault. Do you want to visit the website now?" + }, + "premiumRefresh": { + "message": "Refresh membership" + }, + "premiumNotCurrentMember": { + "message": "You are not currently a Premium member." + }, + "premiumSignUpAndGet": { + "message": "Sign up for a Premium membership and get:" + }, + "ppremiumSignUpStorage": { + "message": "1 GB encrypted storage for file attachments." + }, + "ppremiumSignUpTwoStep": { + "message": "Additional two-step login options such as YubiKey, FIDO U2F, and Duo." + }, + "ppremiumSignUpReports": { + "message": "Password hygiene, account health, and data breach reports to keep your vault safe." + }, + "ppremiumSignUpTotp": { + "message": "TOTP verification code (2FA) generator for logins in your vault." + }, + "ppremiumSignUpSupport": { + "message": "Priority customer support." + }, + "ppremiumSignUpFuture": { + "message": "All future Premium features. More coming soon!" + }, + "premiumPurchase": { + "message": "Purchase Premium" + }, + "premiumPurchaseAlert": { + "message": "You can purchase Premium membership on the bitwarden.com web vault. Do you want to visit the website now?" + }, + "premiumCurrentMember": { + "message": "You are a Premium member!" + }, + "premiumCurrentMemberThanks": { + "message": "Thank you for supporting Bitwarden." + }, + "premiumPrice": { + "message": "All for just $PRICE$ /year!", + "placeholders": { + "price": { + "content": "$1", + "example": "$10" + } + } + }, + "refreshComplete": { + "message": "Refresh complete" + }, + "enableAutoTotpCopy": { + "message": "Copy TOTP automatically" + }, + "disableAutoTotpCopyDesc": { + "message": "If a login has an authenticator key, copy the TOTP verification code to your clip-board when you auto-fill the login." + }, + "enableAutoBiometricsPrompt": { + "message": "Ask for biometrics on launch" + }, + "premiumRequired": { + "message": "Premium required" + }, + "premiumRequiredDesc": { + "message": "A Premium membership is required to use this feature." + }, + "enterVerificationCodeApp": { + "message": "Enter the 6 digit verification code from your authenticator app." + }, + "enterVerificationCodeEmail": { + "message": "Enter the 6 digit verification code that was emailed to $EMAIL$.", + "placeholders": { + "email": { + "content": "$1", + "example": "example@gmail.com" + } + } + }, + "verificationCodeEmailSent": { + "message": "Verification email sent to $EMAIL$.", + "placeholders": { + "email": { + "content": "$1", + "example": "example@gmail.com" + } + } + }, + "rememberMe": { + "message": "Remember me" + }, + "sendVerificationCodeEmailAgain": { + "message": "Send verification code email again" + }, + "useAnotherTwoStepMethod": { + "message": "Use another two-step login method" + }, + "insertYubiKey": { + "message": "Insert your YubiKey into your computer's USB port, then touch its button." + }, + "insertU2f": { + "message": "Insert your security key into your computer's USB port. If it has a button, touch it." + }, + "webAuthnNewTab": { + "message": "To start the WebAuthn 2FA verification. Click the button below to open a new tab and follow the instructions provided in the new tab." + }, + "webAuthnNewTabOpen": { + "message": "Open new tab" + }, + "webAuthnAuthenticate": { + "message": "Authenticate WebAuthn" + }, + "loginUnavailable": { + "message": "Login unavailable" + }, + "noTwoStepProviders": { + "message": "This account has two-step login set up, however, none of the configured two-step providers are supported by this web browser." + }, + "noTwoStepProviders2": { + "message": "Please use a supported web browser (such as Chrome) and/or add additional providers that are better supported across web browsers (such as an authenticator app)." + }, + "twoStepOptions": { + "message": "Two-step login options" + }, + "recoveryCodeDesc": { + "message": "Lost access to all of your two-factor providers? Use your recovery code to turn off all two-factor providers from your account." + }, + "recoveryCodeTitle": { + "message": "Recovery code" + }, + "authenticatorAppTitle": { + "message": "Authenticator app" + }, + "authenticatorAppDesc": { + "message": "Use an authenticator app (such as Authy or Google Authenticator) to generate time-based verification codes.", + "description": "'Authy' and 'Google Authenticator' are product names and should not be translated." + }, + "yubiKeyTitle": { + "message": "YubiKey OTP Security Key" + }, + "yubiKeyDesc": { + "message": "Use a YubiKey to access your account. Works with YubiKey 4, 4 Nano, 4C, and NEO devices." + }, + "duoDesc": { + "message": "Verify with Duo Security using the Duo Mobile app, SMS, phone call, or U2F security key.", + "description": "'Duo Security' and 'Duo Mobile' are product names and should not be translated." + }, + "duoOrganizationDesc": { + "message": "Verify with Duo Security for your organization using the Duo Mobile app, SMS, phone call, or U2F security key.", + "description": "'Duo Security' and 'Duo Mobile' are product names and should not be translated." + }, + "webAuthnTitle": { + "message": "FIDO2 WebAuthn" + }, + "webAuthnDesc": { + "message": "Use any WebAuthn compatible security key to access your account." + }, + "emailTitle": { + "message": "Email" + }, + "emailDesc": { + "message": "Verification codes will be emailed to you." + }, + "selfHostedEnvironment": { + "message": "Self-hosted environment" + }, + "selfHostedEnvironmentFooter": { + "message": "Specify the base URL of your on-premises hosted Bitwarden installation." + }, + "customEnvironment": { + "message": "Custom environment" + }, + "customEnvironmentFooter": { + "message": "For advanced users. You can specify the base URL of each service independently." + }, + "baseUrl": { + "message": "Server URL" + }, + "apiUrl": { + "message": "API Server URL" + }, + "webVaultUrl": { + "message": "Web vault server URL" + }, + "identityUrl": { + "message": "Identity server URL" + }, + "notificationsUrl": { + "message": "Notifications server URL" + }, + "iconsUrl": { + "message": "Icons server URL" + }, + "environmentSaved": { + "message": "Environment URLs saved" + }, + "enableAutoFillOnPageLoad": { + "message": "Auto-fill on page load" + }, + "enableAutoFillOnPageLoadDesc": { + "message": "If a login form is detected, auto-fill when the web page loads." + }, + "experimentalFeature": { + "message": "Compromised or untrusted websites can exploit auto-fill on page load." + }, + "learnMoreAboutAutofill": { + "message": "Learn more about auto-fill" + }, + "defaultAutoFillOnPageLoad": { + "message": "Default autofill setting for login items" + }, + "defaultAutoFillOnPageLoadDesc": { + "message": "You can turn off auto-fill on page load for individual login items from the item's Edit view." + }, + "itemAutoFillOnPageLoad": { + "message": "Auto-fill on page load (if set up in Options)" + }, + "autoFillOnPageLoadUseDefault": { + "message": "Use default setting" + }, + "autoFillOnPageLoadYes": { + "message": "Auto-fill on page load" + }, + "autoFillOnPageLoadNo": { + "message": "Do not auto-fill on page load" + }, + "commandOpenPopup": { + "message": "Open vault popup" + }, + "commandOpenSidebar": { + "message": "Open vault in sidebar" + }, + "commandAutofillDesc": { + "message": "Auto-fill the last used login for the current website" + }, + "commandGeneratePasswordDesc": { + "message": "Generate and copy a new random password to the clipboard" + }, + "commandLockVaultDesc": { + "message": "Lock the vault" + }, + "privateModeWarning": { + "message": "Private mode support is experimental and some features are limited." + }, + "customFields": { + "message": "Custom fields" + }, + "copyValue": { + "message": "Copy value" + }, + "value": { + "message": "Value" + }, + "newCustomField": { + "message": "New custom field" + }, + "dragToSort": { + "message": "Drag to sort" + }, + "cfTypeText": { + "message": "Text" + }, + "cfTypeHidden": { + "message": "Hidden" + }, + "cfTypeBoolean": { + "message": "Boolean" + }, + "cfTypeLinked": { + "message": "Linked", + "description": "This describes a field that is 'linked' (tied) to another field." + }, + "linkedValue": { + "message": "Linked value", + "description": "This describes a value that is 'linked' (tied) to another value." + }, + "popup2faCloseMessage": { + "message": "Clicking outside the popup window to check your email for your verification code will cause this popup to close. Do you want to open this popup in a new window so that it does not close?" + }, + "popupU2fCloseMessage": { + "message": "This browser cannot process U2F requests in this popup window. Do you want to open this popup in a new window so that you can log in using U2F?" + }, + "enableFavicon": { + "message": "Show website icons" + }, + "faviconDesc": { + "message": "Show a recognizable image next to each login." + }, + "enableBadgeCounter": { + "message": "Show badge counter" + }, + "badgeCounterDesc": { + "message": "Indicate how many logins you have for the current web page." + }, + "cardholderName": { + "message": "Cardholder name" + }, + "number": { + "message": "Number" + }, + "brand": { + "message": "Brand" + }, + "expirationMonth": { + "message": "Expiration month" + }, + "expirationYear": { + "message": "Expiration year" + }, + "expiration": { + "message": "Expiration" + }, + "january": { + "message": "January" + }, + "february": { + "message": "February" + }, + "march": { + "message": "March" + }, + "april": { + "message": "April" + }, + "may": { + "message": "May" + }, + "june": { + "message": "June" + }, + "july": { + "message": "July" + }, + "august": { + "message": "August" + }, + "september": { + "message": "September" + }, + "october": { + "message": "October" + }, + "november": { + "message": "November" + }, + "december": { + "message": "December" + }, + "securityCode": { + "message": "Security code" + }, + "ex": { + "message": "ex." + }, + "title": { + "message": "Title" + }, + "mr": { + "message": "Mr" + }, + "mrs": { + "message": "Mrs" + }, + "ms": { + "message": "Ms" + }, + "dr": { + "message": "Dr" + }, + "mx": { + "message": "Mx" + }, + "firstName": { + "message": "First name" + }, + "middleName": { + "message": "Middle name" + }, + "lastName": { + "message": "Last name" + }, + "fullName": { + "message": "Full name" + }, + "identityName": { + "message": "Identity name" + }, + "company": { + "message": "Company" + }, + "ssn": { + "message": "Social Security number" + }, + "passportNumber": { + "message": "Passport number" + }, + "licenseNumber": { + "message": "License number" + }, + "email": { + "message": "Email" + }, + "phone": { + "message": "Phone" + }, + "address": { + "message": "Address" + }, + "address1": { + "message": "Address 1" + }, + "address2": { + "message": "Address 2" + }, + "address3": { + "message": "Address 3" + }, + "cityTown": { + "message": "City / Town" + }, + "stateProvince": { + "message": "State / Province" + }, + "zipPostalCode": { + "message": "Zip / Postal code" + }, + "country": { + "message": "Country" + }, + "type": { + "message": "Type" + }, + "typeLogin": { + "message": "Login" + }, + "typeLogins": { + "message": "Logins" + }, + "typeSecureNote": { + "message": "Secure note" + }, + "typeCard": { + "message": "Card" + }, + "typeIdentity": { + "message": "Identity" + }, + "passwordHistory": { + "message": "Password history" + }, + "back": { + "message": "Back" + }, + "collections": { + "message": "Collections" + }, + "favorites": { + "message": "Favorites" + }, + "popOutNewWindow": { + "message": "Pop out to a new window" + }, + "refresh": { + "message": "Refresh" + }, + "cards": { + "message": "Cards" + }, + "identities": { + "message": "Identities" + }, + "logins": { + "message": "Logins" + }, + "secureNotes": { + "message": "Secure notes" + }, + "clear": { + "message": "Clear", + "description": "To clear something out. example: To clear browser history." + }, + "checkPassword": { + "message": "Check if password has been exposed." + }, + "passwordExposed": { + "message": "This password has been exposed $VALUE$ time(s) in data breaches. You should change it.", + "placeholders": { + "value": { + "content": "$1", + "example": "2" + } + } + }, + "passwordSafe": { + "message": "This password was not found in any known data breaches. It should be safe to use." + }, + "baseDomain": { + "message": "Base domain", + "description": "Domain name. Ex. website.com" + }, + "domainName": { + "message": "Domain name", + "description": "Domain name. Ex. website.com" + }, + "host": { + "message": "Host", + "description": "A URL's host value. For example, the host of https://sub.domain.com:443 is 'sub.domain.com:443'." + }, + "exact": { + "message": "Exact" + }, + "startsWith": { + "message": "Starts with" + }, + "regEx": { + "message": "Regular expression", + "description": "A programming term, also known as 'RegEx'." + }, + "matchDetection": { + "message": "Match detection", + "description": "URI match detection for auto-fill." + }, + "defaultMatchDetection": { + "message": "Default match detection", + "description": "Default URI match detection for auto-fill." + }, + "toggleOptions": { + "message": "Toggle options" + }, + "toggleCurrentUris": { + "message": "Toggle current URIs", + "description": "Toggle the display of the URIs of the currently open tabs in the browser." + }, + "currentUri": { + "message": "Current URI", + "description": "The URI of one of the current open tabs in the browser." + }, + "organization": { + "message": "Organization", + "description": "An entity of multiple related people (ex. a team or business organization)." + }, + "types": { + "message": "Types" + }, + "allItems": { + "message": "All items" + }, + "noPasswordsInList": { + "message": "There are no passwords to list." + }, + "remove": { + "message": "Remove" + }, + "default": { + "message": "Default" + }, + "dateUpdated": { + "message": "Updated", + "description": "ex. Date this item was updated" + }, + "dateCreated": { + "message": "Created", + "description": "ex. Date this item was created" + }, + "datePasswordUpdated": { + "message": "Password updated", + "description": "ex. Date this password was updated" + }, + "neverLockWarning": { + "message": "Are you sure you want to use the \"Never\" option? Setting your lock options to \"Never\" stores your vault's encryption key on your device. If you use this option you should ensure that you keep your device properly protected." + }, + "noOrganizationsList": { + "message": "You do not belong to any organizations. Organizations allow you to securely share items with other users." + }, + "noCollectionsInList": { + "message": "There are no collections to list." + }, + "ownership": { + "message": "Ownership" + }, + "whoOwnsThisItem": { + "message": "Who owns this item?" + }, + "strong": { + "message": "Strong", + "description": "ex. A strong password. Scale: Weak -> Good -> Strong" + }, + "good": { + "message": "Good", + "description": "ex. A good password. Scale: Weak -> Good -> Strong" + }, + "weak": { + "message": "Weak", + "description": "ex. A weak password. Scale: Weak -> Good -> Strong" + }, + "weakMasterPassword": { + "message": "Weak master password" + }, + "weakMasterPasswordDesc": { + "message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?" + }, + "pin": { + "message": "PIN", + "description": "PIN code. Ex. The short code (often numeric) that you use to unlock a device." + }, + "unlockWithPin": { + "message": "Unlock with PIN" + }, + "setYourPinCode": { + "message": "Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if you ever fully log out of the application." + }, + "pinRequired": { + "message": "PIN code is required." + }, + "invalidPin": { + "message": "Invalid PIN code." + }, + "unlockWithBiometrics": { + "message": "Unlock with biometrics" + }, + "awaitDesktop": { + "message": "Awaiting confirmation from desktop" + }, + "awaitDesktopDesc": { + "message": "Please confirm using biometrics in the Bitwarden desktop application to set up biometrics for browser." + }, + "lockWithMasterPassOnRestart": { + "message": "Lock with master password on browser restart" + }, + "selectOneCollection": { + "message": "You must select at least one collection." + }, + "cloneItem": { + "message": "Clone item" + }, + "clone": { + "message": "Clone" + }, + "passwordGeneratorPolicyInEffect": { + "message": "One or more organization policies are affecting your generator settings." + }, + "vaultTimeoutAction": { + "message": "Vault timeout action" + }, + "lock": { + "message": "Lock", + "description": "Verb form: to make secure or inaccesible by" + }, + "trash": { + "message": "Trash", + "description": "Noun: a special folder to hold deleted items" + }, + "searchTrash": { + "message": "Search trash" + }, + "permanentlyDeleteItem": { + "message": "Permanently delete item" + }, + "permanentlyDeleteItemConfirmation": { + "message": "Are you sure you want to permanently delete this item?" + }, + "permanentlyDeletedItem": { + "message": "Item permanently deleted" + }, + "restoreItem": { + "message": "Restore item" + }, + "restoreItemConfirmation": { + "message": "Are you sure you want to restore this item?" + }, + "restoredItem": { + "message": "Item restored" + }, + "vaultTimeoutLogOutConfirmation": { + "message": "Logging out will remove all access to your vault and requires online authentication after the timeout period. Are you sure you want to use this setting?" + }, + "vaultTimeoutLogOutConfirmationTitle": { + "message": "Timeout action confirmation" + }, + "autoFillAndSave": { + "message": "Auto-fill and save" + }, + "autoFillSuccessAndSavedUri": { + "message": "Item auto-filled and URI saved" + }, + "autoFillSuccess": { + "message": "Item auto-filled " + }, + "setMasterPassword": { + "message": "Set master password" + }, + "masterPasswordPolicyInEffect": { + "message": "One or more organization policies require your master password to meet the following requirements:" + }, + "policyInEffectMinComplexity": { + "message": "Minimum complexity score of $SCORE$", + "placeholders": { + "score": { + "content": "$1", + "example": "4" + } + } + }, + "policyInEffectMinLength": { + "message": "Minimum length of $LENGTH$", + "placeholders": { + "length": { + "content": "$1", + "example": "14" + } + } + }, + "policyInEffectUppercase": { + "message": "Contain one or more uppercase characters" + }, + "policyInEffectLowercase": { + "message": "Contain one or more lowercase characters" + }, + "policyInEffectNumbers": { + "message": "Contain one or more numbers" + }, + "policyInEffectSpecial": { + "message": "Contain one or more of the following special characters $CHARS$", + "placeholders": { + "chars": { + "content": "$1", + "example": "!@#$%^&*" + } + } + }, + "masterPasswordPolicyRequirementsNotMet": { + "message": "Your new master password does not meet the policy requirements." + }, + "acceptPolicies": { + "message": "By checking this box you agree to the following:" + }, + "acceptPoliciesRequired": { + "message": "Terms of Service and Privacy Policy have not been acknowledged." + }, + "termsOfService": { + "message": "Terms of Service" + }, + "privacyPolicy": { + "message": "Privacy Policy" + }, + "hintEqualsPassword": { + "message": "Your password hint cannot be the same as your password." + }, + "ok": { + "message": "Ok" + }, + "desktopSyncVerificationTitle": { + "message": "Desktop sync verification" + }, + "desktopIntegrationVerificationText": { + "message": "Please verify that the desktop application shows this fingerprint: " + }, + "desktopIntegrationDisabledTitle": { + "message": "Browser integration is not set up" + }, + "desktopIntegrationDisabledDesc": { + "message": "Browser integration is not set up in the Bitwarden desktop application. Please set it up in the settings within the desktop application." + }, + "startDesktopTitle": { + "message": "Start the Bitwarden desktop application" + }, + "startDesktopDesc": { + "message": "The Bitwarden desktop application needs to be started before unlock with biometrics can be used." + }, + "errorEnableBiometricTitle": { + "message": "Unable to set up biometrics" + }, + "errorEnableBiometricDesc": { + "message": "Action was canceled by the desktop application" + }, + "nativeMessagingInvalidEncryptionDesc": { + "message": "Desktop application invalidated the secure communication channel. Please retry this operation" + }, + "nativeMessagingInvalidEncryptionTitle": { + "message": "Desktop communication interrupted" + }, + "nativeMessagingWrongUserDesc": { + "message": "The desktop application is logged into a different account. Please ensure both applications are logged into the same account." + }, + "nativeMessagingWrongUserTitle": { + "message": "Account missmatch" + }, + "biometricsNotEnabledTitle": { + "message": "Biometrics not set up" + }, + "biometricsNotEnabledDesc": { + "message": "Browser biometrics requires desktop biometric to be set up in the settings first." + }, + "biometricsNotSupportedTitle": { + "message": "Biometrics not supported" + }, + "biometricsNotSupportedDesc": { + "message": "Browser biometrics is not supported on this device." + }, + "nativeMessaginPermissionErrorTitle": { + "message": "Permission not provided" + }, + "nativeMessaginPermissionErrorDesc": { + "message": "Without permission to communicate with the Bitwarden Desktop Application we cannot provide biometrics in the browser extension. Please try again." + }, + "nativeMessaginPermissionSidebarTitle": { + "message": "Permission request error" + }, + "nativeMessaginPermissionSidebarDesc": { + "message": "This action cannot be done in the sidebar, please retry the action in the popup or popout." + }, + "personalOwnershipSubmitError": { + "message": "Due to an Enterprise Policy, you are restricted from saving items to your personal vault. Change the Ownership option to an organization and choose from available collections." + }, + "personalOwnershipPolicyInEffect": { + "message": "An organization policy is affecting your ownership options." + }, + "excludedDomains": { + "message": "Excluded domains" + }, + "excludedDomainsDesc": { + "message": "Bitwarden will not ask to save login details for these domains. You must refresh the page for changes to take effect." + }, + "excludedDomainsInvalidDomain": { + "message": "$DOMAIN$ is not a valid domain", + "placeholders": { + "domain": { + "content": "$1", + "example": "googlecom" + } + } + }, + "send": { + "message": "Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "searchSends": { + "message": "Search Sends", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "addSend": { + "message": "Add Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "sendTypeText": { + "message": "Text" + }, + "sendTypeFile": { + "message": "File" + }, + "allSends": { + "message": "All Sends", + "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", + "description": "This text will be displayed after a Send has been accessed the maximum amount of times." + }, + "expired": { + "message": "Expired" + }, + "pendingDeletion": { + "message": "Pending deletion" + }, + "passwordProtected": { + "message": "Password protected" + }, + "copySendLink": { + "message": "Copy Send link", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "removePassword": { + "message": "Remove Password" + }, + "delete": { + "message": "Delete" + }, + "removedPassword": { + "message": "Password removed" + }, + "deletedSend": { + "message": "Send deleted", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "sendLink": { + "message": "Send link", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "disabled": { + "message": "Disabled" + }, + "removePasswordConfirmation": { + "message": "Are you sure you want to remove the password?" + }, + "deleteSend": { + "message": "Delete Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "deleteSendConfirmation": { + "message": "Are you sure you want to delete this Send?", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "editSend": { + "message": "Edit Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "sendTypeHeader": { + "message": "What type of Send is this?", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "sendNameDesc": { + "message": "A friendly name to describe this Send.", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "sendFileDesc": { + "message": "The file you want to send." + }, + "deletionDate": { + "message": "Deletion date" + }, + "deletionDateDesc": { + "message": "The Send will be permanently deleted on the specified date and time.", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "expirationDate": { + "message": "Expiration date" + }, + "expirationDateDesc": { + "message": "If set, access to this Send will expire on the specified date and time.", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "oneDay": { + "message": "1 day" + }, + "days": { + "message": "$DAYS$ days", + "placeholders": { + "days": { + "content": "$1", + "example": "2" + } + } + }, + "custom": { + "message": "Custom" + }, + "maximumAccessCount": { + "message": "Maximum Access Count" + }, + "maximumAccessCountDesc": { + "message": "If set, users will no longer be able to access this Send once the maximum access count is reached.", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "sendPasswordDesc": { + "message": "Optionally require a password for users to access this Send.", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "sendNotesDesc": { + "message": "Private notes about this Send.", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "sendDisableDesc": { + "message": "Deactivate this Send so that no one can access it.", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "sendShareDesc": { + "message": "Copy this Send's link to clipboard upon save.", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "sendTextDesc": { + "message": "The text you want to send." + }, + "sendHideText": { + "message": "Hide this Send's text by default.", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "currentAccessCount": { + "message": "Current access count" + }, + "createSend": { + "message": "New Send", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "newPassword": { + "message": "New password" + }, + "sendDisabled": { + "message": "Send removed", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "sendDisabledWarning": { + "message": "Due to an enterprise policy, you are only able to delete an existing Send.", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "createdSend": { + "message": "Send created", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "editedSend": { + "message": "Send saved", + "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." + }, + "sendLinuxChromiumFileWarning": { + "message": "In order to choose a file, open the extension in the sidebar (if possible) or pop out to a new window by clicking this banner." + }, + "sendFirefoxFileWarning": { + "message": "In order to choose a file using Firefox, open the extension in the sidebar or pop out to a new window by clicking this banner." + }, + "sendSafariFileWarning": { + "message": "In order to choose a file using Safari, pop out to a new window by clicking this banner." + }, + "sendFileCalloutHeader": { + "message": "Before you start" + }, + "sendFirefoxCustomDatePopoutMessage1": { + "message": "To use a calendar style date picker", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read '**To use a calendar style date picker ** click here to pop out your window.'" + }, + "sendFirefoxCustomDatePopoutMessage2": { + "message": "click here", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'To use a calendar style date picker **click here** to pop out your window.'" + }, + "sendFirefoxCustomDatePopoutMessage3": { + "message": "to pop out your window.", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'To use a calendar style date picker click here **to pop out your window.**'" + }, + "expirationDateIsInvalid": { + "message": "The expiration date provided is not valid." + }, + "deletionDateIsInvalid": { + "message": "The deletion date provided is not valid." + }, + "expirationDateAndTimeRequired": { + "message": "An expiration date and time are required." + }, + "deletionDateAndTimeRequired": { + "message": "A deletion date and time are required." + }, + "dateParsingError": { + "message": "There was an error saving your deletion and expiration dates." + }, + "hideEmail": { + "message": "Hide my email address from recipients." + }, + "sendOptionsPolicyInEffect": { + "message": "One or more organization policies are affecting your Send options." + }, + "passwordPrompt": { + "message": "Master password re-prompt" + }, + "passwordConfirmation": { + "message": "Master password confirmation" + }, + "passwordConfirmationDesc": { + "message": "This action is protected. To continue, please re-enter your master password to verify your identity." + }, + "emailVerificationRequired": { + "message": "Email verification required" + }, + "emailVerificationRequiredDesc": { + "message": "You must verify your email to use this feature. You can verify your email in the web vault." + }, + "updatedMasterPassword": { + "message": "Updated master password" + }, + "updateMasterPassword": { + "message": "Update master password" + }, + "updateMasterPasswordWarning": { + "message": "Your master password was recently changed by an administrator in your organization. In order to access the vault, you must update it now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour." + }, + "resetPasswordPolicyAutoEnroll": { + "message": "Automatic enrollment" + }, + "resetPasswordAutoEnrollInviteWarning": { + "message": "This organization has an enterprise policy that will automatically enroll you in password reset. Enrollment will allow organization administrators to change your master password." + }, + "selectFolder": { + "message": "Select folder..." + }, + "ssoCompleteRegistration": { + "message": "In order to complete logging in with SSO, please set a master password to access and protect your vault." + }, + "hours": { + "message": "Hours" + }, + "minutes": { + "message": "Minutes" + }, + "vaultTimeoutPolicyInEffect": { + "message": "Your organization policies are affecting your vault timeout. Maximum allowed Vault Timeout is $HOURS$ hour(s) and $MINUTES$ minute(s)", + "placeholders": { + "hours": { + "content": "$1", + "example": "5" + }, + "minutes": { + "content": "$2", + "example": "5" + } + } + }, + "vaultTimeoutTooLarge": { + "message": "Your vault timeout exceeds the restrictions set by your organization." + }, + "vaultExportDisabled": { + "message": "Vault export unavailable" + }, + "personalVaultExportPolicyInEffect": { + "message": "One or more organization policies prevents you from exporting your individual vault." + }, + "copyCustomFieldNameInvalidElement": { + "message": "Unable to identify a valid form element. Try inspecting the HTML instead." + }, + "copyCustomFieldNameNotUnique": { + "message": "No unique identifier found." + }, + "convertOrganizationEncryptionDesc": { + "message": "$ORGANIZATION$ is using SSO with a self-hosted key server. A master password is no longer required to log in for members of this organization.", + "placeholders": { + "organization": { + "content": "$1", + "example": "My Org Name" + } + } + }, + "leaveOrganization": { + "message": "Leave organization" + }, + "removeMasterPassword": { + "message": "Remove master password" + }, + "removedMasterPassword": { + "message": "Master password removed" + }, + "leaveOrganizationConfirmation": { + "message": "Are you sure you want to leave this organization?" + }, + "leftOrganization": { + "message": "You have left the organization." + }, + "toggleCharacterCount": { + "message": "Toggle character count" + }, + "sessionTimeout": { + "message": "Your session has timed out. Please go back and try logging in again." + }, + "exportingPersonalVaultTitle": { + "message": "Exporting individual vault" + }, + "exportingPersonalVaultDescription": { + "message": "Only the individual vault items associated with $EMAIL$ will be exported. Organization vault items will not be included.", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "error": { + "message": "Error" + }, + "regenerateUsername": { + "message": "Regenerate username" + }, + "generateUsername": { + "message": "Generate username" + }, + "usernameType": { + "message": "Username type" + }, + "plusAddressedEmail": { + "message": "Plus addressed email", + "description": "Username generator option that appends a random sub-address to the username. For example: address+subaddress@email.com" + }, + "plusAddressedEmailDesc": { + "message": "Use your email provider's sub-addressing capabilities." + }, + "catchallEmail": { + "message": "Catch-all email" + }, + "catchallEmailDesc": { + "message": "Use your domain's configured catch-all inbox." + }, + "random": { + "message": "Random" + }, + "randomWord": { + "message": "Random word" + }, + "websiteName": { + "message": "Website name" + }, + "whatWouldYouLikeToGenerate": { + "message": "What would you like to generate?" + }, + "passwordType": { + "message": "Password type" + }, + "service": { + "message": "Service" + }, + "forwardedEmail": { + "message": "Forwarded email alias" + }, + "forwardedEmailDesc": { + "message": "Generate an email alias with an external forwarding service." + }, + "hostname": { + "message": "Hostname", + "description": "Part of a URL." + }, + "apiAccessToken": { + "message": "API Access Token" + }, + "apiKey": { + "message": "API Key" + }, + "ssoKeyConnectorError": { + "message": "Key connector error: make sure key connector is available and working correctly." + }, + "premiumSubcriptionRequired": { + "message": "Premium subscription required" + }, + "organizationIsDisabled": { + "message": "Organization suspended." + }, + "disabledOrganizationFilterError": { + "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." + }, + "loggingInTo": { + "message": "Logging in to $DOMAIN$", + "placeholders": { + "domain": { + "content": "$1", + "example": "example.com" + } + } + }, + "settingsEdited": { + "message": "Settings have been edited" + }, + "environmentEditedClick": { + "message": "Click here" + }, + "environmentEditedReset": { + "message": "to reset to pre-configured settings" + }, + "serverVersion": { + "message": "Server version" + }, + "selfHosted": { + "message": "Self-hosted" + }, + "thirdParty": { + "message": "Third-party" + }, + "thirdPartyServerMessage": { + "message": "Connected to third-party server implementation, $SERVERNAME$. Please verify bugs using the official server, or report them to the third-party server.", + "placeholders": { + "servername": { + "content": "$1", + "example": "ThirdPartyServerName" + } + } + }, + "lastSeenOn": { + "message": "last seen on: $DATE$", + "placeholders": { + "date": { + "content": "$1", + "example": "Jun 15, 2015" + } + } + }, + "loginWithMasterPassword": { + "message": "Log in with master password" + }, + "loggingInAs": { + "message": "Logging in as" + }, + "notYou": { + "message": "Not you?" + }, + "newAroundHere": { + "message": "New around here?" + }, + "rememberEmail": { + "message": "Remember email" + }, + "loginWithDevice": { + "message": "Log in with device" + }, + "loginWithDeviceEnabledInfo": { + "message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?" + }, + "fingerprintPhraseHeader": { + "message": "Fingerprint phrase" + }, + "fingerprintMatchInfo": { + "message": "Please make sure your vault is unlocked and the Fingerprint phrase matches on the other device." + }, + "resendNotification": { + "message": "Resend notification" + }, + "viewAllLoginOptions": { + "message": "View all log in options" + }, + "notificationSentDevice": { + "message": "A notification has been sent to your device." + }, + "logInInitiated": { + "message": "Log in initiated" + }, + "exposedMasterPassword": { + "message": "Exposed Master Password" + }, + "exposedMasterPasswordDesc": { + "message": "Password found in a data breach. Use a unique password to protect your account. Are you sure you want to use an exposed password?" + }, + "weakAndExposedMasterPassword": { + "message": "Weak and Exposed Master Password" + }, + "weakAndBreachedMasterPasswordDesc": { + "message": "Weak password identified and found in a data breach. Use a strong and unique password to protect your account. Are you sure you want to use this password?" + }, + "checkForBreaches": { + "message": "Check known data breaches for this password" + }, + "important": { + "message": "Important:" + }, + "masterPasswordHint": { + "message": "Your master password cannot be recovered if you forget it!" + }, + "characterMinimum": { + "message": "$LENGTH$ character minimum", + "placeholders": { + "length": { + "content": "$1", + "example": "14" + } + } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + } +} diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json index b5d47c11f2d..7c5aefecae8 100644 --- a/apps/browser/src/_locales/nb/messages.json +++ b/apps/browser/src/_locales/nb/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Hjelp og tilbakemelding" }, + "helpCenter": { + "message": "Bitwarden hjelpesenter" + }, + "communityForums": { + "message": "Utforsk Bitwardens community forum" + }, + "contactSupport": { + "message": "Kontakt Bitwarden brukerstøtte" + }, "sync": { "message": "Synkroniser" }, @@ -430,7 +439,14 @@ "message": "Skriv inn hovedpassordet på nytt." }, "masterPasswordMinlength": { - "message": "Hovedpassordet må være minst åtte tegn." + "message": "Hovedpassordet må være minst $VALUE$ tegn.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Superpassord-bekreftelsen er ikke samsvarende." @@ -960,10 +976,10 @@ "message": "Dersom et innloggingskjema blir oppdaget, utfør automatisk en auto-utfylling når nettstedet lastes inn." }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "Kompromitterte eller upålitelige nettsider kan utnytte auto-utfylling når du laster inn siden." }, "learnMoreAboutAutofill": { - "message": "Learn more about auto-fill" + "message": "Lær mer om auto-utfylling" }, "defaultAutoFillOnPageLoad": { "message": "Standard autofyll innstilling for innloggingselementer" @@ -1127,7 +1143,7 @@ "message": "Dr." }, "mx": { - "message": "Mx" + "message": "Nøytral" }, "firstName": { "message": "Fornavn" @@ -1396,7 +1412,7 @@ "message": "Klon" }, "passwordGeneratorPolicyInEffect": { - "message": "En eller flere av organisasjonens vilkår påvirker generatorinnstillingene dine." + "message": "En eller flere av virksomhetens regler påvirker generatorinnstillingene dine." }, "vaultTimeoutAction": { "message": "Handling ved tidsavbrudd i hvelvet" @@ -1449,7 +1465,7 @@ "message": "Angi hovedpassord" }, "masterPasswordPolicyInEffect": { - "message": "Ett eller flere av organisasjonens vilkår krever at hovedpassordet oppfyller følgende krav:" + "message": "En eller flere av virksomhetens regler krever at hovedpassordet oppfyller følgende krav:" }, "policyInEffectMinComplexity": { "message": "Minimumspoengsum for kompleksistet er $SCORE$", @@ -1488,7 +1504,7 @@ } }, "masterPasswordPolicyRequirementsNotMet": { - "message": "Det nye hovedpassordet ditt oppfyller ikke vilkårene." + "message": "Det nye hovedpassordet ditt oppfyller ikke vilkår i virksomhetsreglene." }, "acceptPolicies": { "message": "Ved å merke av denne boksen sier du deg enig i følgende:" @@ -1569,10 +1585,10 @@ "message": "Denne handlingen kan ikke gjøres i sidestolpen, prøv på nytt i sprettoppvinduet eller popvindu." }, "personalOwnershipSubmitError": { - "message": "På grunn av bedrifsretningslinjer er du begrenset fra å lagre objekter til ditt personlige hvelv. Endre alternativ for eierskap til en organisasjon og velg blant tilgjengelige samlinger." + "message": "På grunn av en virksomhetsregel er du begrenset fra å lagre objekter til ditt personlige hvelv. Endre alternativ for eierskap til en organisasjon og velg blant tilgjengelige samlinger." }, "personalOwnershipPolicyInEffect": { - "message": "En bedriftsretningslinje påvirker dine eierskapsinnstillinger." + "message": "En virksomhetsregel påvirker dine eierskapsinnstillinger." }, "excludedDomains": { "message": "Ekskluderte domener" @@ -1802,7 +1818,7 @@ "message": "Skjul min e-postadresse fra mottakere." }, "sendOptionsPolicyInEffect": { - "message": "En eller flere av organisasjons retningslinjer påvirker generatorinnstillingene dine." + "message": "En eller flere av virksomhetens regler påvirker generatorinnstillingene dine." }, "passwordPrompt": { "message": "Forespørsel om hovedpassord på nytt" @@ -1832,7 +1848,7 @@ "message": "Automatisk registrering" }, "resetPasswordAutoEnrollInviteWarning": { - "message": "Denne organisasjonen har en bedriftsoppsettsregel som automatisk innrullerer deg i tilbakestilling av passord. Registrering vil tillate organisasjonsadministratorer å endre hovedpassordet ditt." + "message": "Denne organisasjonen har en virksomhetsregel som automatisk innrullerer deg i tilbakestilling av passord. Registrering vil tillate organisasjonsadministratorer å endre hovedpassordet ditt." }, "selectFolder": { "message": "Velg mappe …" @@ -1847,7 +1863,7 @@ "message": "Minutter" }, "vaultTimeoutPolicyInEffect": { - "message": "Organisasjonens retningslinjer påvirker tidsavbruddet for hvelvet ditt. Maksimalt tillatt tidsavbrudd for hvelv er $HOURS$ time(r) og $MINUTES$ minutt(er)", + "message": "Din virksomhets regler påvirker tidsavbruddet for hvelvet ditt. Maksimalt tillatt tidsavbrudd for hvelv er $HOURS$ time(r) og $MINUTES$ minutt(er)", "placeholders": { "hours": { "content": "$1", @@ -1866,7 +1882,7 @@ "message": "Hvelveksportering er skrudd av" }, "personalVaultExportPolicyInEffect": { - "message": "En eller flere regler i organisasjonsoppsettet forhindrer deg i å eksportere ditt personlige hvelv." + "message": "En eller flere virksomhetsregler forhindrer deg i å eksportere ditt personlige hvelv." }, "copyCustomFieldNameInvalidElement": { "message": "Klarte ikke å identifisere et gyldig skjemaelement. Prøv å inspisere HTML-en i stedet." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Elementer i deaktiverte organisasjoner kan ikke aksesseres. Kontakt organisasjonseier for hjelp." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logger inn på $DOMAIN$", "placeholders": { @@ -2051,28 +2064,28 @@ "message": "Husk e-post" }, "loginWithDevice": { - "message": "Log in with device" + "message": "Logg inn med enhet" }, "loginWithDeviceEnabledInfo": { - "message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?" + "message": "Logg på med enhet må settes opp i Bitwarden-innstillingene. Trenger du et annet alternativ?" }, "fingerprintPhraseHeader": { - "message": "Fingerprint phrase" + "message": "Fingeravtrykksfrase" }, "fingerprintMatchInfo": { - "message": "Please make sure your vault is unlocked and the Fingerprint phrase matches on the other device." + "message": "Kontroller at hvelvet ditt er låst opp, og at fingeravtrykksfrasen er lik på den andre enheten." }, "resendNotification": { - "message": "Resend notification" + "message": "Send varslingen på nytt" }, "viewAllLoginOptions": { - "message": "View all log in options" + "message": "Vis alle innloggingsalternativer" }, "notificationSentDevice": { - "message": "A notification has been sent to your device." + "message": "Et varsel er sendt til enheten din." }, "logInInitiated": { - "message": "Log in initiated" + "message": "Innlogging startet" }, "exposedMasterPassword": { "message": "Eksponert hovedpassord" @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Virksomhetsreglene dine har slått på automatisk utfylling av sidene." + }, + "howToAutofill": { + "message": "Hvordan bruke auto-utfylling" + }, + "autofillSelectInfoWithCommand": { + "message": "Velg et element fra denne siden eller bruk snarveien: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Velg et element fra denne siden eller angi en snarvei i innstillingene." + }, + "gotIt": { + "message": "Skjønner" + }, + "autofillSettings": { + "message": "Innstillinger for auto-utfylling" + }, + "autofillShortcut": { + "message": "Auto-utfyll tastatursnarvei" + }, + "autofillShortcutNotSet": { + "message": "Snarveien for automatisk utfylling er ikke angitt. Endre dette i nettleserens innstillinger." + }, + "autofillShortcutText": { + "message": "Snarveien for automatisk utfylling er: $COMMAND$. Endre dette i nettleserens innstillinger.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Standard auto-utfyllingssnarvei: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/ne/messages.json b/apps/browser/src/_locales/ne/messages.json index 9c228a74174..8f6d3d0da96 100644 --- a/apps/browser/src/_locales/ne/messages.json +++ b/apps/browser/src/_locales/ne/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Help & feedback" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Sync" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Master password confirmation does not match." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json index 5100e36c452..c04c806e3bb 100644 --- a/apps/browser/src/_locales/nl/messages.json +++ b/apps/browser/src/_locales/nl/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Help & reacties" }, + "helpCenter": { + "message": "Bitwarden Hulpcentrum" + }, + "communityForums": { + "message": "Ontdek Bitwarden community-forums" + }, + "contactSupport": { + "message": "Contacteer Bitwarden support" + }, "sync": { "message": "Synchroniseren" }, @@ -430,7 +439,14 @@ "message": "Type je hoofdwachtwoord opnieuw in." }, "masterPasswordMinlength": { - "message": "Het hoofdwachtwoord moet minimaal 8 tekens lang zijn." + "message": "Hoofdwachtwoord moet minstens $VALUE$ tekens lang zijn.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "De hoofdwachtwoorden komen niet overeen." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Je kunt uitgeschakelde items in een organisatie niet benaderen. Neem contact op met de eigenaar van je organisatie voor hulp." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Inloggen op $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Je organisatiebeleid heeft het automatisch invullen bij laden van pagina ingeschakeld." + }, + "howToAutofill": { + "message": "Hoe automatisch aanvullen" + }, + "autofillSelectInfoWithCommand": { + "message": "Selecteer een item op deze pagina of gebruik de snelkoppeling: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Selecteer een item op deze pagina of stel een snelkoppeling in via instellingen." + }, + "gotIt": { + "message": "Ik snap het" + }, + "autofillSettings": { + "message": "Instellingen automatisch invullen" + }, + "autofillShortcut": { + "message": "Snelkoppeling automatisch invullen" + }, + "autofillShortcutNotSet": { + "message": "De sneltoets voor automatisch invullen is niet ingesteld. Wijzig dit in de instellingen van de browser." + }, + "autofillShortcutText": { + "message": "De sneltoets voor automatisch invullen is: $COMMAND$. Wijzig dit in de instellingen van de browser.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Standaard snelkoppeling voor automatisch invullen:: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json index 9c228a74174..8f6d3d0da96 100644 --- a/apps/browser/src/_locales/nn/messages.json +++ b/apps/browser/src/_locales/nn/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Help & feedback" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Sync" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Master password confirmation does not match." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index 0f30b493cca..8ea3cec11ba 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Pomoc i opinie" }, + "helpCenter": { + "message": "Centrum pomocy Bitwarden" + }, + "communityForums": { + "message": "Przeglądaj fora społeczności Bitwarden" + }, + "contactSupport": { + "message": "Skontaktuj się z pomocą techniczną Bitwarden" + }, "sync": { "message": "Synchronizacja" }, @@ -430,7 +439,14 @@ "message": "Wymagane jest ponowne wpisanie hasła głównego." }, "masterPasswordMinlength": { - "message": "Hasło główne musi zawierać co najmniej 8 znaków." + "message": "Hasło główne musi zawierać co najmniej $VALUE$ znaki(-ów).", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Hasła nie pasują do siebie." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Nie można uzyskać dostępu do elementów w zawieszonych organizacjach. Skontaktuj się z właścicielem organizacji, aby uzyskać pomoc." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logowanie do $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Twoja organizacji włączyła autouzupełnianie podczas wczytywania strony." + }, + "howToAutofill": { + "message": "Jak autouzupełniać" + }, + "autofillSelectInfoWithCommand": { + "message": "Wybierz element z tej strony lub użyj skrótu: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Wybierz element z tej strony lub ustaw skrót w ustawieniach." + }, + "gotIt": { + "message": "Rozumiem" + }, + "autofillSettings": { + "message": "Ustawienia autouzupełniania" + }, + "autofillShortcut": { + "message": "Skrót klawiaturowy autouzupełniania" + }, + "autofillShortcutNotSet": { + "message": "Skrót autouzupełniania nie jest ustawiony. Zmień to w ustawieniach przeglądarki." + }, + "autofillShortcutText": { + "message": "Skrót autouzupełniania to: $COMMAND$. Zmień to w ustawieniach przeglądarki.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Domyślny skrót autouzupełniania: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index bc614644f4e..edb53d548db 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Ajuda & Feedback" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Sincronizar" }, @@ -245,7 +254,7 @@ "message": "Números (0-9)" }, "specialCharacters": { - "message": "Caracteres Especiais (!@#$%^&*)" + "message": "Caracteres especiais (!@#$%^&*)" }, "numWords": { "message": "Número de Palavras" @@ -424,13 +433,20 @@ "message": "Endereço de e-mail inválido." }, "masterPasswordRequired": { - "message": "A senha mestre é obrigatória." + "message": "A senha mestra é obrigatória." }, "confirmMasterPasswordRequired": { - "message": "É necessário redigitar a senha mestre." + "message": "É necessário redigitar a senha mestra." }, "masterPasswordMinlength": { - "message": "A senha mestre deve ter pelo menos 8 caracteres." + "message": "A senha mestra deve ter pelo menos $VALUE$ caracteres.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "A confirmação da senha mestra não corresponde." @@ -649,7 +665,7 @@ "message": "Exportar Cofre" }, "fileFormat": { - "message": "Formato do Arquivo" + "message": "Formato de arquivo" }, "warning": { "message": "AVISO", @@ -744,7 +760,7 @@ "message": "O tamanho máximo do arquivo é de 500 MB." }, "featureUnavailable": { - "message": "Recurso Indisponível" + "message": "Funcionalidade Indisponível" }, "updateKey": { "message": "Você não pode usar este recurso, até você atualizar sua chave de criptografia." @@ -762,10 +778,10 @@ "message": "Atualizar Assinatura" }, "premiumNotCurrentMember": { - "message": "Você não é atualmente um membro premium." + "message": "Você não é um membro Premium atualmente." }, "premiumSignUpAndGet": { - "message": "Registe-se para uma assinatura premium e obtenha:" + "message": "Registre-se para uma assinatura Premium e obtenha:" }, "ppremiumSignUpStorage": { "message": "1 GB de armazenamento de arquivos encriptados." @@ -783,7 +799,7 @@ "message": "Prioridade no suporte ao cliente." }, "ppremiumSignUpFuture": { - "message": "Todos os recursos premium no futuro. Mais em breve!" + "message": "Todas as funcionalidades Premium no futuro. Mais em breve!" }, "premiumPurchase": { "message": "Comprar Premium" @@ -813,7 +829,7 @@ "message": "Copiar TOTP automaticamente" }, "disableAutoTotpCopyDesc": { - "message": "Se a sua credencial tiver uma chave de autenticação anexada, o código de verificação TOTP será copiado automaticamente para a área de transferência quando você autopreencher a credencial." + "message": "Se sua credencial tiver uma chave de autenticação, copie o código de verificação TOTP quando for autopreenchê-la." }, "enableAutoBiometricsPrompt": { "message": "Pedir biometria ao iniciar" @@ -960,7 +976,7 @@ "message": "Se um formulário de login for detectado, realizar automaticamente um auto-preenchimento quando a página web carregar." }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "Sites comprometidos ou não confiáveis podem tomar vantagem do autopreenchimento ao carregar a página." }, "learnMoreAboutAutofill": { "message": "Saiba mais sobre preenchimento automático" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Itens em Organizações Desativadas não podem ser acessados. Entre em contato com o proprietário da sua Organização para obter assistência." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Fazendo login em $DOMAIN$", "placeholders": { @@ -2051,19 +2064,19 @@ "message": "Lembrar e-mail" }, "loginWithDevice": { - "message": "Log in with device" + "message": "Fazer login com dispositivo" }, "loginWithDeviceEnabledInfo": { - "message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?" + "message": "Login com dispositivo deve ser habilitado nas configurações do aplicativo móvel do Bitwarden. Necessita de outra opção?" }, "fingerprintPhraseHeader": { - "message": "Fingerprint phrase" + "message": "Frase de impressão digital" }, "fingerprintMatchInfo": { - "message": "Please make sure your vault is unlocked and the Fingerprint phrase matches on the other device." + "message": "Certifique-se que o cofre esteja desbloqueado e que a frase de impressão digital corresponda à do outro dispositivo." }, "resendNotification": { - "message": "Resend notification" + "message": "Reenviar notificação" }, "viewAllLoginOptions": { "message": "Ver todas as opções de login" @@ -2072,7 +2085,7 @@ "message": "Uma notificação foi enviada para seu dispositivo." }, "logInInitiated": { - "message": "Log in initiated" + "message": "Login iniciado" }, "exposedMasterPassword": { "message": "Senha Mestra comprometida" @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "Como autopreencher" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Entendi" + }, + "autofillSettings": { + "message": "Configurações de autopreenchimento" + }, + "autofillShortcut": { + "message": "Atalho para autopreenchimento" + }, + "autofillShortcutNotSet": { + "message": "O atalho de preenchimento automático não está definido. Altere-o nas configurações do navegador." + }, + "autofillShortcutText": { + "message": "O atalho de preenchimento automático é: $COMMAND$. Altere-o nas configurações do navegador.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Atalho padrão de autopreenchimento: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json index cc0b04862d2..69c429a5960 100644 --- a/apps/browser/src/_locales/pt_PT/messages.json +++ b/apps/browser/src/_locales/pt_PT/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Ajuda e feedback" }, + "helpCenter": { + "message": "Centrro de ajuda do Bitwarden" + }, + "communityForums": { + "message": "Explorar os fóruns da comunidade do Bitwarden" + }, + "contactSupport": { + "message": "Contactar o suporte do Bitwarden" + }, "sync": { "message": "Sincronizar" }, @@ -430,7 +439,14 @@ "message": "É necessário reescrever a palavra-passe mestra." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "A confirmação da palavra-passe mestra não corresponde." @@ -1741,7 +1757,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "newPassword": { - "message": "New password" + "message": "Nova palavra-passe" }, "sendDisabled": { "message": "Send removed", @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "A iniciar sessão em $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json index f5480ef465e..b4ec3c35518 100644 --- a/apps/browser/src/_locales/ro/messages.json +++ b/apps/browser/src/_locales/ro/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Ajutor și feedback" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Sincronizare" }, @@ -430,7 +439,14 @@ "message": "Este necesară rescrierea parolei principale." }, "masterPasswordMinlength": { - "message": "Parola principală trebuie să aibă cel puțin 8 caractere." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Parola principală și confirmarea ei nu coincid!" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Articolele din Organizații suspendate nu pot fi accesate. Contactați proprietarul Organizației pentru asistență." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Conectarea la $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json index bdc918af1be..db33e2ab4da 100644 --- a/apps/browser/src/_locales/ru/messages.json +++ b/apps/browser/src/_locales/ru/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Помощь и обратная связь" }, + "helpCenter": { + "message": "Справочный центр Bitwarden" + }, + "communityForums": { + "message": "Посетите форумы сообщества Bitwarden" + }, + "contactSupport": { + "message": "Свяжитесь со службой поддержки Bitwarden" + }, "sync": { "message": "Синхронизация" }, @@ -309,7 +318,7 @@ "message": "Папка" }, "deleteItem": { - "message": "Удаление элемента" + "message": "Удалить элемент" }, "viewItem": { "message": "Просмотр элемента" @@ -430,7 +439,14 @@ "message": "Необходимо повторно ввести мастер-пароль." }, "masterPasswordMinlength": { - "message": "Мастер-пароль должен содержать не менее 8 символов." + "message": "Мастер-пароль должен содержать не менее $VALUE$ символов.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Мастер-пароли не совпадают." @@ -1811,7 +1827,7 @@ "message": "Подтверждение мастер-пароля" }, "passwordConfirmationDesc": { - "message": "Это действие защищено. Для продолжения введите свой мастер-пароль, чтобы подтвердить свою личность." + "message": "Это действие защищено. Чтобы продолжить, введите ваш мастер-пароль для подтверждения личности." }, "emailVerificationRequired": { "message": "Требуется подтверждение электронной почты" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Доступ к элементам в отключенных организациях невозможен. Обратитесь за помощью к владельцу организации." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Вход в $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Автозаполнение при загрузке страницы было активировано политиками вашей организации." + }, + "howToAutofill": { + "message": "Как использовать автозаполнение" + }, + "autofillSelectInfoWithCommand": { + "message": "Выберите элемент на этой странице или используйте сочетание клавиш: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Выберите элемент на этой странице или задайте сочетание клавиш в настройках." + }, + "gotIt": { + "message": "Понятно" + }, + "autofillSettings": { + "message": "Настройки автозаполнения" + }, + "autofillShortcut": { + "message": "Сочетание клавиш для автозаполнения" + }, + "autofillShortcutNotSet": { + "message": "Сочетание клавиш для автозаполнения не установлено. Установите его в настройках браузера." + }, + "autofillShortcutText": { + "message": "Сочетание клавиш для автозаполнения: $COMMAND$. Измените его в настройках браузера.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Сочетание клавиш для автозаполнения по умолчанию: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json index a6be566bb75..4e7946dcc2a 100644 --- a/apps/browser/src/_locales/si/messages.json +++ b/apps/browser/src/_locales/si/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "උදව් සහ ප්රතිපෝෂණ" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "සමමුහූර්තනය" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "ප්රධාන මුරපදය තහවුරු කිරීම නොගැලපේ." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json index 38157666ca7..29749b55785 100644 --- a/apps/browser/src/_locales/sk/messages.json +++ b/apps/browser/src/_locales/sk/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Pomoc a spätná väzba" }, + "helpCenter": { + "message": "Centrum pomoci Bitwarden" + }, + "communityForums": { + "message": "Prehliadať komunitné fóra Bitwardenu" + }, + "contactSupport": { + "message": "Kontaktovať podporu Bitwardenu" + }, "sync": { "message": "Synchronizácia" }, @@ -430,7 +439,14 @@ "message": "Vyžaduje sa opätovné zadanie hlavného hesla." }, "masterPasswordMinlength": { - "message": "Hlavné heslo musí obsahovať aspoň 8 znakov." + "message": "Hlavné heslo musí mať aspoň $VALUE$ znakov.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Potvrdenie hlavného hesla sa nezhoduje." @@ -543,7 +559,7 @@ "message": "Naozaj chcete odstrániť túto položku?" }, "deletedItem": { - "message": "Odstránená položka" + "message": "Položka odstránená" }, "overwritePassword": { "message": "Prepísať heslo" @@ -960,7 +976,7 @@ "message": "Ak je detekovaný prihlasovací formulár, automaticky vykonať vypĺňanie pri načítaní stránky." }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "Skompromitované alebo nedôveryhodné stránky môžu pri svojom načítaní zneužiť automatické dopĺňanie." }, "learnMoreAboutAutofill": { "message": "Dozvedieť sa viac o automatickom dopĺňaní" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "K položkám vo vypnutej organizácii nie je možné pristupovať. Požiadajte o pomoc vlastníka organizácie." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Prihlásenie do $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "V pravidlách vašej organizácie je zapnuté automatické vypĺňanie pri načítaní stránky." + }, + "howToAutofill": { + "message": "Ako používať automatické vypĺňanie" + }, + "autofillSelectInfoWithCommand": { + "message": "Vyberte položku z tejto stránky, alebo použite skratku: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Vyberte položku z tejto stránky, alebo nastavte skratku v nastaveniach." + }, + "gotIt": { + "message": "Chápem" + }, + "autofillSettings": { + "message": "Nastavenia automatického vypĺňania" + }, + "autofillShortcut": { + "message": "Klávesová skratka automatického vypĺňania" + }, + "autofillShortcutNotSet": { + "message": "Skratka automatického vypĺňania nie je nastavená. Zmeníte ju v nastaveniach prehliadača." + }, + "autofillShortcutText": { + "message": "Skratka automatického vypĺňania je: $COMMAND$. Zmeníte ju v nastaveniach prehliadača.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Predvolená skratka automatického vypĺňania: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index 47c8e334874..bcd6f9eee1e 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -149,11 +149,11 @@ "message": "Spremeni glavno geslo" }, "fingerprintPhrase": { - "message": "Fingerprint fraza", + "message": "Identifikacijsko geslo", "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "yourAccountsFingerprint": { - "message": "Fingerprint fraza vašega računa", + "message": "Identifikacijsko geslo vašega računa", "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "twoStepLogin": { @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Pomoč in povratne informacije" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Sinhronizacija" }, @@ -291,7 +300,7 @@ "message": "Geslo" }, "passphrase": { - "message": "Parafraza" + "message": "Večbesedno geslo" }, "favorite": { "message": "Priljubljeni" @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Potrditev glavnega gesla se ne ujema." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2057,7 +2070,7 @@ "message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?" }, "fingerprintPhraseHeader": { - "message": "Fingerprint phrase" + "message": "Identifikacijsko geslo" }, "fingerprintMatchInfo": { "message": "Please make sure your vault is unlocked and the Fingerprint phrase matches on the other device." @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index 63cbd16b198..19af58209cb 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -3,15 +3,15 @@ "message": "Bitwarden" }, "extName": { - "message": "Bitwarden - Бесплатни Менаџер Лозинки", + "message": "Bitwarden - бесплатни менаџер лозинки", "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "Сигурни и бесплатни менаџер лозинке за све ваше уређаје.", + "message": "Сигурни и бесплатни менаџер лозинки за све ваше уређаје.", "description": "Extension description" }, "loginOrCreateNewAccount": { - "message": "Пријавите се или креирајте нови налог за приступ Сефу." + "message": "Пријавите се или креирајте нови налог за приступ сефу." }, "createAccount": { "message": "Креирај налог" @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Помоћ и подршка" }, + "helpCenter": { + "message": "Bitwarden помоћни центар" + }, + "communityForums": { + "message": "Претражити форуми заједнице Bitwarden-а" + }, + "contactSupport": { + "message": "Контактирајте подршку Bitwarden-а" + }, "sync": { "message": "Синхронизација" }, @@ -430,7 +439,14 @@ "message": "Поновно уписивање главне лозинке је неопходно." }, "masterPasswordMinlength": { - "message": "Главна лозинка треба имати барем 8 карактера." + "message": "Главна лозинка мора бити дужине најмање $VALUE$ карактера.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Потврда главне лозинке се не подудара." @@ -960,7 +976,7 @@ "message": "Ако се открије образац за пријаву, извршите аутоматско попуњавање када се веб страница учита." }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "Компромитоване или непоуздане веб локације могу да искористе ауто-пуњење при учитавању странице." }, "learnMoreAboutAutofill": { "message": "Сазнајте више о ауто-пуњење" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Није могуће приступити ставкама у онемогућене организације. Обратите се власнику организације за помоћ." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Пријављивање на $DOMAIN$", "placeholders": { @@ -2075,13 +2088,13 @@ "message": "Пријава је покренута" }, "exposedMasterPassword": { - "message": "Exposed Master Password" + "message": "Изложена главна лозинка" }, "exposedMasterPasswordDesc": { "message": "Password found in a data breach. Use a unique password to protect your account. Are you sure you want to use an exposed password?" }, "weakAndExposedMasterPassword": { - "message": "Weak and Exposed Master Password" + "message": "Слаба и изложена главна лозинка" }, "weakAndBreachedMasterPasswordDesc": { "message": "Weak password identified and found in a data breach. Use a strong and unique password to protect your account. Are you sure you want to use this password?" @@ -2090,18 +2103,66 @@ "message": "Check known data breaches for this password" }, "important": { - "message": "Important:" + "message": "Важно:" }, "masterPasswordHint": { - "message": "Your master password cannot be recovered if you forget it!" + "message": "Ваша главна лозинка се не може повратити ако је заборавите!" }, "characterMinimum": { - "message": "$LENGTH$ character minimum", + "message": "Минимум $LENGTH$ карактера", "placeholders": { "length": { "content": "$1", "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Смернице ваше организације су укључиле ауто-пуњење при учитавању странице." + }, + "howToAutofill": { + "message": "Како ауто-попуњавати" + }, + "autofillSelectInfoWithCommand": { + "message": "Изаберите ставку са ове странице или користите пречицу: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Изаберите ставку са ове странице или поставите пречицу у подешавањима." + }, + "gotIt": { + "message": "Разумем" + }, + "autofillSettings": { + "message": "Подешавања Ауто-пуњења" + }, + "autofillShortcut": { + "message": "Пречице Ауто-пуњења" + }, + "autofillShortcutNotSet": { + "message": "Пречица за ауто-попуњавање није подешена. Промените ово у подешавањима претраживача." + }, + "autofillShortcutText": { + "message": "Пречица ауто-пуњења је: $COMMAND$. Промените ово у подешавањима претраживача.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Подразумевана пречица за ауто-пуњење: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index 91b56f4c204..00ec979e51b 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Hjälp & Feedback" }, + "helpCenter": { + "message": "Bitwarden Hjälpcenter" + }, + "communityForums": { + "message": "Utforska Bitwardens communityforum" + }, + "contactSupport": { + "message": "Kontakta Bitwarden support" + }, "sync": { "message": "Synkronisera" }, @@ -430,7 +439,14 @@ "message": "Huvudlösenord måste anges igen." }, "masterPasswordMinlength": { - "message": "Huvudlösenordet måste vara minst 8 tecken långt." + "message": "Huvudlösenordet måste vara minst $VALUE$ tecken långt.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Bekräftelsen för huvudlösenordet stämde ej." @@ -960,10 +976,10 @@ "message": "Utför automatisk ifyllnad om ett inloggningsformulär upptäcks när webbsidan laddas." }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "Komprometterade eller ej betrodda webbplatser kan utnyttja automatisk ifyllnad vid sidladdning." }, "learnMoreAboutAutofill": { - "message": "Learn more about auto-fill" + "message": "Läs mer om automatisk ifyllnad" }, "defaultAutoFillOnPageLoad": { "message": "Standardinställning för autofyll för inloggningsobjekt" @@ -1127,7 +1143,7 @@ "message": "Dr" }, "mx": { - "message": "Mx" + "message": "Vederbörande" }, "firstName": { "message": "Förnamn" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Objekt i inaktiverade organisationer är inte åtkomliga. Kontakta organisationens ägare för att få hjälp." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Loggar in på $DOMAIN$", "placeholders": { @@ -2054,16 +2067,16 @@ "message": "Logga in med enhet" }, "loginWithDeviceEnabledInfo": { - "message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?" + "message": "\"Logga in med enhet\" måste ställas in i inställningarna i Bitwardens app. Behöver du ett annat alternativ?" }, "fingerprintPhraseHeader": { "message": "Fingeravtrycksfras" }, "fingerprintMatchInfo": { - "message": "Please make sure your vault is unlocked and the Fingerprint phrase matches on the other device." + "message": "Se till att ditt valv är upplåst och att fingeravtrycksfrasen matchar på den andra enheten." }, "resendNotification": { - "message": "Resend notification" + "message": "Skicka avisering igen" }, "viewAllLoginOptions": { "message": "Visa alla inloggningsalternativ" @@ -2072,16 +2085,16 @@ "message": "En avisering har skickats till din enhet." }, "logInInitiated": { - "message": "Log in initiated" + "message": "Inloggning påbörjad" }, "exposedMasterPassword": { - "message": "Huvudlösenordet har avslöjats" + "message": "Huvudlösenordet har exponerats" }, "exposedMasterPasswordDesc": { "message": "Lösenordet avslöjades vid ett dataintrång. Använd ett unikt lösenord för att skydda ditt konto. Är du säker på att du vill använda ett lösenord som avslöjats?" }, "weakAndExposedMasterPassword": { - "message": "Huvudlösenordet är svagt och har avslöjats" + "message": "Huvudlösenordet är svagt och har exponerats" }, "weakAndBreachedMasterPasswordDesc": { "message": "Lösenordet är svagt och avslöjades vid ett dataintrång. Använd ett starkt och unikt lösenord för att skydda ditt konto. Är det säkert att du vill använda detta lösenord?" @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Dina organisationspolicyer har aktiverat automatisk ifyllnad vid sidladdning." + }, + "howToAutofill": { + "message": "Hur du fyller i automatiskt" + }, + "autofillSelectInfoWithCommand": { + "message": "Välj ett objekt från denna sida eller använd genvägen: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Välj ett objekt från den här sidan eller ange en genväg i inställningarna." + }, + "gotIt": { + "message": "Förstått" + }, + "autofillSettings": { + "message": "Inställningar för automatisk ifyllnad" + }, + "autofillShortcut": { + "message": "Tangentbordsgenväg för automatisk ifyllnad" + }, + "autofillShortcutNotSet": { + "message": "Genvägen för automatisk ifyllnad är inte satt. Ändra detta i webbläsarens inställningar." + }, + "autofillShortcutText": { + "message": "Genvägen för automatisk ifyllnad är: $COMMAND$. Ändra detta i webbläsarens inställningar.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Standardgenväg för automatisk ifyllnad: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/te/messages.json b/apps/browser/src/_locales/te/messages.json index 9c228a74174..8f6d3d0da96 100644 --- a/apps/browser/src/_locales/te/messages.json +++ b/apps/browser/src/_locales/te/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Help & feedback" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Sync" }, @@ -430,7 +439,14 @@ "message": "Master password retype is required." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Master password confirmation does not match." @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json index 60d0041532f..c90949aab82 100644 --- a/apps/browser/src/_locales/th/messages.json +++ b/apps/browser/src/_locales/th/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Help & Feedback" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "ซิงค์" }, @@ -430,7 +439,14 @@ "message": "ต้องพิมพ์รหัสผ่านหลักอีกครั้ง" }, "masterPasswordMinlength": { - "message": "รหัสผ่านหลักต้องมีความยาวอย่างน้อย 8 ตัวอักษร" + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "การยืนยันรหัสผ่านหลักไม่ตรงกัน" @@ -448,7 +464,7 @@ "message": "โค้ดยืนยันไม่ถูกต้อง" }, "valueCopied": { - "message": " copied", + "message": "$VALUE$ copied", "description": "Value has been copied to the clipboard.", "placeholders": { "value": { @@ -798,7 +814,7 @@ "message": "Thank you for supporting bitwarden." }, "premiumPrice": { - "message": "All for just %price% /year!", + "message": "All for just $PRICE$ /year!", "placeholders": { "price": { "content": "$1", @@ -828,7 +844,7 @@ "message": "Enter the 6 digit verification code from your authenticator app." }, "enterVerificationCodeEmail": { - "message": "Enter the 6 digit verification code that was emailed to", + "message": "Enter the 6 digit verification code that was emailed to $EMAIL$.", "placeholders": { "email": { "content": "$1", @@ -1242,7 +1258,7 @@ "message": "ตรวจสอบว่ารหัสผ่านถูกเปิดเผยหรือไม่" }, "passwordExposed": { - "message": "This password has been exposed in data breaches. You should change it.", + "message": "This password has been exposed $VALUE$ time(s) in data breaches. You should change it.", "placeholders": { "value": { "content": "$1", @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Logging in to $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index 5abffc91709..9747e06ce8e 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Yardım ve geribildirim" }, + "helpCenter": { + "message": "Bitwarden yardım merkezi" + }, + "communityForums": { + "message": "Bitwarden forumlarını keşfedin" + }, + "contactSupport": { + "message": "Bitwarden destek ekibiyle iletişime geçin" + }, "sync": { "message": "Eşitle" }, @@ -430,7 +439,14 @@ "message": "Ana parolayı yeniden yazmalısınız." }, "masterPasswordMinlength": { - "message": "Ana parola en az 8 karakter uzunluğunda olmalıdır." + "message": "Ana parola en az $VALUE$ karakter uzunluğunda olmalıdır.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Ana parola onayı eşleşmiyor." @@ -960,7 +976,7 @@ "message": "Sayfa yüklendiğinde giriş formu tespit edilirse otomatik olarak formu doldur." }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "Ele geçirilmiş veya güvenilmeyen web siteleri sayfa yüklenirken otomatik doldurmayı suistimal edebilir." }, "learnMoreAboutAutofill": { "message": "Otomatik doldurma hakkında bilgi alın" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Askıya alınmış kuruluşlardaki kayıtlara erişilemez. Destek almak için kuruluş sahibinizle iletişime geçin." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "$DOMAIN$ sitesine giriş yapılıyor", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Kuruluş ilkeleriniz, sayfa yüklendiğinde otomatik doldurmayı etkinleştirdi." + }, + "howToAutofill": { + "message": "Otomatik doldurma nasıl yapılır?" + }, + "autofillSelectInfoWithCommand": { + "message": "Bu sayfadan bir kayıt seçin veya $COMMAND$ kısayolunu kullanın.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Bu sayfadan bir kayıt seçin veya ayarlardan bir kısayol ayarlayın." + }, + "gotIt": { + "message": "Anladım" + }, + "autofillSettings": { + "message": "Otomatik doldurma ayarları" + }, + "autofillShortcut": { + "message": "Otomatik doldurma klavye kısayolu" + }, + "autofillShortcutNotSet": { + "message": "Otomatik doldurma kısayolu ayarlanmamış. Bunu tarayıcının ayarlarından değiştirebilirsiniz." + }, + "autofillShortcutText": { + "message": "Otomatik doldurma kısayolu: $COMMAND$. Bunu tarayıcının ayarlarından değiştirebilirsiniz.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Varsayılan otomatik doldurma kısayolu: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json index b117ddc14b1..3e9b88a9404 100644 --- a/apps/browser/src/_locales/uk/messages.json +++ b/apps/browser/src/_locales/uk/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Допомога і зворотний зв'язок" }, + "helpCenter": { + "message": "Центр допомоги Bitwarden" + }, + "communityForums": { + "message": "Форуми спільноти Bitwarden" + }, + "contactSupport": { + "message": "Звернутися в службу підтримки Bitwarden" + }, "sync": { "message": "Синхронізація" }, @@ -430,7 +439,14 @@ "message": "Необхідно повторно ввести головний пароль." }, "masterPasswordMinlength": { - "message": "Довжина головного пароля має бути принаймні 8 символів." + "message": "Довжина головного пароля має бути принаймні $VALUE$ символів.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Підтвердження головного пароля не збігається." @@ -1130,7 +1146,7 @@ "message": "Mx" }, "firstName": { - "message": "Ім’я" + "message": "Ім'я" }, "middleName": { "message": "По батькові" @@ -1612,7 +1628,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "maxAccessCountReached": { - "message": "Досягнуто максимальну кількість доступів", + "message": "Досягнуто максимальної кількості доступів", "description": "This text will be displayed after a Send has been accessed the maximum amount of times." }, "expired": { @@ -1675,7 +1691,7 @@ "message": "Файл, який ви хочете відправити." }, "deletionDate": { - "message": "Дата видалення" + "message": "Термін дії" }, "deletionDateDesc": { "message": "Відправлення буде остаточно видалено у вказаний час.", @@ -1701,7 +1717,7 @@ } }, "custom": { - "message": "Спеціальний" + "message": "Власний" }, "maximumAccessCount": { "message": "Максимальна кількість доступів" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Записи у вимкнених організаціях недоступні. Зверніться до власника вашої організації для отримання допомоги." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Вхід до $DOMAIN$", "placeholders": { @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Політикою вашої організації було увімкнено автозаповнення на сторінці." + }, + "howToAutofill": { + "message": "Як працює автозаповнення" + }, + "autofillSelectInfoWithCommand": { + "message": "Виберіть елемент з цієї сторінки або використайте комбінацію клавіш: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Виберіть елемент з цієї сторінки або встановіть комбінацію клавіш у налаштуваннях." + }, + "gotIt": { + "message": "Зрозуміло" + }, + "autofillSettings": { + "message": "Налаштування автозаповнення" + }, + "autofillShortcut": { + "message": "Комбінації клавіш автозаповнення" + }, + "autofillShortcutNotSet": { + "message": "Комбінацію клавіш для автозаповнення не встановлено. Змініть це в налаштуваннях браузера." + }, + "autofillShortcutText": { + "message": "Комбінація клавіш автозаповнення: $COMMAND$. Змініть це в налаштуваннях браузера.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Типова комбінація клавіш автозаповнення: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json index b20c8ad63c7..6d89da61fed 100644 --- a/apps/browser/src/_locales/vi/messages.json +++ b/apps/browser/src/_locales/vi/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "Trợ giúp & phản hồi" }, + "helpCenter": { + "message": "Bitwarden Help center" + }, + "communityForums": { + "message": "Explore Bitwarden community forums" + }, + "contactSupport": { + "message": "Contact Bitwarden support" + }, "sync": { "message": "Đồng bộ" }, @@ -430,7 +439,14 @@ "message": "Yêu cầu nhập lại mật khẩu chính." }, "masterPasswordMinlength": { - "message": "Mật khẩu chính phải có ít nhất 8 kí tự." + "message": "Master password must be at least $VALUE$ characters long.", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "Xác nhận mật khẩu chính không khớp." @@ -963,7 +979,7 @@ "message": "Compromised or untrusted websites can exploit auto-fill on page load." }, "learnMoreAboutAutofill": { - "message": "Learn more about auto-fill" + "message": "Tìm hiểu thêm về tự động điền" }, "defaultAutoFillOnPageLoad": { "message": "Cài đặt tự động điền mặc định cho mục đăng nhập" @@ -1452,7 +1468,7 @@ "message": "Tổ chức của bạn yêu cầu mật khẩu chính của bạn phải đáp ứng các yêu cầu sau:" }, "policyInEffectMinComplexity": { - "message": "Minimum complexity score of $SCORE$", + "message": "Điểm phức tạp tối thiểu của $SCORE$", "placeholders": { "score": { "content": "$1", @@ -1494,7 +1510,7 @@ "message": "Bạn đồng ý với những điều sau khi nhấn chọn ô này:" }, "acceptPoliciesRequired": { - "message": "Terms of Service and Privacy Policy have not been acknowledged." + "message": "Điều khoản sử dụng và Chính sách quyền riêng tư chưa được đồng ý." }, "termsOfService": { "message": "Điều khoản sử dụng" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "Items in suspended Organizations cannot be accessed. Contact your Organization owner for assistance." }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "Đang đăng nhập vào $DOMAIN$", "placeholders": { @@ -2051,25 +2064,25 @@ "message": "Ghi nhớ email" }, "loginWithDevice": { - "message": "Log in with device" + "message": "Đăng nhập bằng thiết bị" }, "loginWithDeviceEnabledInfo": { "message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?" }, "fingerprintPhraseHeader": { - "message": "Fingerprint phrase" + "message": "Cụm từ dấu vân tay" }, "fingerprintMatchInfo": { "message": "Please make sure your vault is unlocked and the Fingerprint phrase matches on the other device." }, "resendNotification": { - "message": "Resend notification" + "message": "Gửi lại thông báo" }, "viewAllLoginOptions": { - "message": "View all log in options" + "message": "Xem tất cả tùy chọn đăng nhập" }, "notificationSentDevice": { - "message": "A notification has been sent to your device." + "message": "Một thông báo đã được gửi đến thiết bị của bạn." }, "logInInitiated": { "message": "Log in initiated" @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "How to auto-fill" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "Got it" + }, + "autofillSettings": { + "message": "Auto-fill settings" + }, + "autofillShortcut": { + "message": "Auto-fill keyboard shortcut" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "Default auto-fill shortcut: $COMMAND$.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index ff0c12b0f56..190e6a1b090 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "帮助与反馈" }, + "helpCenter": { + "message": "Bitwarden 帮助中心" + }, + "communityForums": { + "message": "探索 Bitwarden 社区论坛" + }, + "contactSupport": { + "message": "联系 Bitwarden 支持" + }, "sync": { "message": "同步" }, @@ -430,7 +439,14 @@ "message": "必须填写确认主密码。" }, "masterPasswordMinlength": { - "message": "主密码至少需要 8 个字符。" + "message": "主密码必须至少 $VALUE$ 个字符长度。", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "两次填写的主密码不一致。" @@ -491,7 +507,7 @@ "message": "您可以在 bitwarden.com 网页版密码库修改主密码。您现在要访问这个网站吗?" }, "twoStepLoginConfirmation": { - "message": "两步登录要求您从其他设备(例如安全钥匙、验证器应用、短信、电话或者电子邮件)来验证您的登录,这能使您的账户更加安全。两步登录需要在 bitwarden.com 网页版密码中设置。您现在要访问这个网站吗?" + "message": "两步登录要求您从其他设备(例如安全钥匙、验证器应用、短信、电话或者电子邮件)来验证您的登录,这能使您的账户更加安全。两步登录需要在 bitwarden.com 网页版密码库中设置。现在访问此网站吗?" }, "editedFolder": { "message": "文件夹已保存" @@ -662,10 +678,10 @@ "message": "导出的密码库数据包含未加密格式。您不应该通过不安全的渠道(例如电子邮件)来存储或发送导出的文件。用完后请立即将其删除。" }, "encExportKeyWarningDesc": { - "message": "此导出将使用您账户的加密密钥来加密您的数据。 如果您曾经轮换过账户的加密密钥,您应将其重新导出,否则您将无法解密导出的文件。" + "message": "此导出将使用您账户的加密密钥来加密您的数据。如果您曾经轮换过账户的加密密钥,您应将其重新导出,否则您将无法解密导出的文件。" }, "encExportAccountWarningDesc": { - "message": "账户加密密钥对每个 Bitwarden 用户账户都是唯一的,所以您不能将加密的导出导入到另一个账户。" + "message": "每个 Bitwarden 用户账户的账户加密密钥都是唯一的,因此您无法将加密的导出导入到另一个账户。" }, "exportMasterPassword": { "message": "输入主密码来导出你的密码库。" @@ -960,7 +976,7 @@ "message": "网页加载时如果检测到登录表单,则执行自动填充。" }, "experimentalFeature": { - "message": "Compromised or untrusted websites can exploit auto-fill on page load." + "message": "不完整或不信任的网站可以在页面加载时自动填充。" }, "learnMoreAboutAutofill": { "message": "了解更多关于自动填充的信息" @@ -1061,13 +1077,13 @@ "message": "品牌" }, "expirationMonth": { - "message": "到期月份" + "message": "过期月份" }, "expirationYear": { - "message": "到期年份" + "message": "过期年份" }, "expiration": { - "message": "到期" + "message": "过期日" }, "january": { "message": "一月" @@ -1214,7 +1230,7 @@ "message": "集合" }, "favorites": { - "message": "收藏" + "message": "收藏夹" }, "popOutNewWindow": { "message": "弹出到新窗口" @@ -1479,7 +1495,7 @@ "message": "至少包含一个数字" }, "policyInEffectSpecial": { - "message": "至少包含一个下列的特殊字符:$CHARS$", + "message": "至少包含一个以下特殊字符 $CHARS$", "placeholders": { "chars": { "content": "$1", @@ -1682,7 +1698,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "expirationDate": { - "message": "到期日期" + "message": "过期日期" }, "expirationDateDesc": { "message": "设置后,对此 Send 的访问将在指定的日期和时间后过期。", @@ -1784,19 +1800,19 @@ "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'To use a calendar style date picker click here **to pop out your window.**'" }, "expirationDateIsInvalid": { - "message": "所提供的到期日期无效。" + "message": "所提供的过期日期无效。" }, "deletionDateIsInvalid": { "message": "所提供的删除日期无效。" }, "expirationDateAndTimeRequired": { - "message": "需要到期日期和时间。" + "message": "需要过期日期和时间。" }, "deletionDateAndTimeRequired": { "message": "需要删除日期和时间。" }, "dateParsingError": { - "message": "保存您的删除和到期日期时出错。" + "message": "保存您的删除和过期日期时出错。" }, "hideEmail": { "message": "对收件人隐藏我的电子邮件地址。" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "无法访问已暂停组织中的项目。请联系您的组织所有者获取帮助。" }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "正在登录到 $DOMAIN$", "placeholders": { @@ -2051,57 +2064,105 @@ "message": "记住电子邮件地址" }, "loginWithDevice": { - "message": "使用设备登录" + "message": "设备登录" }, "loginWithDeviceEnabledInfo": { - "message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?" + "message": "必须在 Bitwarden 应用程序的设置中启用设备登录。需要其他选项吗?" }, "fingerprintPhraseHeader": { - "message": "Fingerprint phrase" + "message": "指纹短语" }, "fingerprintMatchInfo": { - "message": "Please make sure your vault is unlocked and the Fingerprint phrase matches on the other device." + "message": "请确保您的密码库已解锁,并且指纹短语与其他设备上的相匹配。" }, "resendNotification": { "message": "重新发送通知" }, "viewAllLoginOptions": { - "message": "View all log in options" + "message": "查看所有登录选项" }, "notificationSentDevice": { - "message": "A notification has been sent to your device." + "message": "通知已发送到您的设备。" }, "logInInitiated": { - "message": "Log in initiated" + "message": "登录已发起" }, "exposedMasterPassword": { - "message": "暴露的主密码" + "message": "已暴露的主密码" }, "exposedMasterPasswordDesc": { - "message": "数据泄露中发现的密码。使用独特的密码来保护您的帐户。您确定要使用已暴露的密码吗?" + "message": "密码在数据泄露中被发现。请使用一个唯一的密码以保护您的账户。确定要使用已暴露的密码吗?" }, "weakAndExposedMasterPassword": { - "message": "弱而暴露的主密码" + "message": "主密码弱且曾经暴露" }, "weakAndBreachedMasterPasswordDesc": { - "message": "已经识别和发现在数据泄露中的弱密码。使用强大且独特的密码来保护您的帐户。您确定要使用此密码吗?" + "message": "识别到弱密码且其出现在数据泄露中。请使用一个强且唯一的密码以保护你的账户。确定要使用这个密码吗?" }, "checkForBreaches": { "message": "检查已知的数据泄露是否包含此密码。" }, "important": { - "message": "简体中文:重要" + "message": "重要:" }, "masterPasswordHint": { - "message": "检查此密码的已知数据泄露" + "message": "主密码忘记后,将无法恢复!" }, "characterMinimum": { - "message": "重要", + "message": "至少 $LENGTH$ 个字符", "placeholders": { "length": { "content": "$1", "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "您的组织策略已开启在页面加载时的自动填充。" + }, + "howToAutofill": { + "message": "如何自动填充" + }, + "autofillSelectInfoWithCommand": { + "message": "从此页面选择一个项目,或使用快捷方式:$COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "从此页面选择一个项目,或者在设置中设置一个快捷方式。" + }, + "gotIt": { + "message": "明白了" + }, + "autofillSettings": { + "message": "自动填充设置" + }, + "autofillShortcut": { + "message": "自动填充键盘快捷键" + }, + "autofillShortcutNotSet": { + "message": "未设置自动填充快捷方式。请在浏览器设置中更改此设置。" + }, + "autofillShortcutText": { + "message": "自动填充快捷方式为: $COMMAND$。在浏览器设置中更改此项。", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "默认自动填充快捷方式:$COMMAND$。", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json index 362a1807583..bc0e50147e8 100644 --- a/apps/browser/src/_locales/zh_TW/messages.json +++ b/apps/browser/src/_locales/zh_TW/messages.json @@ -195,6 +195,15 @@ "helpFeedback": { "message": "協助與意見反應" }, + "helpCenter": { + "message": "Bitwarden 說明中心" + }, + "communityForums": { + "message": "瀏覽 Bitwarden 社群論壇" + }, + "contactSupport": { + "message": "連絡 Bitwarden 客戶支援" + }, "sync": { "message": "同步" }, @@ -430,7 +439,14 @@ "message": "必須再次輸入主密碼。" }, "masterPasswordMinlength": { - "message": "主密碼需要至少 8 個字元。" + "message": "主密碼需要至少 $VALUE$ 個字元。", + "description": "The Master Password must be at least a specific number of characters long.", + "placeholders": { + "value": { + "content": "$1", + "example": "8" + } + } }, "masterPassDoesntMatch": { "message": "兩次填入的主密碼不相符。" @@ -963,7 +979,7 @@ "message": "Compromised or untrusted websites can exploit auto-fill on page load." }, "learnMoreAboutAutofill": { - "message": "Learn more about auto-fill" + "message": "進一步瞭解「自動填入」功能" }, "defaultAutoFillOnPageLoad": { "message": "登入項目的預設自動填入設定" @@ -1987,9 +2003,6 @@ "disabledOrganizationFilterError": { "message": "無法存取已停用組織中的項目。請聯絡您組織的擁有者以獲取協助。" }, - "cardBrandMir": { - "message": "Mir" - }, "loggingInTo": { "message": "正在登入至 $DOMAIN$", "placeholders": { @@ -2051,28 +2064,28 @@ "message": "記住電子郵件地址" }, "loginWithDevice": { - "message": "Log in with device" + "message": "使用裝置登入" }, "loginWithDeviceEnabledInfo": { "message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?" }, "fingerprintPhraseHeader": { - "message": "Fingerprint phrase" + "message": "指紋短語" }, "fingerprintMatchInfo": { "message": "Please make sure your vault is unlocked and the Fingerprint phrase matches on the other device." }, "resendNotification": { - "message": "Resend notification" + "message": "重新傳送通知" }, "viewAllLoginOptions": { - "message": "View all log in options" + "message": "檢視所有登入選項" }, "notificationSentDevice": { - "message": "A notification has been sent to your device." + "message": "已傳送通知至您的裝置。" }, "logInInitiated": { - "message": "Log in initiated" + "message": "登入已起始" }, "exposedMasterPassword": { "message": "已暴露的主密碼" @@ -2103,5 +2116,53 @@ "example": "14" } } + }, + "autofillPageLoadPolicyActivated": { + "message": "Your organization policies have turned on auto-fill on page load." + }, + "howToAutofill": { + "message": "如何自動填入" + }, + "autofillSelectInfoWithCommand": { + "message": "Select an item from this page or use the shortcut: $COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillSelectInfoWithoutCommand": { + "message": "Select an item from this page or set a shortcut in settings." + }, + "gotIt": { + "message": "我知道了" + }, + "autofillSettings": { + "message": "自動填入設定" + }, + "autofillShortcut": { + "message": "自動填入鍵盤快速鍵" + }, + "autofillShortcutNotSet": { + "message": "The auto-fill shortcut is not set. Change this in the browser's settings." + }, + "autofillShortcutText": { + "message": "The auto-fill shortcut is: $COMMAND$. Change this in the browser's settings.", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } + }, + "autofillShortcutTextSafari": { + "message": "預設自動填入快速鍵:$COMMAND$", + "placeholders": { + "command": { + "content": "$1", + "example": "CTRL+Shift+L" + } + } } } diff --git a/apps/browser/src/background/service_factories/collection-service.factory.ts b/apps/browser/src/admin-console/background/service-factories/collection-service.factory.ts similarity index 57% rename from apps/browser/src/background/service_factories/collection-service.factory.ts rename to apps/browser/src/admin-console/background/service-factories/collection-service.factory.ts index d85e6dd8dcd..0035eee8c42 100644 --- a/apps/browser/src/background/service_factories/collection-service.factory.ts +++ b/apps/browser/src/admin-console/background/service-factories/collection-service.factory.ts @@ -1,13 +1,23 @@ -import { CollectionService as AbstractCollectionService } from "@bitwarden/common/abstractions/collection.service"; -import { CollectionService } from "@bitwarden/common/services/collection.service"; +import { CollectionService as AbstractCollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; +import { CollectionService } from "@bitwarden/common/admin-console/services/collection.service"; -import { cryptoServiceFactory, CryptoServiceInitOptions } from "./crypto-service.factory"; -import { CachedServices, factory, FactoryOptions } from "./factory-options"; -import { i18nServiceFactory, I18nServiceInitOptions } from "./i18n-service.factory"; +import { + cryptoServiceFactory, + CryptoServiceInitOptions, +} from "../../../background/service_factories/crypto-service.factory"; +import { + CachedServices, + factory, + FactoryOptions, +} from "../../../background/service_factories/factory-options"; +import { + i18nServiceFactory, + I18nServiceInitOptions, +} from "../../../background/service_factories/i18n-service.factory"; import { stateServiceFactory as stateServiceFactory, StateServiceInitOptions, -} from "./state-service.factory"; +} from "../../../background/service_factories/state-service.factory"; type CollectionServiceFactoryOptions = FactoryOptions; diff --git a/apps/browser/src/background/service_factories/organization-service.factory.ts b/apps/browser/src/admin-console/background/service-factories/organization-service.factory.ts similarity index 66% rename from apps/browser/src/background/service_factories/organization-service.factory.ts rename to apps/browser/src/admin-console/background/service-factories/organization-service.factory.ts index 4f2eaee8058..454b1ce9cd2 100644 --- a/apps/browser/src/background/service_factories/organization-service.factory.ts +++ b/apps/browser/src/admin-console/background/service-factories/organization-service.factory.ts @@ -1,10 +1,16 @@ -import { OrganizationService as AbstractOrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; +import { OrganizationService as AbstractOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { + FactoryOptions, + CachedServices, + factory, +} from "../../../background/service_factories/factory-options"; +import { + stateServiceFactory, + StateServiceInitOptions, +} from "../../../background/service_factories/state-service.factory"; import { BrowserOrganizationService } from "../../services/browser-organization.service"; -import { FactoryOptions, CachedServices, factory } from "./factory-options"; -import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory"; - type OrganizationServiceFactoryOptions = FactoryOptions; export type OrganizationServiceInitOptions = OrganizationServiceFactoryOptions & diff --git a/apps/browser/src/background/service_factories/policy-service.factory.ts b/apps/browser/src/admin-console/background/service-factories/policy-service.factory.ts similarity index 77% rename from apps/browser/src/background/service_factories/policy-service.factory.ts rename to apps/browser/src/admin-console/background/service-factories/policy-service.factory.ts index d20bca3c62e..4bb19639c88 100644 --- a/apps/browser/src/background/service_factories/policy-service.factory.ts +++ b/apps/browser/src/admin-console/background/service-factories/policy-service.factory.ts @@ -1,16 +1,20 @@ -import { PolicyService as AbstractPolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; +import { PolicyService as AbstractPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { + CachedServices, + factory, + FactoryOptions, +} from "../../../background/service_factories/factory-options"; +import { + stateServiceFactory as stateServiceFactory, + StateServiceInitOptions, +} from "../../../background/service_factories/state-service.factory"; import { BrowserPolicyService } from "../../services/browser-policy.service"; -import { CachedServices, factory, FactoryOptions } from "./factory-options"; import { organizationServiceFactory, OrganizationServiceInitOptions, } from "./organization-service.factory"; -import { - stateServiceFactory as stateServiceFactory, - StateServiceInitOptions, -} from "./state-service.factory"; type PolicyServiceFactoryOptions = FactoryOptions; diff --git a/apps/browser/src/admin-console/services/browser-organization.service.ts b/apps/browser/src/admin-console/services/browser-organization.service.ts new file mode 100644 index 00000000000..3b0ae245a64 --- /dev/null +++ b/apps/browser/src/admin-console/services/browser-organization.service.ts @@ -0,0 +1,12 @@ +import { BehaviorSubject } from "rxjs"; + +import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service"; + +import { browserSession, sessionSync } from "../../decorators/session-sync-observable"; + +@browserSession +export class BrowserOrganizationService extends OrganizationService { + @sessionSync({ initializer: Organization.fromJSON, initializeAs: "array" }) + protected _organizations: BehaviorSubject; +} diff --git a/apps/browser/src/admin-console/services/browser-policy.service.ts b/apps/browser/src/admin-console/services/browser-policy.service.ts new file mode 100644 index 00000000000..89aa35a51e1 --- /dev/null +++ b/apps/browser/src/admin-console/services/browser-policy.service.ts @@ -0,0 +1,44 @@ +import { BehaviorSubject, filter, map, Observable, switchMap, tap } from "rxjs"; +import { Jsonify } from "type-fest"; + +import { StateService } from "@bitwarden/common/abstractions/state.service"; +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { PolicyType } from "@bitwarden/common/admin-console/enums/policy-type"; +import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; +import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service"; + +import { browserSession, sessionSync } from "../../decorators/session-sync-observable"; + +@browserSession +export class BrowserPolicyService extends PolicyService { + @sessionSync({ + initializer: (obj: Jsonify) => Object.assign(new Policy(), obj), + initializeAs: "array", + }) + protected _policies: BehaviorSubject; + + constructor(stateService: StateService, organizationService: OrganizationService) { + super(stateService, organizationService); + this._policies.pipe(this.handleActivateAutofillPolicy.bind(this)).subscribe(); + } + + /** + * If the ActivateAutofill policy is enabled, save a flag indicating if we need to + * enable Autofill on page load. + */ + private handleActivateAutofillPolicy(policies$: Observable) { + return policies$.pipe( + map((policies) => policies.find((p) => p.type == PolicyType.ActivateAutofill && p.enabled)), + filter((p) => p != null), + switchMap(async (_) => [ + await this.stateService.getActivateAutoFillOnPageLoadFromPolicy(), + await this.stateService.getEnableAutoFillOnPageLoad(), + ]), + tap(([activated, autofillEnabled]) => { + if (activated === undefined) { + this.stateService.setActivateAutoFillOnPageLoadFromPolicy(!autofillEnabled); + } + }) + ); + } +} diff --git a/apps/browser/src/types/group-policy-environment.ts b/apps/browser/src/admin-console/types/group-policy-environment.ts similarity index 100% rename from apps/browser/src/types/group-policy-environment.ts rename to apps/browser/src/admin-console/types/group-policy-environment.ts diff --git a/apps/browser/src/alarms/alarm-state.ts b/apps/browser/src/alarms/alarm-state.ts index 71f7b518197..695f8642809 100644 --- a/apps/browser/src/alarms/alarm-state.ts +++ b/apps/browser/src/alarms/alarm-state.ts @@ -2,7 +2,7 @@ import { clearClipboardAlarmName } from "../autofill/clipboard"; import { BrowserApi } from "../browser/browserApi"; export const alarmKeys = [clearClipboardAlarmName] as const; -export type AlarmKeys = typeof alarmKeys[number]; +export type AlarmKeys = (typeof alarmKeys)[number]; type AlarmState = { [T in AlarmKeys]: number | undefined }; diff --git a/apps/browser/src/auth/background/service-factories/key-connector-service.factory.ts b/apps/browser/src/auth/background/service-factories/key-connector-service.factory.ts index c9e154da1b2..0689398f9c4 100644 --- a/apps/browser/src/auth/background/service-factories/key-connector-service.factory.ts +++ b/apps/browser/src/auth/background/service-factories/key-connector-service.factory.ts @@ -1,6 +1,10 @@ import { KeyConnectorService as AbstractKeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.service"; +import { + OrganizationServiceInitOptions, + organizationServiceFactory, +} from "../../../admin-console/background/service-factories/organization-service.factory"; import { apiServiceFactory, ApiServiceInitOptions, @@ -22,10 +26,6 @@ import { logServiceFactory, LogServiceInitOptions, } from "../../../background/service_factories/log-service.factory"; -import { - OrganizationServiceInitOptions, - organizationServiceFactory, -} from "../../../background/service_factories/organization-service.factory"; import { stateServiceFactory, StateServiceInitOptions, diff --git a/apps/browser/src/auth/popup/home.component.html b/apps/browser/src/auth/popup/home.component.html index 24feb9c83e5..fb51458c136 100644 --- a/apps/browser/src/auth/popup/home.component.html +++ b/apps/browser/src/auth/popup/home.component.html @@ -10,7 +10,7 @@
diff --git a/apps/browser/src/auth/popup/login-with-device.component.html b/apps/browser/src/auth/popup/login-with-device.component.html index cb2a248170c..d794b7d212b 100644 --- a/apps/browser/src/auth/popup/login-with-device.component.html +++ b/apps/browser/src/auth/popup/login-with-device.component.html @@ -19,7 +19,7 @@
{{ "fingerprintPhraseHeader" | i18n }}

- {{ passwordlessRequest?.fingerprintPhrase }} + {{ fingerprintPhrase }}

diff --git a/apps/browser/src/auth/popup/login-with-device.component.ts b/apps/browser/src/auth/popup/login-with-device.component.ts index 9b89c123e14..dae6fd2d4da 100644 --- a/apps/browser/src/auth/popup/login-with-device.component.ts +++ b/apps/browser/src/auth/popup/login-with-device.component.ts @@ -10,12 +10,12 @@ import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunc import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; -import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { ValidationService } from "@bitwarden/common/abstractions/validation.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { LoginService } from "@bitwarden/common/auth/abstractions/login.service"; +import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; @Component({ @@ -31,7 +31,7 @@ export class LoginWithDeviceComponent cryptoService: CryptoService, cryptoFunctionService: CryptoFunctionService, appIdService: AppIdService, - passwordGenerationService: PasswordGenerationService, + passwordGenerationService: PasswordGenerationServiceAbstraction, apiService: ApiService, authService: AuthService, logService: LogService, diff --git a/apps/browser/src/auth/popup/login.component.ts b/apps/browser/src/auth/popup/login.component.ts index 539ef43a4aa..cc48a75e4e9 100644 --- a/apps/browser/src/auth/popup/login.component.ts +++ b/apps/browser/src/auth/popup/login.component.ts @@ -10,12 +10,12 @@ import { EnvironmentService } from "@bitwarden/common/abstractions/environment.s import { FormValidationErrorsService } from "@bitwarden/common/abstractions/formValidationErrors.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; -import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { LoginService } from "@bitwarden/common/auth/abstractions/login.service"; import { Utils } from "@bitwarden/common/misc/utils"; +import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { flagEnabled } from "../../flags"; @@ -35,7 +35,7 @@ export class LoginComponent extends BaseLoginComponent { protected i18nService: I18nService, protected stateService: StateService, protected environmentService: EnvironmentService, - protected passwordGenerationService: PasswordGenerationService, + protected passwordGenerationService: PasswordGenerationServiceAbstraction, protected cryptoFunctionService: CryptoFunctionService, syncService: SyncService, logService: LogService, @@ -118,7 +118,9 @@ export class LoginComponent extends BaseLoginComponent { "&state=" + state + "&codeChallenge=" + - codeChallenge + codeChallenge + + "&email=" + + encodeURIComponent(this.formGroup.controls.email.value) ); } } diff --git a/apps/browser/src/auth/popup/register.component.ts b/apps/browser/src/auth/popup/register.component.ts index 85faff832d6..11b01dd38f4 100644 --- a/apps/browser/src/auth/popup/register.component.ts +++ b/apps/browser/src/auth/popup/register.component.ts @@ -10,10 +10,10 @@ import { EnvironmentService } from "@bitwarden/common/abstractions/environment.s import { FormValidationErrorsService } from "@bitwarden/common/abstractions/formValidationErrors.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; -import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; @Component({ selector: "app-register", @@ -33,7 +33,7 @@ export class RegisterComponent extends BaseRegisterComponent { apiService: ApiService, stateService: StateService, platformUtilsService: PlatformUtilsService, - passwordGenerationService: PasswordGenerationService, + passwordGenerationService: PasswordGenerationServiceAbstraction, environmentService: EnvironmentService, logService: LogService, auditService: AuditService diff --git a/apps/browser/src/auth/popup/remove-password.component.html b/apps/browser/src/auth/popup/remove-password.component.html index 793bcff3e09..8024023976f 100644 --- a/apps/browser/src/auth/popup/remove-password.component.html +++ b/apps/browser/src/auth/popup/remove-password.component.html @@ -10,7 +10,7 @@
-

{{ "convertOrganizationEncryptionDesc" | i18n: organization.name }}

+

{{ "convertOrganizationEncryptionDesc" | i18n : organization.name }}

@@ -87,7 +87,7 @@
- +
diff --git a/apps/browser/src/auth/popup/update-temp-password.component.ts b/apps/browser/src/auth/popup/update-temp-password.component.ts index 968400e7f64..c20d5fb422b 100644 --- a/apps/browser/src/auth/popup/update-temp-password.component.ts +++ b/apps/browser/src/auth/popup/update-temp-password.component.ts @@ -6,10 +6,10 @@ import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; -import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; -import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; import { StateService } from "@bitwarden/common/abstractions/state.service"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; @Component({ @@ -20,7 +20,7 @@ export class UpdateTempPasswordComponent extends BaseUpdateTempPasswordComponent constructor( i18nService: I18nService, platformUtilsService: PlatformUtilsService, - passwordGenerationService: PasswordGenerationService, + passwordGenerationService: PasswordGenerationServiceAbstraction, policyService: PolicyService, cryptoService: CryptoService, stateService: StateService, diff --git a/apps/browser/src/autofill/background/notification.background.ts b/apps/browser/src/autofill/background/notification.background.ts index ca0149bd729..71284dbbe51 100644 --- a/apps/browser/src/autofill/background/notification.background.ts +++ b/apps/browser/src/autofill/background/notification.background.ts @@ -1,17 +1,15 @@ import { firstValueFrom } from "rxjs"; -import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { PolicyType } from "@bitwarden/common/admin-console/enums/policy-type"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; -import { PolicyType } from "@bitwarden/common/enums/policyType"; import { ThemeType } from "@bitwarden/common/enums/themeType"; import { Utils } from "@bitwarden/common/misc/utils"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; 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 AddChangePasswordQueueMessage from "../../background/models/addChangePasswordQueueMessage"; import AddLoginQueueMessage from "../../background/models/addLoginQueueMessage"; @@ -95,7 +93,7 @@ export default class NotificationBackground { await BrowserApi.tabSendMessageData(sender.tab, "promptForLogin"); return; } - await this.saveOrUpdateCredentials(sender.tab, msg.folder); + await this.saveOrUpdateCredentials(sender.tab, msg.edit, msg.folder); break; case "bgNeverSave": await this.saveNever(sender.tab); @@ -168,6 +166,7 @@ export default class NotificationBackground { typeData: { isVaultLocked: this.notificationQueue[i].wasVaultLocked, theme: await this.getCurrentTheme(), + removeIndividualVault: await this.removeIndividualVault(), }, }); } else if (this.notificationQueue[i].type === NotificationQueueMessageType.ChangePassword) { @@ -225,10 +224,6 @@ export default class NotificationBackground { return; } - if (!(await this.allowPersonalOwnership())) { - return; - } - this.pushAddLoginToQueue(loginDomain, loginInfo, tab, true); return; } @@ -242,10 +237,6 @@ export default class NotificationBackground { return; } - if (!(await this.allowPersonalOwnership())) { - return; - } - this.pushAddLoginToQueue(loginDomain, loginInfo, tab); } else if ( usernameMatches.length === 1 && @@ -332,14 +323,10 @@ export default class NotificationBackground { await this.checkNotificationQueue(tab); } - private async saveOrUpdateCredentials(tab: chrome.tabs.Tab, folderId?: string) { + private async saveOrUpdateCredentials(tab: chrome.tabs.Tab, edit: boolean, folderId?: string) { for (let i = this.notificationQueue.length - 1; i >= 0; i--) { const queueMessage = this.notificationQueue[i]; - if ( - queueMessage.tabId !== tab.id || - (queueMessage.type !== NotificationQueueMessageType.AddLogin && - queueMessage.type !== NotificationQueueMessageType.ChangePassword) - ) { + if (queueMessage.tabId !== tab.id || !(queueMessage.type in NotificationQueueMessageType)) { continue; } @@ -352,63 +339,79 @@ export default class NotificationBackground { BrowserApi.tabSendMessageData(tab, "closeNotificationBar"); if (queueMessage.type === NotificationQueueMessageType.ChangePassword) { - const changePasswordMessage = queueMessage as AddChangePasswordQueueMessage; - const cipher = await this.getDecryptedCipherById(changePasswordMessage.cipherId); - if (cipher == null) { - return; - } - await this.updateCipher(cipher, changePasswordMessage.newPassword); + const cipherView = await this.getDecryptedCipherById(queueMessage.cipherId); + await this.updatePassword(cipherView, queueMessage.newPassword, edit, tab); return; } if (queueMessage.type === NotificationQueueMessageType.AddLogin) { - if (!queueMessage.wasVaultLocked) { - await this.createNewCipher(queueMessage as AddLoginQueueMessage, folderId); - BrowserApi.tabSendMessageData(tab, "addedCipher"); - return; - } - // If the vault was locked, check if a cipher needs updating instead of creating a new one - const addLoginMessage = queueMessage as AddLoginQueueMessage; - const ciphers = await this.cipherService.getAllDecryptedForUrl(addLoginMessage.uri); - const usernameMatches = ciphers.filter( - (c) => - c.login.username != null && c.login.username.toLowerCase() === addLoginMessage.username - ); + if (queueMessage.wasVaultLocked) { + const allCiphers = await this.cipherService.getAllDecryptedForUrl(queueMessage.uri); + const existingCipher = allCiphers.find( + (c) => + c.login.username != null && c.login.username.toLowerCase() === queueMessage.username + ); - if (usernameMatches.length >= 1) { - await this.updateCipher(usernameMatches[0], addLoginMessage.password); + if (existingCipher != null) { + await this.updatePassword(existingCipher, queueMessage.password, edit, tab); + return; + } + } + + folderId = (await this.folderExists(folderId)) ? folderId : null; + const newCipher = AddLoginQueueMessage.toCipherView(queueMessage, folderId); + + if (edit) { + await this.editItem(newCipher, tab); return; } - await this.createNewCipher(addLoginMessage, folderId); + const cipher = await this.cipherService.encrypt(newCipher); + await this.cipherService.createWithServer(cipher); BrowserApi.tabSendMessageData(tab, "addedCipher"); } } } - private async createNewCipher(queueMessage: AddLoginQueueMessage, folderId: string) { - const loginModel = new LoginView(); - const loginUri = new LoginUriView(); - loginUri.uri = queueMessage.uri; - loginModel.uris = [loginUri]; - loginModel.username = queueMessage.username; - loginModel.password = queueMessage.password; - const model = new CipherView(); - model.name = Utils.getHostname(queueMessage.uri) || queueMessage.domain; - model.name = model.name.replace(/^www\./, ""); - model.type = CipherType.Login; - model.login = loginModel; + private async updatePassword( + cipherView: CipherView, + newPassword: string, + edit: boolean, + tab: chrome.tabs.Tab + ) { + cipherView.login.password = newPassword; - if (!Utils.isNullOrWhitespace(folderId)) { - const folders = await firstValueFrom(this.folderService.folderViews$); - if (folders.some((x) => x.id === folderId)) { - model.folderId = folderId; - } + if (edit) { + await this.editItem(cipherView, tab); + BrowserApi.tabSendMessage(tab, "editedCipher"); + return; } - const cipher = await this.cipherService.encrypt(model); - await this.cipherService.createWithServer(cipher); + const cipher = await this.cipherService.encrypt(cipherView); + await this.cipherService.updateWithServer(cipher); + // We've only updated the password, no need to broadcast editedCipher message + return; + } + + private async editItem(cipherView: CipherView, senderTab: chrome.tabs.Tab) { + await this.stateService.setAddEditCipherInfo({ + cipher: cipherView, + collectionIds: cipherView.collectionIds, + }); + + await BrowserApi.tabSendMessageData(senderTab, "openAddEditCipher", { + cipherId: cipherView.id, + }); + } + + private async folderExists(folderId: string) { + if (Utils.isNullOrWhitespace(folderId) || folderId === "null") { + return false; + } + + const folders = await firstValueFrom(this.folderService.folderViews$); + return folders.some((x) => x.id === folderId); } private async getDecryptedCipherById(cipherId: string) { @@ -419,14 +422,6 @@ export default class NotificationBackground { return null; } - private async updateCipher(cipher: CipherView, newPassword: string) { - if (cipher != null && cipher.type === CipherType.Login) { - cipher.login.password = newPassword; - const newCipher = await this.cipherService.encrypt(cipher); - await this.cipherService.updateWithServer(newCipher); - } - } - private async saveNever(tab: chrome.tabs.Tab) { for (let i = this.notificationQueue.length - 1; i >= 0; i--) { const queueMessage = this.notificationQueue[i]; @@ -459,9 +454,9 @@ export default class NotificationBackground { await BrowserApi.tabSendMessageData(tab, responseCommand, responseData); } - private async allowPersonalOwnership(): Promise { - return !(await firstValueFrom( + private async removeIndividualVault(): Promise { + return await firstValueFrom( this.policyService.policyAppliesToActiveUser$(PolicyType.PersonalOwnership) - )); + ); } } diff --git a/apps/browser/src/autofill/background/service_factories/autofill-service.factory.ts b/apps/browser/src/autofill/background/service_factories/autofill-service.factory.ts index 87836198d7b..a23b5e8dbaf 100644 --- a/apps/browser/src/autofill/background/service_factories/autofill-service.factory.ts +++ b/apps/browser/src/autofill/background/service_factories/autofill-service.factory.ts @@ -15,6 +15,10 @@ import { logServiceFactory, LogServiceInitOptions, } from "../../../background/service_factories/log-service.factory"; +import { + settingsServiceFactory, + SettingsServiceInitOptions, +} from "../../../background/service_factories/settings-service.factory"; import { stateServiceFactory, StateServiceInitOptions, @@ -33,7 +37,8 @@ export type AutoFillServiceInitOptions = AutoFillServiceOptions & StateServiceInitOptions & TotpServiceInitOptions & EventCollectionServiceInitOptions & - LogServiceInitOptions; + LogServiceInitOptions & + SettingsServiceInitOptions; export function autofillServiceFactory( cache: { autofillService?: AbstractAutoFillService } & CachedServices, @@ -49,7 +54,8 @@ export function autofillServiceFactory( await stateServiceFactory(cache, opts), await totpServiceFactory(cache, opts), await eventCollectionServiceFactory(cache, opts), - await logServiceFactory(cache, opts) + await logServiceFactory(cache, opts), + await settingsServiceFactory(cache, opts) ) ); } diff --git a/apps/browser/src/autofill/browser/context-menu-clicked-handler.spec.ts b/apps/browser/src/autofill/browser/context-menu-clicked-handler.spec.ts index 1ac8b5d9dcd..a9dbcbaacc5 100644 --- a/apps/browser/src/autofill/browser/context-menu-clicked-handler.spec.ts +++ b/apps/browser/src/autofill/browser/context-menu-clicked-handler.spec.ts @@ -9,13 +9,12 @@ import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { Cipher } from "@bitwarden/common/vault/models/domain/cipher"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; -import { AutofillTabCommand } from "../commands/autofill-tab-command"; - import { CopyToClipboardAction, ContextMenuClickedHandler, CopyToClipboardOptions, GeneratePasswordToClipboardAction, + AutofillAction, } from "./context-menu-clicked-handler"; import { AUTOFILL_ID, @@ -59,9 +58,9 @@ describe("ContextMenuClickedHandler", () => { let copyToClipboard: CopyToClipboardAction; let generatePasswordToClipboard: GeneratePasswordToClipboardAction; + let autofill: AutofillAction; let authService: MockProxy; let cipherService: MockProxy; - let autofillTabCommand: MockProxy; let totpService: MockProxy; let eventCollectionService: MockProxy; @@ -70,18 +69,18 @@ describe("ContextMenuClickedHandler", () => { beforeEach(() => { copyToClipboard = jest.fn(); generatePasswordToClipboard = jest.fn, [tab: chrome.tabs.Tab]>(); + autofill = jest.fn, [tab: chrome.tabs.Tab, cipher: CipherView]>(); authService = mock(); cipherService = mock(); - autofillTabCommand = mock(); totpService = mock(); eventCollectionService = mock(); sut = new ContextMenuClickedHandler( copyToClipboard, generatePasswordToClipboard, + autofill, authService, cipherService, - autofillTabCommand, totpService, eventCollectionService ); @@ -106,9 +105,9 @@ describe("ContextMenuClickedHandler", () => { await sut.run(createData("T_1", AUTOFILL_ID), { id: 5 } as any); - expect(autofillTabCommand.doAutofillTabWithCipherCommand).toBeCalledTimes(1); + expect(autofill).toBeCalledTimes(1); - expect(autofillTabCommand.doAutofillTabWithCipherCommand).toBeCalledWith({ id: 5 }, cipher); + expect(autofill).toBeCalledWith({ id: 5 }, cipher); }); it("copies username to clipboard", async () => { diff --git a/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts b/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts index 840ae7a7743..9583c077c89 100644 --- a/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts +++ b/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts @@ -43,6 +43,7 @@ import { export type CopyToClipboardOptions = { text: string; tab: chrome.tabs.Tab }; export type CopyToClipboardAction = (options: CopyToClipboardOptions) => void; +export type AutofillAction = (tab: chrome.tabs.Tab, cipher: CipherView) => Promise; export type GeneratePasswordToClipboardAction = (tab: chrome.tabs.Tab) => Promise; @@ -53,9 +54,9 @@ export class ContextMenuClickedHandler { constructor( private copyToClipboard: CopyToClipboardAction, private generatePasswordToClipboard: GeneratePasswordToClipboardAction, + private autofillAction: AutofillAction, private authService: AuthService, private cipherService: CipherService, - private autofillTabCommand: AutofillTabCommand, private totpService: TotpService, private eventCollectionService: EventCollectionService ) {} @@ -104,12 +105,16 @@ export class ContextMenuClickedHandler { await stateServiceFactory(cachedServices, serviceOptions) ); + const autofillCommand = new AutofillTabCommand( + await autofillServiceFactory(cachedServices, serviceOptions) + ); + return new ContextMenuClickedHandler( (options) => copyToClipboard(options.tab, options.text), (tab) => generatePasswordToClipboardCommand.generatePasswordToClipboard(tab), + (tab, cipher) => autofillCommand.doAutofillTabWithCipherCommand(tab, cipher), await authServiceFactory(cachedServices, serviceOptions), await cipherServiceFactory(cachedServices, serviceOptions), - new AutofillTabCommand(await autofillServiceFactory(cachedServices, serviceOptions)), await totpServiceFactory(cachedServices, serviceOptions), await eventCollectionServiceFactory(cachedServices, serviceOptions) ); @@ -205,7 +210,7 @@ export class ContextMenuClickedHandler { if (tab == null) { return; } - await this.autofillTabCommand.doAutofillTabWithCipherCommand(tab, cipher); + await this.autofillAction(tab, cipher); break; case COPY_USERNAME_ID: this.copyToClipboard({ text: cipher.login.username, tab: tab }); diff --git a/apps/browser/src/autofill/clipboard/generate-password-to-clipboard-command.spec.ts b/apps/browser/src/autofill/clipboard/generate-password-to-clipboard-command.spec.ts index 4c1460c86ef..38c62231ac8 100644 --- a/apps/browser/src/autofill/clipboard/generate-password-to-clipboard-command.spec.ts +++ b/apps/browser/src/autofill/clipboard/generate-password-to-clipboard-command.spec.ts @@ -1,6 +1,6 @@ import { mock, MockProxy } from "jest-mock-extended"; -import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; +import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { setAlarmTime } from "../../alarms/alarm-state"; import { BrowserApi } from "../../browser/browserApi"; @@ -18,13 +18,13 @@ jest.mock("../../alarms/alarm-state", () => { const setAlarmTimeMock = setAlarmTime as jest.Mock; describe("GeneratePasswordToClipboardCommand", () => { - let passwordGenerationService: MockProxy; + let passwordGenerationService: MockProxy; let stateService: MockProxy; let sut: GeneratePasswordToClipboardCommand; beforeEach(() => { - passwordGenerationService = mock(); + passwordGenerationService = mock(); stateService = mock(); passwordGenerationService.getOptions.mockResolvedValue([{ length: 8 }, {} as any]); diff --git a/apps/browser/src/autofill/clipboard/generate-password-to-clipboard-command.ts b/apps/browser/src/autofill/clipboard/generate-password-to-clipboard-command.ts index eec0b31834d..7dd37a64ad4 100644 --- a/apps/browser/src/autofill/clipboard/generate-password-to-clipboard-command.ts +++ b/apps/browser/src/autofill/clipboard/generate-password-to-clipboard-command.ts @@ -1,4 +1,4 @@ -import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; +import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { setAlarmTime } from "../../alarms/alarm-state"; import { BrowserStateService } from "../../services/abstractions/browser-state.service"; @@ -8,7 +8,7 @@ import { copyToClipboard } from "./copy-to-clipboard-command"; export class GeneratePasswordToClipboardCommand { constructor( - private passwordGenerationService: PasswordGenerationService, + private passwordGenerationService: PasswordGenerationServiceAbstraction, private stateService: BrowserStateService ) {} diff --git a/apps/browser/src/autofill/content/autofill.js b/apps/browser/src/autofill/content/autofill.js index d9ac840c8d8..e79470b265d 100644 --- a/apps/browser/src/autofill/content/autofill.js +++ b/apps/browser/src/autofill/content/autofill.js @@ -31,21 +31,115 @@ /* MODIFICATIONS FROM ORIGINAL - 1. Populate isFirefox - 2. Remove isChrome and isSafari since they are not used. - 3. Unminify and format to meet Mozilla review requirements. - 4. Remove unnecessary input types from getFormElements query selector and limit number of elements returned. - 5. Remove fakeTested prop. - 6. Rename com.agilebits.* stuff to com.bitwarden.* - 7. Remove "some useful globals" on window - 8. Add ability to autofill span[data-bwautofill] elements - 9. Add new handler, for new command that responds with page details in response callback + 1. Populate isFirefox + 2. Remove isChrome and isSafari since they are not used. + 3. Unminify and format to meet Mozilla review requirements. + 4. Remove unnecessary input types from getFormElements query selector and limit number of elements returned. + 5. Remove fakeTested prop. + 6. Rename com.agilebits.* stuff to com.bitwarden.* + 7. Remove "some useful globals" on window + 8. Add ability to autofill span[data-bwautofill] elements + 9. Add new handler, for new command that responds with page details in response callback 10. Handle sandbox iframe and sandbox rule in CSP 11. Work on array of saved urls instead of just one to determine if we should autofill non-https sites 12. Remove setting of attribute com.browser.browser.userEdited on user-inputs 13. Handle null value URLs in urlNotSecure + 14. Implement new HTML element query logic to be able to traverse into ShadowRoot */ + /* + * `openOrClosedShadowRoot` is only available to WebExtensions. + * We need to use the correct implementation based on browser. + */ + // START MODIFICATION + var getShadowRoot; + + if (chrome.dom && chrome.dom.openOrClosedShadowRoot) { + // Chromium 88+ + // https://developer.chrome.com/docs/extensions/reference/dom/ + getShadowRoot = function (element) { + if (!(element instanceof HTMLElement)) { + return null; + } + + return chrome.dom.openOrClosedShadowRoot(element); + }; + } else { + getShadowRoot = function (element) { + // `openOrClosedShadowRoot` is currently available for Firefox 63+ + // https://developer.mozilla.org/en-US/docs/Web/API/Element/openOrClosedShadowRoot + // Fallback to usual shadowRoot if it doesn't exist, which will only find open ShadowRoots, not closed ones. + // https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot#browser_compatibility + return element.openOrClosedShadowRoot || element.shadowRoot; + }; + } + + /* + * Returns elements like Document.querySelectorAll does, but traverses the document and shadow + * roots, yielding a visited node only if it passes the predicate in filterCallback. + */ + function queryDocAll(doc, rootEl, filterCallback) { + var accumulatedNodes = []; + + // mutates accumulatedNodes + accumulatingQueryDocAll(doc, rootEl, filterCallback, accumulatedNodes); + + return accumulatedNodes; + } + + function accumulatingQueryDocAll(doc, rootEl, filterCallback, accumulatedNodes) { + var treeWalker = doc.createTreeWalker(rootEl, NodeFilter.SHOW_ELEMENT); + var node; + + while (node = treeWalker.nextNode()) { + if (filterCallback(node)) { + accumulatedNodes.push(node); + } + + // If node contains a ShadowRoot we want to step into it and also traverse all child nodes inside. + var nodeShadowRoot = getShadowRoot(node); + + if (!nodeShadowRoot) { + continue; + } + + // recursively traverse into ShadowRoot + accumulatingQueryDocAll(doc, nodeShadowRoot, filterCallback, accumulatedNodes); + } + } + + /* + * Returns an element like Document.querySelector does, but traverses the document and shadow + * roots, yielding a visited node only if it passes the predicate in filterCallback. + */ + function queryDoc(doc, rootEl, filterCallback) { + var treeWalker = doc.createTreeWalker(rootEl, NodeFilter.SHOW_ELEMENT); + var node; + + while (node = treeWalker.nextNode()) { + if (filterCallback(node)) { + return node; + } + + // If node contains a ShadowRoot we want to step into it and also traverse all child nodes inside. + var nodeShadowRoot = getShadowRoot(node); + + if (!nodeShadowRoot) { + continue; + } + + // recursively traverse into ShadowRoot + var subQueryResult = queryDoc(doc, nodeShadowRoot, filterCallback); + + if (subQueryResult) { + return subQueryResult; + } + } + + return null; + } + // END MODIFICATION + function collect(document, undefined) { // START MODIFICATION var isFirefox = navigator.userAgent.indexOf('Firefox') !== -1 || navigator.userAgent.indexOf('Gecko/') !== -1; @@ -56,7 +150,12 @@ function getPageDetails(theDoc, oneShotId) { // start helpers - // get the value of a dom element's attribute + /** + * For a given element `el`, returns the value of the attribute `attrName`. + * @param {HTMLElement} el + * @param {string} attrName + * @returns {string} The value of the attribute + */ function getElementAttrValue(el, attrName) { var attrVal = el[attrName]; if ('string' == typeof attrVal) { @@ -89,7 +188,11 @@ return elType !== el.type; } - // get the value of a dom element + /** + * Returns the value of the given element. + * @param {HTMLElement} el + * @returns {any} Value of the element + */ function getElementValue(el) { switch (toLowerString(el.type)) { case 'checkbox': @@ -113,7 +216,11 @@ } } - // get all the options for a "select" element + /** + * If `el` is a `` element + */ function getSelectElementOptions(el) { if (!el.options) { return null; @@ -132,34 +239,51 @@ }; } - // get the top label + /** + * If `el` is in a data table, get the label in the row directly above it + * @param {HTMLElement} el + * @returns {string} A string containing the label, or null if not found + */ function getLabelTop(el) { var parent; + + // Traverse up the DOM until we reach either the top or the table data element containing our field for (el = el.parentElement || el.parentNode; el && 'td' != toLowerString(el.tagName);) { el = el.parentElement || el.parentNode; } + // If we reached the top, return null if (!el || void 0 === el) { return null; } + // Establish the parent of the table and make sure it's a table row parent = el.parentElement || el.parentNode; if ('tr' != parent.tagName.toLowerCase()) { return null; } + // Get the previous sibling of the table row and make sure it's a table row parent = parent.previousElementSibling; if (!parent || 'tr' != (parent.tagName + '').toLowerCase() || parent.cells && el.cellIndex >= parent.cells.length) { return null; } + // Parent is established as the row above the table data element containing our field + // Now let's traverse over to the cell in the same column as our field el = parent.cells[el.cellIndex]; + + // Get the contents of this label var elText = el.textContent || el.innerText; return elText = cleanText(elText); } - // get all the tags for a given label + /** + * Get the contents of the elements that are labels for `el` + * @param {HTMLElement} el + * @returns {string} A string containing all of the `innerText` or `textContent` values for all elements that are labels for `el` + */ function getLabelTag(el) { var docLabel, theLabels = []; @@ -168,12 +292,22 @@ theLabels = Array.prototype.slice.call(el.labels); } else { if (el.id) { - theLabels = theLabels.concat(Array.prototype.slice.call( - queryDoc(theDoc, 'label[for=' + JSON.stringify(el.id) + ']'))); + // START MODIFICATION + var elId = JSON.stringify(el.id); + var labelsByReferencedId = queryDocAll(theDoc, theDoc.body, function (node) { + return node.nodeName === 'LABEL' && node.htmlFor === elId; + }); + theLabels = theLabels.concat(labelsByReferencedId); + // END MODIFICATION } if (el.name) { - docLabel = queryDoc(theDoc, 'label[for=' + JSON.stringify(el.name) + ']'); + // START MODIFICATION + var elName = JSON.stringify(el.name); + docLabel = queryDocAll(theDoc, theDoc.body, function (node) { + return node.nodeName === 'LABEL' && node.htmlFor === elName; + }); + // END MODIFICATION for (var labelIndex = 0; labelIndex < docLabel.length; labelIndex++) { if (-1 === theLabels.indexOf(docLabel[labelIndex])) { @@ -207,7 +341,13 @@ }).join(''); } - // add property and value to the object if there is a value + /** + * Add property `prop` with value `val` to the object `obj` + * @param {object} obj + * @param {string} prop + * @param {any} val + * @param {*} d + */ function addProp(obj, prop, val, d) { if (0 !== d && d === val || null === val || void 0 === val) { return; @@ -216,27 +356,29 @@ obj[prop] = val; } - // lowercase helper + /** + * Converts the string `s` to lowercase + * @param {string} s + * @returns Lowercase string + */ function toLowerString(s) { return 'string' === typeof s ? s.toLowerCase() : ('' + s).toLowerCase(); } - - // query the document helper - function queryDoc(doc, query) { - var els = []; - try { - els = doc.querySelectorAll(query); - } catch (e) { } - return els; - } - + // START MODIFICATION + // renamed queryDoc to queryDocAll and moved to top + // END MODIFICATION // end helpers var theView = theDoc.defaultView ? theDoc.defaultView : window, passwordRegEx = RegExp('((\\\\b|_|-)pin(\\\\b|_|-)|password|passwort|kennwort|(\\\\b|_|-)passe(\\\\b|_|-)|contraseña|senha|密码|adgangskode|hasło|wachtwoord)', 'i'); // get all the docs - var theForms = Array.prototype.slice.call(queryDoc(theDoc, 'form')).map(function (formEl, elIndex) { + // START MODIFICATION + var formNodes = queryDocAll(theDoc, theDoc.body, function (el) { + return el.nodeName === 'FORM'; + }); + var theForms = formNodes.map(function (formEl, elIndex) { + // END MODIFICATION var op = {}, formOpId = '__form__' + elIndex; @@ -382,7 +524,6 @@ title: theDoc.title, url: theView.location.href, documentUrl: theDoc.location.href, - tabUrl: theView.location.href, forms: function (forms) { var formObj = {}; forms.forEach(function (f) { @@ -395,7 +536,11 @@ }; // get proper page title. maybe they are using the special meta tag? - var theTitle = document.querySelector('[data-onepassword-title]') + // START MODIFICATION + var theTitle = queryDoc(theDoc, theDoc, function (node) { + return node.hasAttribute('data-onepassword-title'); + }); + // END MODIFICATION if (theTitle && theTitle.dataset[DISPLAY_TITLE_ATTRIBUE]) { pageDetails.displayTitle = theTitle.dataset.onepasswordTitle; } @@ -405,6 +550,12 @@ document.elementForOPID = getElementForOPID; + /** + * Do the event on the element. + * @param {HTMLElement} kedol The element to do the event on + * @param {string} fonor The event name + * @returns + */ function doEventOnElement(kedol, fonor) { var quebo; isFirefox ? (quebo = document.createEvent('KeyboardEvent'), quebo.initKeyEvent(fonor, true, false, null, false, false, false, false, 0, 0)) : (quebo = kedol.ownerDocument.createEvent('Events'), @@ -413,20 +564,35 @@ return quebo; } - // clean up the text + /** + * Clean up the string `s` to remove non-printable characters and whitespace. + * @param {string} s + * @returns {string} Clean text + */ function cleanText(s) { var sVal = null; s && (sVal = s.replace(/^\\s+|\\s+$|\\r?\\n.*$/gm, ''), sVal = 0 < sVal.length ? sVal : null); return sVal; } - // check the node type and adjust the array accordingly + /** + * If `el` is a text node, add the node's text to `arr`. + * If `el` is an element node, add the element's `textContent or `innerText` to `arr`. + * @param {string[]} arr An array of `textContent` or `innerText` values + * @param {HTMLElement} el The element to push to the array + */ function checkNodeType(arr, el) { var theText = ''; 3 === el.nodeType ? theText = el.nodeValue : 1 === el.nodeType && (theText = el.textContent || el.innerText); (theText = cleanText(theText)) && arr.push(theText); } + /** + * Check if `el` is a type that indicates the transition to a new section of the page. + * If so, this indicates that we should not use `el` or its children for getting autofill context for the previous element. + * @param {HTMLElement} el The element to check + * @returns {boolean} Returns `true` if `el` is an HTML element from a known set and `false` otherwise + */ function isKnownTag(el) { if (el && void 0 !== el) { var tags = 'select option input form textarea button table iframe body head script'.split(' '); @@ -444,6 +610,12 @@ } } + /** + * Recursively gather all of the text values from the elements preceding `el` in the DOM + * @param {HTMLElement} el + * @param {string[]} arr An array of `textContent` or `innerText` values + * @param {number} steps The number of steps to take up the DOM tree + */ function shiftForLeftLabel(el, arr, steps) { var sib; for (steps || (steps = 0); el && el.previousSibling;) { @@ -470,37 +642,54 @@ } } - // is a dom element visible on screen? + /** + * Determine if the element is visible. + * Visible is define as not having `display: none` or `visibility: hidden`. + * @param {HTMLElement} el + * @returns {boolean} Returns `true` if the element is visible and `false` otherwise + */ function isElementVisible(el) { var theEl = el; + // Get the top level document el = (el = el.ownerDocument) ? el.defaultView : {}; - // walk the dom tree + // walk the dom tree until we reach the top for (var elStyle; theEl && theEl !== document;) { - elStyle = el.getComputedStyle ? el.getComputedStyle(theEl, null) : theEl.style; + // Calculate the style of the element + // START MODIFICATION + elStyle = el.getComputedStyle && theEl instanceof Element ? el.getComputedStyle(theEl, null) : theEl.style; + // END MODIFICATION + + // If there's no computed style at all, we're done, as we know that it's not hidden if (!elStyle) { return true; } + // If the element's computed style includes `display: none` or `visibility: hidden`, we know it's hidden if ('none' === elStyle.display || 'hidden' == elStyle.visibility) { return false; } - // walk up + // At this point, we aren't sure if the element is hidden or not, so we need to keep walking up the tree theEl = theEl.parentNode; } return theEl === document; } - // is a dom element "viewable" on screen? + /** + * Determine if the element is "viewable" on the screen. + * "Viewable" is defined as being visible in the DOM and being within the confines of the viewport. + * @param {HTMLElement} el + * @returns {boolean} Returns `true` if the element is viewable and `false` otherwise + */ function isElementViewable(el) { var theDoc = el.ownerDocument.documentElement, - rect = el.getBoundingClientRect(), - docScrollWidth = theDoc.scrollWidth, - docScrollHeight = theDoc.scrollHeight, - leftOffset = rect.left - theDoc.clientLeft, - topOffset = rect.top - theDoc.clientTop, + rect = el.getBoundingClientRect(), // getBoundingClientRect is relative to the viewport + docScrollWidth = theDoc.scrollWidth, // scrollWidth is the width of the document including any overflow + docScrollHeight = theDoc.scrollHeight, // scrollHeight is the height of the document including any overflow + leftOffset = rect.left - theDoc.clientLeft, // How far from the left of the viewport is the element, minus the left border width? + topOffset = rect.top - theDoc.clientTop, // How far from the top of the viewport is the element, minus the top border width? theRect; if (!isElementVisible(el) || !el.offsetParent || 10 > el.clientWidth || 10 > el.clientHeight) { @@ -512,30 +701,49 @@ return false; } + // If any of the rects have a left side that is further right than the document width or a right side that is + // further left than the origin (i.e. is negative), we consider the element to be not viewable for (var i = 0; i < rects.length; i++) { if (theRect = rects[i], theRect.left > docScrollWidth || 0 > theRect.right) { return false; } } + // If the element is further left than the document width, or further down than the document height, we know that it's not viewable if (0 > leftOffset || leftOffset > docScrollWidth || 0 > topOffset || topOffset > docScrollHeight) { return false; } - // walk the tree + // Our next check is going to get the center point of the element, and then use elementFromPoint to see if the element + // is actually returned from that point. If it is, we know that it's viewable. If it isn't, we know that it's not viewable. + // If the right side of the bounding rectangle is outside the viewport, the x coordinate of the center point is the window width (minus offset) divided by 2. + // If the right side of the bounding rectangle is inside the viewport, the x coordinate of the center point is the width of the bounding rectangle divided by 2. + // If the bottom of the bounding rectangle is outside the viewport, the y coordinate of the center point is the window height (minus offset) divided by 2. + // If the bottom side of the bounding rectangle is inside the viewport, the y coordinate of the center point is the height of the bounding rectangle divided by + // We then use elementFromPoint to find the element at that point. for (var pointEl = el.ownerDocument.elementFromPoint(leftOffset + (rect.right > window.innerWidth ? (window.innerWidth - leftOffset) / 2 : rect.width / 2), topOffset + (rect.bottom > window.innerHeight ? (window.innerHeight - topOffset) / 2 : rect.height / 2)); pointEl && pointEl !== el && pointEl !== document;) { - if (pointEl.tagName && 'string' === typeof pointEl.tagName && 'label' === pointEl.tagName.toLowerCase() - && el.labels && 0 < el.labels.length) { - return 0 <= Array.prototype.slice.call(el.labels).indexOf(pointEl); - } + // If the element we found is a label, and the element we're checking has labels + if (pointEl.tagName && 'string' === typeof pointEl.tagName && 'label' === pointEl.tagName.toLowerCase() + && el.labels && 0 < el.labels.length) { + // Return true if the element we found is one of the labels for the element we're checking. + // This means that the element we're looking for is considered viewable + return 0 <= Array.prototype.slice.call(el.labels).indexOf(pointEl); + } - // walk up - pointEl = pointEl.parentNode; + // Walk up the DOM tree to check the parent element + pointEl = pointEl.parentNode; } + // If the for loop exited because we found the element we're looking for, return true, as it's viewable + // If the element that we found isn't the element we're looking for, it means the element we're looking for is not viewable return pointEl === el; } + /** + * Retrieve the element from the document with the specified `opid` property + * @param {number} opId + * @returns {HTMLElement} The element with the specified `opiId`, or `null` if no such element exists + */ function getElementForOPID(opId) { var theEl; if (void 0 === opId || null === opId) { @@ -561,16 +769,49 @@ } } - // get all the form elements that we care about + var ignoredInputTypes = { + hidden: true, + submit: true, + reset: true, + button: true, + image: true, + file: true, + }; + + /* + * inputEl MUST BE an instanceof HTMLInputElement, else inputEl.type.toLowerCase will throw an error + */ + function isRelevantInputField(inputEl) { + if (inputEl.hasAttribute('data-bwignore')) { + return false; + } + + const isIgnoredInputType = ignoredInputTypes.hasOwnProperty(inputEl.type.toLowerCase()); + + return !isIgnoredInputType; + } + + /** + * Query `theDoc` for form elements that we can use for autofill, ranked by importance and limited by `limit` + * @param {Document} theDoc The Document to query + * @param {number} limit The maximum number of elements to return + * @returns An array of HTMLElements + */ function getFormElements(theDoc, limit) { // START MODIFICATION - var els = []; - try { - var elsList = theDoc.querySelectorAll('input:not([type="hidden"]):not([type="submit"]):not([type="reset"])' + - ':not([type="button"]):not([type="image"]):not([type="file"]):not([data-bwignore]), select, ' + - 'span[data-bwautofill]'); - els = Array.prototype.slice.call(elsList); - } catch (e) { } + + var els = queryDocAll(theDoc, theDoc.body, function (el) { + switch (el.nodeName) { + case 'SELECT': + return true; + case 'SPAN': + return el.hasAttribute('data-bwautofill'); + case 'INPUT': + return isRelevantInputField(el); + default: + return false; + } + }); if (!limit || els.length <= limit) { return els; @@ -600,10 +841,14 @@ } return returnEls; - // END MODIFICATION } + // END MODIFICATION - // focus the element and optionally restore its original value + /** + * Focus the element `el` and optionally restore its original value + * @param {HTMLElement} el + * @param {boolean} setVal Set the value of the element to its original value + */ function focusElement(el, setVal) { if (setVal) { var initialValue = el.value; @@ -626,6 +871,12 @@ var markTheFilling = true, animateTheFilling = true; + function queryPasswordInputs() { + return queryDocAll(document, document.body, function (el) { + return el.nodeName === 'INPUT' && el.type.toLowerCase() === 'password'; + }) + } + // Check if URL is not secure when the original saved one was function urlNotSecure(savedURLs) { var passwordInputs = null; @@ -633,7 +884,7 @@ return false; } - return savedURLs.some(url => url?.indexOf('https://') === 0) && 'http:' === document.location.protocol && (passwordInputs = document.querySelectorAll('input[type=password]'), + return savedURLs.some(url => url?.indexOf('https://') === 0) && 'http:' === document.location.protocol && (passwordInputs = queryPasswordInputs(), 0 < passwordInputs.length && (confirmResult = confirm('Warning: This is an unsecured HTTP page, and any information you submit can potentially be seen and changed by others. This Login was originally saved on a secure (HTTPS) page.\n\nDo you still wish to fill this login?'), 0 == confirmResult)) ? true : false; } @@ -660,6 +911,19 @@ return; } + if (fillScript.untrustedIframe) { + // confirm() is blocked by sandboxed iframes, but we don't want to fill sandboxed iframes anyway. + // If this occurs, confirm() returns false without displaying the dialog box, and autofill will be aborted. + // The browser may print a message to the console, but this is not a standard error that we can handle. + var acceptedIframeWarning = confirm("The form is hosted by a different domain than the URI " + + "of your saved login. Choose OK to auto-fill anyway, or Cancel to stop. " + + "To prevent this warning in the future, save this URI, " + + window.location.hostname + ", to your login."); + if (!acceptedIframeWarning) { + return; + } + } + doOperation = function (ops, theOperation) { var op = ops[0]; if (void 0 === op) { @@ -755,7 +1019,12 @@ return el ? (fillTheElement(el, op), [el]) : null; } - // do a fill by query operation + /** + * Find all elements matching `query` and fill them using the value `op` from the fill script + * @param {string} query + * @param {string} op + * @returns {HTMLElement} + */ function doFillByQuery(query, op) { var elements = selectAllFromDoc(query); return Array.prototype.map.call(Array.prototype.slice.call(elements), function (el) { @@ -764,7 +1033,12 @@ }, this); } - // do a simple set value by query + /** + * Assign `valueToSet` to all elements in the DOM that match `query`. + * @param {string} query + * @param {string} valueToSet + * @returns {Array} Array of elements that were set. + */ function doSimpleSetByQuery(query, valueToSet) { var elements = selectAllFromDoc(query), arr = []; @@ -774,7 +1048,11 @@ return arr; } - // focus by opid + /** + * Do a a click and focus on the element with the given `opId`. + * @param {number} opId + * @returns + */ function doFocusByOpId(opId) { var el = getElementByOpId(opId) if (el) { @@ -785,13 +1063,21 @@ return null; } - // do a click by opid operation + /** + * Do a click on the element with the given `opId`. + * @param {number} opId + * @returns + */ function doClickByOpId(opId) { var el = getElementByOpId(opId); return el ? clickElement(el) ? [el] : null : null; } - // do a click by query operation + /** + * Do a `click` and `focus` on all elements that match the query. + * @param {string} query + * @returns + */ function doClickByQuery(query) { query = selectAllFromDoc(query); return Array.prototype.map.call(Array.prototype.slice.call(query), function (el) { @@ -811,7 +1097,11 @@ }, styleTimeout = 200; - // fill an element + /** + * Fll an element `el` using the value `op` from the fill script + * @param {HTMLElement} el + * @param {string} op + */ function fillTheElement(el, op) { var shouldCheck; if (el && null !== op && void 0 !== op && !(el.disabled || el.a || el.readOnly)) { @@ -840,7 +1130,11 @@ } } - // do all the full operations needed + /** + * Do all the fill operations needed on the element `el`. + * @param {HTMLElement} el + * @param {*} afterValSetFunc The function to perform after the operations are complete. + */ function doAllFillOperations(el, afterValSetFunc) { setValueForElement(el); afterValSetFunc(el); @@ -860,7 +1154,12 @@ document.elementForOPID = getElementByOpId; - // normalize the event based on API support + /** + * Normalize the event based on API support + * @param {HTMLElement} el + * @param {string} eventName + * @returns {Event} A normalized event + */ function normalizeEvent(el, eventName) { var ev; if ('KeyboardEvent' in window) { @@ -882,7 +1181,11 @@ return ev; } - // set value of the given element + /** + * Simulate the entry of a value into an element. + * Clicks the element, focuses it, and then fires a keydown, keypress, and keyup event. + * @param {HTMLElement} el + */ function setValueForElement(el) { var valueToSet = el.value; clickElement(el); @@ -893,7 +1196,11 @@ el.value !== valueToSet && (el.value = valueToSet); } - // set value of the given element by using events + /** + * Simulate the entry of a value into an element by using events. + * Dispatches a keydown, keypress, and keyup event, then fires the `input` and `change` events before removing focus. + * @param {HTMLElement} el + */ function setValueForElementByEvent(el) { var valueToSet = el.value, ev1 = el.ownerDocument.createEvent('HTMLEvents'), @@ -910,7 +1217,11 @@ el.value !== valueToSet && (el.value = valueToSet); } - // click on an element + /** + * Click on an element `el` + * @param {HTMLElement} el + * @returns {boolean} Returns true if the element was clicked and false if it was not able to be clicked + */ function clickElement(el) { if (!el || el && 'function' !== typeof el.click) { return false; @@ -919,15 +1230,23 @@ return true; } - // get all fields we care about + /** + * Get all the elements on the DOM that are likely to be a password field + * @returns {Array} Array of elements + */ function getAllFields() { var r = RegExp('((\\\\b|_|-)pin(\\\\b|_|-)|password|passwort|kennwort|passe|contraseña|senha|密码|adgangskode|hasło|wachtwoord)', 'i'); - return Array.prototype.slice.call(selectAllFromDoc("input[type='text']")).filter(function (el) { - return el.value && r.test(el.value); - }, this); + return queryDocAll(document, document.body, function (el) { + return el.nodeName === 'INPUT' && + el.type.toLowerCase() === 'text' && + el.value && + r.test(el.value); + }); } - // touch all the fields + /** + * Touch all the fields + */ function touchAllFields() { getAllFields().forEach(function (el) { setValueForElement(el); @@ -936,14 +1255,20 @@ }); } - // can we see the element to apply some styling? + /** + * Determine if we can apply styling to `el` to indicate that it was filled. + * @param {HTMLElement} el + * @returns {boolean} Returns true if we can see the element to apply styling. + */ function canSeeElementToStyle(el) { var currentEl; if (currentEl = animateTheFilling) { a: { currentEl = el; for (var owner = el.ownerDocument, owner = owner ? owner.defaultView : {}, theStyle; currentEl && currentEl !== document;) { - theStyle = owner.getComputedStyle ? owner.getComputedStyle(currentEl, null) : currentEl.style; + // START MODIFICATION + theStyle = owner.getComputedStyle && currentEl instanceof Element ? owner.getComputedStyle(currentEl, null) : currentEl.style; + // END MODIFICATION if (!theStyle) { currentEl = true; break a; @@ -965,7 +1290,11 @@ return currentEl ? -1 !== 'email text password number tel url'.split(' ').indexOf(el.type || '') : false; } - // find the element for this operation + /** + * Find the element for the given `opid`. + * @param {number} theOpId + * @returns {HTMLElement} The element for the given `opid`, or `null` if not found. + */ function getElementByOpId(theOpId) { var theElement; if (void 0 === theOpId || null === theOpId) { @@ -973,12 +1302,19 @@ } try { // START MODIFICATION - var elements = Array.prototype.slice.call(selectAllFromDoc('input, select, button, ' + - 'span[data-bwautofill]')); - // END MODIFICATION - var filteredElements = elements.filter(function (o) { - return o.opid == theOpId; + var filteredElements = queryDocAll(document, document.body, function (el) { + switch (el.nodeName) { + case 'INPUT': + case 'SELECT': + case 'BUTTON': + return el.opid === theOpId; + case 'SPAN': + return el.hasAttribute('data-bwautofill') && el.opid === theOpId; + } + + return false; }); + // END MODIFICATION if (0 < filteredElements.length) { theElement = filteredElements[0], 1 < filteredElements.length && console.warn('More than one element found with opid ' + theOpId); @@ -993,16 +1329,24 @@ } } - // helper for doc.querySelectorAll + /** + * Helper for doc.querySelectorAll + * @param {string} theSelector + * @returns + */ function selectAllFromDoc(theSelector) { - var d = document, elements = []; - try { - elements = d.querySelectorAll(theSelector); - } catch (e) { } - return elements; + // START MODIFICATION + return queryDocAll(document, document, function(node) { + return node.matches(theSelector); + }); + // END MODIFICATION } - // focus an element and optionally re-set its value after focusing + /** + * Focus an element and optionally re-set its value after focusing + * @param {HTMLElement} el + * @param {boolean} setValue Re-set the value after focusing + */ function doFocusElement(el, setValue) { if (setValue) { var existingValue = el.value; diff --git a/apps/browser/src/autofill/content/message_handler.ts b/apps/browser/src/autofill/content/message_handler.ts index 0f690bd4f79..5302a5042be 100644 --- a/apps/browser/src/autofill/content/message_handler.ts +++ b/apps/browser/src/autofill/content/message_handler.ts @@ -31,6 +31,7 @@ const forwardCommands = [ "addToLockedVaultPendingNotifications", "unlockCompleted", "addedCipher", + "openAddEditCipher", ]; chrome.runtime.onMessage.addListener((event) => { diff --git a/apps/browser/src/autofill/content/notification-bar.ts b/apps/browser/src/autofill/content/notification-bar.ts index 5a6d519b75e..c031929988d 100644 --- a/apps/browser/src/autofill/content/notification-bar.ts +++ b/apps/browser/src/autofill/content/notification-bar.ts @@ -502,6 +502,7 @@ document.addEventListener("DOMContentLoaded", (event) => { type, isVaultLocked: typeData.isVaultLocked, theme: typeData.theme, + removeIndividualVault: typeData.removeIndividualVault, }; const barQueryString = new URLSearchParams(barQueryParams).toString(); const barPage = "notification/bar.html?" + barQueryString; diff --git a/apps/browser/src/autofill/models/autofill-field.ts b/apps/browser/src/autofill/models/autofill-field.ts index 96da54f6770..425e1dadcb7 100644 --- a/apps/browser/src/autofill/models/autofill-field.ts +++ b/apps/browser/src/autofill/models/autofill-field.ts @@ -1,26 +1,101 @@ +/** + * Represents a single field that is collected from the page source and is potentially autofilled. + */ export default class AutofillField { + /** + * The unique identifier assigned to this field during collection of the page details + */ opid: string; + /** + * Sequential number assigned to each element collected, based on its position in the DOM. + * Used to do perform proximal checks for username and password fields on the DOM. + */ elementNumber: number; + /** + * Designates whether the field is visible, based on the element's style + */ visible: boolean; + /** + * Designates whether the field is viewable on the current part of the DOM that the user can see + */ viewable: boolean; + /** + * The HTML `id` attribute of the field + */ htmlID: string; + /** + * The HTML `name` attribute of the field + */ htmlName: string; + /** + * The HTML `class` attribute of the field + */ htmlClass: string; + /** + * The concatenated `innerText` or `textContent` of all the elements that are to the "left" of the field in the DOM + */ "label-left": string; + /** + * The concatenated `innerText` or `textContent` of all the elements that are to the "right" of the field in the DOM + */ "label-right": string; + /** + * For fields in a data table, the contents of the table row immediately above the field + */ "label-top": string; + /** + * The contatenated `innerText` or `textContent` of all elements that are HTML labels for the field + */ "label-tag": string; + /** + * The `aria-label` attribute for the field + */ "label-aria": string; + /** + * The HTML `placeholder` attribute for the field + */ placeholder: string; + /** + * The HTML `type` attribute for the field + */ type: string; + /** + * The HTML `value` for the field + */ value: string; + /** + * The `disabled` status of the field + */ disabled: boolean; + /** + * The `readonly` status of the field + */ readonly: boolean; + /** + * @deprecated + * The `onePasswordFieldType` from the `dataset` on the element. + * If empty it contains the HTML `type` attribute for the field. + */ onePasswordFieldType: string; + /** + * The `opid` attribute value of the form that contains the field + */ form: string; + /** + * The `x-autocompletetype`, `autocompletetype`, or `autocomplete` attribute for the field + */ autoCompleteType: string; + /** + * For ` - -
-
-
-
-
- -
+ + + + + diff --git a/apps/browser/src/autofill/notification/bar.js b/apps/browser/src/autofill/notification/bar.js deleted file mode 100644 index 316b817c36c..00000000000 --- a/apps/browser/src/autofill/notification/bar.js +++ /dev/null @@ -1,168 +0,0 @@ -// eslint-disable-next-line -require("./bar.scss"); - -document.addEventListener("DOMContentLoaded", () => { - const theme = getQueryVariable("theme"); - document.documentElement.classList.add("theme_" + theme); - - let i18n = {}; - let lang = window.navigator.language; - - i18n.appName = chrome.i18n.getMessage("appName"); - i18n.close = chrome.i18n.getMessage("close"); - i18n.never = chrome.i18n.getMessage("never"); - i18n.folder = chrome.i18n.getMessage("folder"); - i18n.notificationAddSave = chrome.i18n.getMessage("notificationAddSave"); - i18n.notificationAddDesc = chrome.i18n.getMessage("notificationAddDesc"); - i18n.notificationChangeSave = chrome.i18n.getMessage("notificationChangeSave"); - i18n.notificationChangeDesc = chrome.i18n.getMessage("notificationChangeDesc"); - lang = chrome.i18n.getUILanguage(); // eslint-disable-line - - // delay 50ms so that we get proper body dimensions - setTimeout(load, 50); - - function load() { - const isVaultLocked = getQueryVariable("isVaultLocked") == "true"; - document.getElementById("logo").src = isVaultLocked - ? chrome.runtime.getURL("images/icon38_locked.png") - : chrome.runtime.getURL("images/icon38.png"); - - document.getElementById("logo-link").title = i18n.appName; - - var neverButton = document.querySelector("#template-add .never-save"); - neverButton.textContent = i18n.never; - - var selectFolder = document.querySelector("#template-add .select-folder"); - selectFolder.setAttribute("aria-label", i18n.folder); - selectFolder.setAttribute("isVaultLocked", isVaultLocked.toString()); - - var addButton = document.querySelector("#template-add .add-save"); - addButton.textContent = i18n.notificationAddSave; - - var changeButton = document.querySelector("#template-change .change-save"); - changeButton.textContent = i18n.notificationChangeSave; - - var closeButton = document.getElementById("close-button"); - closeButton.title = i18n.close; - closeButton.setAttribute("aria-label", i18n.close); - - document.querySelector("#template-add .add-text").textContent = i18n.notificationAddDesc; - document.querySelector("#template-change .change-text").textContent = - i18n.notificationChangeDesc; - - if (getQueryVariable("type") === "add") { - handleTypeAdd(isVaultLocked); - } else if (getQueryVariable("type") === "change") { - handleTypeChange(); - } - - closeButton.addEventListener("click", (e) => { - e.preventDefault(); - sendPlatformMessage({ - command: "bgCloseNotificationBar", - }); - }); - - window.addEventListener("resize", adjustHeight); - adjustHeight(); - } - - function getQueryVariable(variable) { - var query = window.location.search.substring(1); - var vars = query.split("&"); - - for (var i = 0; i < vars.length; i++) { - var pair = vars[i].split("="); - if (pair[0] === variable) { - return pair[1]; - } - } - - return null; - } - - function handleTypeAdd(isVaultLocked) { - setContent(document.getElementById("template-add")); - - var addButton = document.querySelector("#template-add-clone .add-save"), // eslint-disable-line - neverButton = document.querySelector("#template-add-clone .never-save"); // eslint-disable-line - - addButton.addEventListener("click", (e) => { - e.preventDefault(); - - const folderId = document.querySelector("#template-add-clone .select-folder").value; - - const bgAddSaveMessage = { - command: "bgAddSave", - folder: folderId, - }; - sendPlatformMessage(bgAddSaveMessage); - }); - - neverButton.addEventListener("click", (e) => { - e.preventDefault(); - sendPlatformMessage({ - command: "bgNeverSave", - }); - }); - - if (!isVaultLocked) { - const responseFoldersCommand = "notificationBarGetFoldersList"; - chrome.runtime.onMessage.addListener((msg) => { - if (msg.command === responseFoldersCommand && msg.data) { - fillSelectorWithFolders(msg.data.folders); - } - }); - sendPlatformMessage({ - command: "bgGetDataForTab", - responseCommand: responseFoldersCommand, - }); - } - } - - function handleTypeChange() { - setContent(document.getElementById("template-change")); - var changeButton = document.querySelector("#template-change-clone .change-save"); // eslint-disable-line - changeButton.addEventListener("click", (e) => { - e.preventDefault(); - - const bgChangeSaveMessage = { - command: "bgChangeSave", - }; - sendPlatformMessage(bgChangeSaveMessage); - }); - } - - function setContent(element) { - const content = document.getElementById("content"); - while (content.firstChild) { - content.removeChild(content.firstChild); - } - - var newElement = element.cloneNode(true); - newElement.id = newElement.id + "-clone"; - content.appendChild(newElement); - } - - function sendPlatformMessage(msg) { - chrome.runtime.sendMessage(msg); - } - - function fillSelectorWithFolders(folders) { - const select = document.querySelector("#template-add-clone .select-folder"); - select.appendChild(new Option(chrome.i18n.getMessage("selectFolder"), null, true)); - folders.forEach((folder) => { - //Select "No Folder" (id=null) folder by default - select.appendChild(new Option(folder.name, folder.id || "", false)); - }); - } - - function adjustHeight() { - sendPlatformMessage({ - command: "bgAdjustNotificationBar", - data: { - height: document.querySelector("body").scrollHeight, - }, - }); - } -}); diff --git a/apps/browser/src/autofill/notification/bar.scss b/apps/browser/src/autofill/notification/bar.scss index 581b34f3766..3fdfca01a43 100644 --- a/apps/browser/src/autofill/notification/bar.scss +++ b/apps/browser/src/autofill/notification/bar.scss @@ -80,7 +80,7 @@ button { cursor: pointer; } -button:not(.neutral):not(.link) { +button.primary:not(.neutral) { @include themify($themes) { background-color: themed("primaryColor"); color: themed("textContrast"); @@ -95,6 +95,21 @@ button:not(.neutral):not(.link) { } } +button.secondary:not(.neutral) { + @include themify($themes) { + background-color: themed("backgroundColor"); + color: themed("mutedTextColor"); + border-color: themed("mutedTextColor"); + } + + &:hover { + @include themify($themes) { + background-color: darken(themed("backgroundColor"), 1.5%); + color: darken(themed("mutedTextColor"), 6%); + } + } +} + button.link, button.neutral { @include themify($themes) { @@ -130,12 +145,8 @@ button { font-family: $font-family-sans-serif; } -.select-folder[isVaultLocked="true"] { - display: none; -} - @media screen and (max-width: 768px) { - .select-folder { + #select-folder { display: none; } } diff --git a/apps/browser/src/autofill/notification/bar.ts b/apps/browser/src/autofill/notification/bar.ts new file mode 100644 index 00000000000..59367dabee4 --- /dev/null +++ b/apps/browser/src/autofill/notification/bar.ts @@ -0,0 +1,218 @@ +import type { Jsonify } from "type-fest"; + +import type { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; + +require("./bar.scss"); + +document.addEventListener("DOMContentLoaded", () => { + // delay 50ms so that we get proper body dimensions + setTimeout(load, 50); +}); + +function load() { + const theme = getQueryVariable("theme"); + document.documentElement.classList.add("theme_" + theme); + + const isVaultLocked = getQueryVariable("isVaultLocked") == "true"; + (document.getElementById("logo") as HTMLImageElement).src = isVaultLocked + ? chrome.runtime.getURL("images/icon38_locked.png") + : chrome.runtime.getURL("images/icon38.png"); + + const i18n = { + appName: chrome.i18n.getMessage("appName"), + close: chrome.i18n.getMessage("close"), + never: chrome.i18n.getMessage("never"), + folder: chrome.i18n.getMessage("folder"), + notificationAddSave: chrome.i18n.getMessage("notificationAddSave"), + notificationAddDesc: chrome.i18n.getMessage("notificationAddDesc"), + notificationEdit: chrome.i18n.getMessage("edit"), + notificationChangeSave: chrome.i18n.getMessage("notificationChangeSave"), + notificationChangeDesc: chrome.i18n.getMessage("notificationChangeDesc"), + }; + + document.getElementById("logo-link").title = i18n.appName; + + // i18n for "Add" template + const addTemplate = document.getElementById("template-add") as HTMLTemplateElement; + + const neverButton = addTemplate.content.getElementById("never-save"); + neverButton.textContent = i18n.never; + + const selectFolder = addTemplate.content.getElementById("select-folder"); + selectFolder.hidden = isVaultLocked || removeIndividualVault(); + selectFolder.setAttribute("aria-label", i18n.folder); + + const addButton = addTemplate.content.getElementById("add-save"); + addButton.textContent = i18n.notificationAddSave; + + const addEditButton = addTemplate.content.getElementById("add-edit"); + // If Remove Individual Vault policy applies, "Add" opens the edit tab, so we hide the Edit button + addEditButton.hidden = removeIndividualVault(); + addEditButton.textContent = i18n.notificationEdit; + + addTemplate.content.getElementById("add-text").textContent = i18n.notificationAddDesc; + + // i18n for "Change" (update password) template + const changeTemplate = document.getElementById("template-change") as HTMLTemplateElement; + + const changeButton = changeTemplate.content.getElementById("change-save"); + changeButton.textContent = i18n.notificationChangeSave; + + const changeEditButton = changeTemplate.content.getElementById("change-edit"); + changeEditButton.textContent = i18n.notificationEdit; + + changeTemplate.content.getElementById("change-text").textContent = i18n.notificationChangeDesc; + + // i18n for body content + const closeButton = document.getElementById("close-button"); + closeButton.title = i18n.close; + + if (getQueryVariable("type") === "add") { + handleTypeAdd(); + } else if (getQueryVariable("type") === "change") { + handleTypeChange(); + } + + closeButton.addEventListener("click", (e) => { + e.preventDefault(); + sendPlatformMessage({ + command: "bgCloseNotificationBar", + }); + }); + + window.addEventListener("resize", adjustHeight); + adjustHeight(); +} + +function getQueryVariable(variable: string) { + const query = window.location.search.substring(1); + const vars = query.split("&"); + + for (let i = 0; i < vars.length; i++) { + const pair = vars[i].split("="); + if (pair[0] === variable) { + return pair[1]; + } + } + + return null; +} + +function handleTypeAdd() { + setContent(document.getElementById("template-add") as HTMLTemplateElement); + + const addButton = document.getElementById("add-save"); + addButton.addEventListener("click", (e) => { + e.preventDefault(); + + // If Remove Individual Vault policy applies, "Add" opens the edit tab + sendPlatformMessage({ + command: "bgAddSave", + folder: getSelectedFolder(), + edit: removeIndividualVault(), + }); + }); + + if (removeIndividualVault()) { + // Everything past this point is only required if user has an individual vault + return; + } + + const editButton = document.getElementById("add-edit"); + editButton.addEventListener("click", (e) => { + e.preventDefault(); + + sendPlatformMessage({ + command: "bgAddSave", + folder: getSelectedFolder(), + edit: true, + }); + }); + + const neverButton = document.getElementById("never-save"); + neverButton.addEventListener("click", (e) => { + e.preventDefault(); + sendPlatformMessage({ + command: "bgNeverSave", + }); + }); + + loadFolderSelector(); +} + +function handleTypeChange() { + setContent(document.getElementById("template-change") as HTMLTemplateElement); + const changeButton = document.getElementById("change-save"); + changeButton.addEventListener("click", (e) => { + e.preventDefault(); + + sendPlatformMessage({ + command: "bgChangeSave", + edit: false, + }); + }); + + const editButton = document.getElementById("change-edit"); + editButton.addEventListener("click", (e) => { + e.preventDefault(); + + sendPlatformMessage({ + command: "bgChangeSave", + edit: true, + }); + }); +} + +function setContent(template: HTMLTemplateElement) { + const content = document.getElementById("content"); + while (content.firstChild) { + content.removeChild(content.firstChild); + } + + const newElement = template.content.cloneNode(true) as HTMLElement; + content.appendChild(newElement); +} + +function sendPlatformMessage(msg: Record) { + chrome.runtime.sendMessage(msg); +} + +function loadFolderSelector() { + const responseFoldersCommand = "notificationBarGetFoldersList"; + + chrome.runtime.onMessage.addListener((msg) => { + if (msg.command !== responseFoldersCommand || msg.data == null) { + return; + } + + const folders = msg.data.folders as Jsonify; + const select = document.getElementById("select-folder"); + select.appendChild(new Option(chrome.i18n.getMessage("selectFolder"), null, true)); + folders.forEach((folder) => { + // Select "No Folder" (id=null) folder by default + select.appendChild(new Option(folder.name, folder.id || "", false)); + }); + }); + + sendPlatformMessage({ + command: "bgGetDataForTab", + responseCommand: responseFoldersCommand, + }); +} + +function getSelectedFolder(): string { + return (document.getElementById("select-folder") as HTMLSelectElement).value; +} + +function removeIndividualVault(): boolean { + return getQueryVariable("removeIndividualVault") == "true"; +} + +function adjustHeight() { + sendPlatformMessage({ + command: "bgAdjustNotificationBar", + data: { + height: document.querySelector("body").scrollHeight, + }, + }); +} diff --git a/apps/browser/src/autofill/notification/variables.scss b/apps/browser/src/autofill/notification/variables.scss index ced15691997..bb29ad86336 100644 --- a/apps/browser/src/autofill/notification/variables.scss +++ b/apps/browser/src/autofill/notification/variables.scss @@ -10,6 +10,7 @@ $brand-primary: #175ddc; $background-color: #f0f0f0; +$solarizedDarkBase0: #839496; $solarizedDarkBase03: #002b36; $solarizedDarkBase02: #073642; $solarizedDarkBase01: #586e75; @@ -20,6 +21,7 @@ $solarizedDarkGreen: #859900; $themes: ( light: ( textColor: $text-color, + mutedTextColor: #6d757e, backgroundColor: $background-color, primaryColor: $brand-primary, buttonPrimaryColor: $brand-primary, @@ -29,6 +31,7 @@ $themes: ( ), dark: ( textColor: #ffffff, + mutedTextColor: #bac0ce, backgroundColor: #2f343d, buttonPrimaryColor: #6f9df1, primaryColor: #6f9df1, @@ -38,6 +41,7 @@ $themes: ( ), nord: ( textColor: $nord5, + mutedTextColor: $nord4, backgroundColor: $nord1, buttonPrimaryColor: $nord8, primaryColor: $nord9, @@ -47,6 +51,8 @@ $themes: ( ), solarizedDark: ( textColor: $solarizedDarkBase2, + // Muted uses main text color to avoid contrast issues + mutedTextColor: $solarizedDarkBase2, backgroundColor: $solarizedDarkBase03, buttonPrimaryColor: $solarizedDarkCyan, primaryColor: $solarizedDarkGreen, diff --git a/apps/browser/src/autofill/services/abstractions/autofill.service.ts b/apps/browser/src/autofill/services/abstractions/autofill.service.ts index b65467eec72..2840c6dd5d5 100644 --- a/apps/browser/src/autofill/services/abstractions/autofill.service.ts +++ b/apps/browser/src/autofill/services/abstractions/autofill.service.ts @@ -1,3 +1,4 @@ +import { UriMatchType } from "@bitwarden/common/enums/uriMatchType"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import AutofillField from "../../models/autofill-field"; @@ -20,6 +21,7 @@ export interface AutoFillOptions { onlyVisibleFields?: boolean; fillNewPassword?: boolean; skipLastUsed?: boolean; + allowUntrustedIframe?: boolean; } export interface FormData { @@ -38,4 +40,9 @@ export abstract class AutofillService { fromCommand: boolean ) => Promise; doAutoFillActiveTab: (pageDetails: PageDetail[], fromCommand: boolean) => Promise; + iframeUrlMatches: ( + pageUrl: string, + loginItem: CipherView, + defaultUriMatch: UriMatchType + ) => boolean; } diff --git a/apps/browser/src/services/autofillConstants.ts b/apps/browser/src/autofill/services/autofill-constants.ts similarity index 100% rename from apps/browser/src/services/autofillConstants.ts rename to apps/browser/src/autofill/services/autofill-constants.ts diff --git a/apps/browser/src/autofill/services/autofill.service.ts b/apps/browser/src/autofill/services/autofill.service.ts index c7f9d879a4e..35dbe4b8ea8 100644 --- a/apps/browser/src/autofill/services/autofill.service.ts +++ b/apps/browser/src/autofill/services/autofill.service.ts @@ -1,22 +1,20 @@ import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; +import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service"; import { EventType } from "@bitwarden/common/enums/eventType"; import { FieldType } from "@bitwarden/common/enums/fieldType"; import { UriMatchType } from "@bitwarden/common/enums/uriMatchType"; +import { Utils } from "@bitwarden/common/misc/utils"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FieldView } from "@bitwarden/common/vault/models/view/field.view"; +import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view"; import { BrowserApi } from "../../browser/browserApi"; import { BrowserStateService } from "../../services/abstractions/browser-state.service"; -import { - AutoFillConstants, - CreditCardAutoFillConstants, - IdentityAutoFillConstants, -} from "../../services/autofillConstants"; import AutofillField from "../models/autofill-field"; import AutofillPageDetails from "../models/autofill-page-details"; import AutofillScript from "../models/autofill-script"; @@ -27,6 +25,11 @@ import { PageDetail, FormData, } from "./abstractions/autofill.service"; +import { + AutoFillConstants, + CreditCardAutoFillConstants, + IdentityAutoFillConstants, +} from "./autofill-constants"; export interface GenerateFillScriptOptions { skipUsernameOnlyFill: boolean; @@ -34,6 +37,8 @@ export interface GenerateFillScriptOptions { onlyVisibleFields: boolean; fillNewPassword: boolean; cipher: CipherView; + tabUrl: string; + defaultUriMatch: UriMatchType; } export default class AutofillService implements AutofillServiceInterface { @@ -42,7 +47,8 @@ export default class AutofillService implements AutofillServiceInterface { private stateService: BrowserStateService, private totpService: TotpService, private eventCollectionService: EventCollectionService, - private logService: LogService + private logService: LogService, + private settingsService: SettingsService ) {} getFormsWithPasswordFields(pageDetails: AutofillPageDetails): FormData[] { @@ -84,7 +90,12 @@ export default class AutofillService implements AutofillServiceInterface { return formData; } - async doAutoFill(options: AutoFillOptions) { + /** + * Autofills a given tab with a given login item + * @param options Instructions about the autofill operation, including tab and login item + * @returns The TOTP code of the successfully autofilled login, if any + */ + async doAutoFill(options: AutoFillOptions): Promise { const tab = options.tab; if (!tab || !options.cipher || !options.pageDetails || !options.pageDetails.length) { throw new Error("Nothing to auto-fill."); @@ -93,6 +104,8 @@ export default class AutofillService implements AutofillServiceInterface { let totpPromise: Promise = null; const canAccessPremium = await this.stateService.getCanAccessPremium(); + const defaultUriMatch = (await this.stateService.getDefaultUriMatch()) ?? UriMatchType.Domain; + let didAutofill = false; options.pageDetails.forEach((pd) => { // make sure we're still on correct tab @@ -106,12 +119,23 @@ export default class AutofillService implements AutofillServiceInterface { onlyVisibleFields: options.onlyVisibleFields || false, fillNewPassword: options.fillNewPassword || false, cipher: options.cipher, + tabUrl: tab.url, + defaultUriMatch: defaultUriMatch, }); if (!fillScript || !fillScript.script || !fillScript.script.length) { return; } + if ( + fillScript.untrustedIframe && + options.allowUntrustedIframe != undefined && + !options.allowUntrustedIframe + ) { + this.logService.info("Auto-fill on page load was blocked due to an untrusted iframe."); + return; + } + // Add a small delay between operations fillScript.properties.delay_between_operations = 20; @@ -159,7 +183,18 @@ export default class AutofillService implements AutofillServiceInterface { } } - async doAutoFillOnTab(pageDetails: PageDetail[], tab: chrome.tabs.Tab, fromCommand: boolean) { + /** + * Autofills the specified tab with the next login item from the cache + * @param pageDetails The data scraped from the page + * @param tab The tab to be autofilled + * @param fromCommand Whether the autofill is triggered by a keyboard shortcut (`true`) or autofill on page load (`false`) + * @returns The TOTP code of the successfully autofilled login, if any + */ + async doAutoFillOnTab( + pageDetails: PageDetail[], + tab: chrome.tabs.Tab, + fromCommand: boolean + ): Promise { let cipher: CipherView; if (fromCommand) { cipher = await this.cipherService.getNextCipherForUrl(tab.url); @@ -188,6 +223,7 @@ export default class AutofillService implements AutofillServiceInterface { onlyEmptyFields: !fromCommand, onlyVisibleFields: !fromCommand, fillNewPassword: fromCommand, + allowUntrustedIframe: fromCommand, }); // Update last used index as autofill has succeed @@ -198,7 +234,13 @@ export default class AutofillService implements AutofillServiceInterface { return totpCode; } - async doAutoFillActiveTab(pageDetails: PageDetail[], fromCommand: boolean) { + /** + * Autofills the active tab with the next login item from the cache + * @param pageDetails The data scraped from the page + * @param fromCommand Whether the autofill is triggered by a keyboard shortcut (`true`) or autofill on page load (`false`) + * @returns The TOTP code of the successfully autofilled login, if any + */ + async doAutoFillActiveTab(pageDetails: PageDetail[], fromCommand: boolean): Promise { const tab = await this.getActiveTab(); if (!tab || !tab.url) { return; @@ -309,6 +351,10 @@ export default class AutofillService implements AutofillServiceInterface { fillScript.savedUrls = login?.uris?.filter((u) => u.match != UriMatchType.Never).map((u) => u.uri) ?? []; + const inIframe = pageDetails.url !== options.tabUrl; + fillScript.untrustedIframe = + inIframe && !this.iframeUrlMatches(pageDetails.url, options.cipher, options.defaultUriMatch); + if (!login.password || login.password === "") { // No password for this login. Maybe they just wanted to auto-fill some custom fields? fillScript = AutofillService.setFillScriptForFocus(filledFields, fillScript); @@ -742,6 +788,84 @@ export default class AutofillService implements AutofillServiceInterface { return fillScript; } + /** + * Determines whether to warn the user about filling an iframe + * @param pageUrl The url of the page/iframe, usually from AutofillPageDetails + * @param tabUrl The url of the tab, usually from the message sender (should not come from a content script because + * that is likely to be incorrect in the case of iframes) + * @param loginItem The cipher to be filled + * @returns `true` if the iframe is untrusted and the warning should be shown, `false` otherwise + */ + iframeUrlMatches(pageUrl: string, loginItem: CipherView, defaultUriMatch: UriMatchType): boolean { + // Check the pageUrl against cipher URIs using the configured match detection. + // If we are in this function at all, it is assumed that the tabUrl already matches a URL for `loginItem`, + // need to verify the pageUrl also matches one of the saved URIs using the match detection selected. + const uriMatched = loginItem.login.uris?.some((uri) => + this.uriMatches(uri, pageUrl, defaultUriMatch) + ); + + return uriMatched; + } + + // TODO should this be put in a common place (Utils maybe?) to be used both here and by CipherService? + private uriMatches(uri: LoginUriView, url: string, defaultUriMatch: UriMatchType): boolean { + const matchType = uri.match ?? defaultUriMatch; + + const matchDomains = [Utils.getDomain(url)]; + const equivalentDomains = this.settingsService.getEquivalentDomains(url); + if (equivalentDomains != null) { + matchDomains.push(...equivalentDomains); + } + + switch (matchType) { + case UriMatchType.Domain: + if (url != null && uri.domain != null && matchDomains.includes(uri.domain)) { + if (Utils.DomainMatchBlacklist.has(uri.domain)) { + const domainUrlHost = Utils.getHost(url); + if (!Utils.DomainMatchBlacklist.get(uri.domain).has(domainUrlHost)) { + return true; + } + } else { + return true; + } + } + break; + case UriMatchType.Host: { + const urlHost = Utils.getHost(url); + if (urlHost != null && urlHost === Utils.getHost(uri.uri)) { + return true; + } + break; + } + case UriMatchType.Exact: + if (url === uri.uri) { + return true; + } + break; + case UriMatchType.StartsWith: + if (url.startsWith(uri.uri)) { + return true; + } + break; + case UriMatchType.RegularExpression: + try { + const regex = new RegExp(uri.uri, "i"); + if (regex.test(url)) { + return true; + } + } catch (e) { + this.logService.error(e); + return false; + } + break; + case UriMatchType.Never: + default: + break; + } + + return false; + } + private fieldAttrsContain(field: AutofillField, containsVal: string) { if (!field) { return false; diff --git a/apps/browser/src/background/commands.background.ts b/apps/browser/src/background/commands.background.ts index 7e2c11e2e83..b53c809c357 100644 --- a/apps/browser/src/background/commands.background.ts +++ b/apps/browser/src/background/commands.background.ts @@ -1,8 +1,8 @@ -import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; +import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { BrowserApi } from "../browser/browserApi"; @@ -15,7 +15,7 @@ export default class CommandsBackground { constructor( private main: MainBackground, - private passwordGenerationService: PasswordGenerationService, + private passwordGenerationService: PasswordGenerationServiceAbstraction, private platformUtilsService: PlatformUtilsService, private vaultTimeoutService: VaultTimeoutService, private authService: AuthService diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 4707b6f2cb7..4edb02c00ed 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -2,26 +2,19 @@ import { AvatarUpdateService as AvatarUpdateServiceAbstraction } from "@bitwarde import { ApiService as ApiServiceAbstraction } from "@bitwarden/common/abstractions/api.service"; import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/abstractions/appId.service"; import { AuditService as AuditServiceAbstraction } from "@bitwarden/common/abstractions/audit.service"; -import { CollectionService as CollectionServiceAbstraction } from "@bitwarden/common/abstractions/collection.service"; import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/abstractions/crypto.service"; import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/abstractions/cryptoFunction.service"; import { EncryptService } from "@bitwarden/common/abstractions/encrypt.service"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service"; import { ExportService as ExportServiceAbstraction } from "@bitwarden/common/abstractions/export.service"; -import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/fileUpload.service"; +import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/file-upload/file-upload.service"; import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service"; import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service"; import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/abstractions/messaging.service"; import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service"; -import { InternalOrganizationService as InternalOrganizationServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; -import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "@bitwarden/common/abstractions/passwordGeneration.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/abstractions/platformUtils.service"; -import { PolicyApiServiceAbstraction } from "@bitwarden/common/abstractions/policy/policy-api.service.abstraction"; -import { InternalPolicyService as InternalPolicyServiceAbstraction } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; -import { ProviderService as ProviderServiceAbstraction } from "@bitwarden/common/abstractions/provider.service"; import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service"; -import { SendService as SendServiceAbstraction } from "@bitwarden/common/abstractions/send.service"; import { SettingsService as SettingsServiceAbstraction } from "@bitwarden/common/abstractions/settings.service"; import { AbstractMemoryStorageService, @@ -31,9 +24,16 @@ import { SystemService as SystemServiceAbstraction } from "@bitwarden/common/abs import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/abstractions/totp.service"; import { UserVerificationApiServiceAbstraction } from "@bitwarden/common/abstractions/userVerification/userVerification-api.service.abstraction"; import { UserVerificationService as UserVerificationServiceAbstraction } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction"; -import { UsernameGenerationService as UsernameGenerationServiceAbstraction } from "@bitwarden/common/abstractions/usernameGeneration.service"; import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service"; import { VaultTimeoutSettingsService as VaultTimeoutSettingsServiceAbstraction } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service"; +import { CollectionService as CollectionServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/collection.service"; +import { InternalOrganizationService as InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; +import { InternalPolicyService as InternalPolicyServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { ProviderService as ProviderServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider.service"; +import { CollectionService } from "@bitwarden/common/admin-console/services/collection.service"; +import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service"; +import { ProviderService } from "@bitwarden/common/admin-console/services/provider.service"; import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service"; import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/auth/abstractions/token.service"; @@ -50,7 +50,6 @@ import { AvatarUpdateService } from "@bitwarden/common/services/account/avatar-u import { ApiService } from "@bitwarden/common/services/api.service"; import { AppIdService } from "@bitwarden/common/services/appId.service"; import { AuditService } from "@bitwarden/common/services/audit.service"; -import { CollectionService } from "@bitwarden/common/services/collection.service"; import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service"; import { ContainerService } from "@bitwarden/common/services/container.service"; import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation"; @@ -58,27 +57,35 @@ import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/servi import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service"; import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; import { ExportService } from "@bitwarden/common/services/export.service"; -import { FileUploadService } from "@bitwarden/common/services/fileUpload.service"; +import { FileUploadService } from "@bitwarden/common/services/file-upload/file-upload.service"; import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service"; import { NotificationsService } from "@bitwarden/common/services/notifications.service"; -import { PasswordGenerationService } from "@bitwarden/common/services/passwordGeneration.service"; -import { PolicyApiService } from "@bitwarden/common/services/policy/policy-api.service"; -import { ProviderService } from "@bitwarden/common/services/provider.service"; import { SearchService } from "@bitwarden/common/services/search.service"; -import { SendService } from "@bitwarden/common/services/send.service"; import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service"; import { SystemService } from "@bitwarden/common/services/system.service"; import { TotpService } from "@bitwarden/common/services/totp.service"; -import { UsernameGenerationService } from "@bitwarden/common/services/usernameGeneration.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vaultTimeout/vaultTimeoutSettings.service"; import { WebCryptoFunctionService } from "@bitwarden/common/services/webCryptoFunction.service"; +import { + PasswordGenerationService, + PasswordGenerationServiceAbstraction, +} from "@bitwarden/common/tools/generator/password"; +import { + UsernameGenerationService, + UsernameGenerationServiceAbstraction, +} from "@bitwarden/common/tools/generator/username"; +import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service"; +import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; +import { InternalSendService as InternalSendServiceAbstraction } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CipherFileUploadService as CipherFileUploadServiceAbstraction } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { InternalFolderService as InternalFolderServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { SyncNotifierService as SyncNotifierServiceAbstraction } from "@bitwarden/common/vault/abstractions/sync/sync-notifier.service.abstraction"; import { SyncService as SyncServiceAbstraction } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CipherService } from "@bitwarden/common/vault/services/cipher.service"; +import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service"; import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service"; import { SyncNotifierService } from "@bitwarden/common/vault/services/sync/sync-notifier.service"; import { SyncService } from "@bitwarden/common/vault/services/sync/sync.service"; @@ -88,13 +95,14 @@ import { Fido2UserInterfaceService as Fido2UserInterfaceServiceAbstraction } fro import { Fido2AuthenticatorService } from "@bitwarden/common/webauthn/services/fido2-authenticator.service"; import { Fido2ClientService } from "@bitwarden/common/webauthn/services/fido2-client.service"; +import { BrowserOrganizationService } from "../admin-console/services/browser-organization.service"; +import { BrowserPolicyService } from "../admin-console/services/browser-policy.service"; import ContextMenusBackground from "../autofill/background/context-menus.background"; import NotificationBackground from "../autofill/background/notification.background"; import TabsBackground from "../autofill/background/tabs.background"; import { CipherContextMenuHandler } from "../autofill/browser/cipher-context-menu-handler"; import { ContextMenuClickedHandler } from "../autofill/browser/context-menu-clicked-handler"; import { MainContextMenuHandler } from "../autofill/browser/main-context-menu-handler"; -import { AutofillTabCommand } from "../autofill/commands/autofill-tab-command"; import { AutofillService as AutofillServiceAbstraction } from "../autofill/services/abstractions/autofill.service"; import AutofillService from "../autofill/services/autofill.service"; import { BrowserApi } from "../browser/browserApi"; @@ -106,8 +114,7 @@ import { PopupUtilsService } from "../popup/services/popup-utils.service"; import { BrowserStateService as StateServiceAbstraction } from "../services/abstractions/browser-state.service"; import { BrowserEnvironmentService } from "../services/browser-environment.service"; import { BrowserI18nService } from "../services/browser-i18n.service"; -import { BrowserOrganizationService } from "../services/browser-organization.service"; -import { BrowserPolicyService } from "../services/browser-policy.service"; +import { BrowserSendService } from "../services/browser-send.service"; import { BrowserSettingsService } from "../services/browser-settings.service"; import { BrowserStateService } from "../services/browser-state.service"; import { BrowserCryptoService } from "../services/browserCrypto.service"; @@ -164,9 +171,9 @@ export default class MainBackground { eventCollectionService: EventCollectionServiceAbstraction; eventUploadService: EventUploadServiceAbstraction; policyService: InternalPolicyServiceAbstraction; - popupUtilsService: PopupUtilsService; - sendService: SendServiceAbstraction; + sendService: InternalSendServiceAbstraction; fileUploadService: FileUploadServiceAbstraction; + cipherFileUploadService: CipherFileUploadServiceAbstraction; organizationService: InternalOrganizationServiceAbstraction; providerService: ProviderServiceAbstraction; keyConnectorService: KeyConnectorServiceAbstraction; @@ -177,6 +184,7 @@ export default class MainBackground { encryptService: EncryptService; folderApiService: FolderApiServiceAbstraction; policyApiService: PolicyApiServiceAbstraction; + sendApiService: SendApiServiceAbstraction; userVerificationApiService: UserVerificationApiServiceAbstraction; syncNotifierService: SyncNotifierServiceAbstraction; fido2UserInterfaceService: Fido2UserInterfaceServiceAbstraction; @@ -185,6 +193,7 @@ export default class MainBackground { avatarUpdateService: AvatarUpdateServiceAbstraction; mainContextMenuHandler: MainContextMenuHandler; cipherContextMenuHandler: CipherContextMenuHandler; + popupUtilsService: PopupUtilsService; // Passed to the popup for Safari to workaround issues with theming, downloading, etc. backgroundWindow = window; @@ -300,17 +309,21 @@ export default class MainBackground { (expired: boolean) => this.logout(expired) ); this.settingsService = new BrowserSettingsService(this.stateService); - this.fileUploadService = new FileUploadService(this.logService, this.apiService); + this.fileUploadService = new FileUploadService(this.logService); + this.cipherFileUploadService = new CipherFileUploadService( + this.apiService, + this.fileUploadService + ); this.cipherService = new CipherService( this.cryptoService, this.settingsService, this.apiService, - this.fileUploadService, this.i18nService, () => this.searchService, this.logService, this.stateService, - this.encryptService + this.encryptService, + this.cipherFileUploadService ); this.folderService = new BrowserFolderService( this.cryptoService, @@ -325,14 +338,6 @@ export default class MainBackground { this.stateService ); this.searchService = new SearchService(this.cipherService, this.logService, this.i18nService); - this.sendService = new SendService( - this.cryptoService, - this.apiService, - this.fileUploadService, - this.i18nService, - this.cryptoFunctionService, - this.stateService - ); this.syncNotifierService = new SyncNotifierService(); this.organizationService = new BrowserOrganizationService(this.stateService); this.policyService = new BrowserPolicyService(this.stateService, this.organizationService); @@ -368,7 +373,7 @@ export default class MainBackground { // AuthService should send the messages to the background not popup. send = (subscriber: string, arg: any = {}) => { const message = Object.assign({}, { command: subscriber }, arg); - that.runtimeBackground.processMessage(message, that); + that.runtimeBackground.processMessage(message, that as any); }; })(); this.authService = new AuthService( @@ -409,7 +414,18 @@ export default class MainBackground { lockedCallback, logoutCallback ); - + this.containerService = new ContainerService(this.cryptoService, this.encryptService); + this.sendService = new BrowserSendService( + this.cryptoService, + this.i18nService, + this.cryptoFunctionService, + this.stateService + ); + this.sendApiService = new SendApiService( + this.apiService, + this.fileUploadService, + this.sendService + ); this.providerService = new ProviderService(this.stateService); this.syncService = new SyncService( this.apiService, @@ -427,6 +443,7 @@ export default class MainBackground { this.providerService, this.folderApiService, this.organizationService, + this.sendApiService, logoutCallback ); this.eventUploadService = new EventUploadService( @@ -451,16 +468,17 @@ export default class MainBackground { this.stateService, this.totpService, this.eventCollectionService, - this.logService + this.logService, + this.settingsService ); - this.containerService = new ContainerService(this.cryptoService, this.encryptService); this.auditService = new AuditService(this.cryptoFunctionService, this.apiService); this.exportService = new ExportService( this.folderService, this.cipherService, this.apiService, this.cryptoService, - this.cryptoFunctionService + this.cryptoFunctionService, + this.stateService ); this.notificationsService = new NotificationsService( this.syncService, @@ -473,7 +491,6 @@ export default class MainBackground { this.authService, this.messagingService ); - this.popupUtilsService = new PopupUtilsService(isPrivateMode); this.userVerificationApiService = new UserVerificationApiService(this.apiService); @@ -483,6 +500,7 @@ export default class MainBackground { this.userVerificationApiService ); + this.popupUtilsService = new PopupUtilsService(this.isPrivateMode); this.fido2UserInterfaceService = new BrowserFido2UserInterfaceService(this.popupUtilsService); this.fido2AuthenticatorService = new Fido2AuthenticatorService( this.cipherService, @@ -559,9 +577,20 @@ export default class MainBackground { this.platformUtilsService.copyToClipboard(password, { window: window }); this.passwordGenerationService.addHistory(password); }, + async (tab, cipher) => { + this.loginToAutoFill = cipher; + if (tab == null) { + return; + } + + BrowserApi.tabSendMessage(tab, { + command: "collectPageDetails", + tab: tab, + sender: "contextMenu", + }); + }, this.authService, this.cipherService, - new AutofillTabCommand(this.autofillService), this.totpService, this.eventCollectionService ); diff --git a/apps/browser/src/background/models/addChangePasswordQueueMessage.ts b/apps/browser/src/background/models/addChangePasswordQueueMessage.ts index 51a745643d2..16491032e9b 100644 --- a/apps/browser/src/background/models/addChangePasswordQueueMessage.ts +++ b/apps/browser/src/background/models/addChangePasswordQueueMessage.ts @@ -1,6 +1,8 @@ import NotificationQueueMessage from "./notificationQueueMessage"; +import { NotificationQueueMessageType } from "./notificationQueueMessageType"; export default class AddChangePasswordQueueMessage extends NotificationQueueMessage { + type: NotificationQueueMessageType.ChangePassword; cipherId: string; newPassword: string; } diff --git a/apps/browser/src/background/models/addLoginQueueMessage.ts b/apps/browser/src/background/models/addLoginQueueMessage.ts index ba13071262e..7409100902a 100644 --- a/apps/browser/src/background/models/addLoginQueueMessage.ts +++ b/apps/browser/src/background/models/addLoginQueueMessage.ts @@ -1,7 +1,33 @@ +import { Utils } from "@bitwarden/common/misc/utils"; +import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; +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 NotificationQueueMessage from "./notificationQueueMessage"; +import { NotificationQueueMessageType } from "./notificationQueueMessageType"; export default class AddLoginQueueMessage extends NotificationQueueMessage { + type: NotificationQueueMessageType.AddLogin; username: string; password: string; uri: string; + + static toCipherView(message: AddLoginQueueMessage, folderId?: string): CipherView { + const uriView = new LoginUriView(); + uriView.uri = message.uri; + + const loginView = new LoginView(); + loginView.uris = [uriView]; + loginView.username = message.username; + loginView.password = message.password; + + const cipherView = new CipherView(); + cipherView.name = (Utils.getHostname(message.uri) || message.domain).replace(/^www\./, ""); + cipherView.folderId = folderId; + cipherView.type = CipherType.Login; + cipherView.login = loginView; + + return cipherView; + } } diff --git a/apps/browser/src/background/runtime.background.ts b/apps/browser/src/background/runtime.background.ts index 0ad9d9d2b5e..e1d0dd9e57b 100644 --- a/apps/browser/src/background/runtime.background.ts +++ b/apps/browser/src/background/runtime.background.ts @@ -70,19 +70,15 @@ export default class RuntimeBackground { } } - async processMessage(msg: any, sender: any): Promise { + async processMessage(msg: any, sender: chrome.runtime.MessageSender) { switch (msg.command) { case "loggedIn": case "unlocked": { let item: LockedVaultPendingNotificationsItem; if (this.lockedVaultPendingNotifications?.length > 0) { - await BrowserApi.closeLoginTab(); - item = this.lockedVaultPendingNotifications.pop(); - if (item.commandToRetry.sender?.tab?.id) { - await BrowserApi.focusSpecifiedTab(item.commandToRetry.sender.tab.id); - } + BrowserApi.closeBitwardenExtensionTab(); } await this.main.refreshBadge(); @@ -118,7 +114,21 @@ export default class RuntimeBackground { await this.main.openPopup(); break; case "promptForLogin": - await BrowserApi.createNewTab("popup/index.html?uilocation=popout", true, true); + BrowserApi.openBitwardenExtensionTab("popup/index.html", true, sender.tab); + break; + case "openAddEditCipher": { + const addEditCipherUrl = + msg.data?.cipherId == null + ? "popup/index.html#/edit-cipher" + : "popup/index.html#/edit-cipher?cipherId=" + msg.data.cipherId; + + BrowserApi.openBitwardenExtensionTab(addEditCipherUrl, true, sender.tab); + break; + } + case "closeTab": + setTimeout(() => { + BrowserApi.closeBitwardenExtensionTab(); + }, msg.delay ?? 0); break; case "showDialogResolve": this.platformUtilsService.resolveDialogPromise(msg.dialogId, msg.confirmed); @@ -197,11 +207,7 @@ export default class RuntimeBackground { const params = `webAuthnResponse=${encodeURIComponent(msg.data)};` + `remember=${encodeURIComponent(msg.remember)}`; - BrowserApi.createNewTab( - `popup/index.html?uilocation=popout#/2fa;${params}`, - undefined, - false - ); + BrowserApi.openBitwardenExtensionTab(`popup/index.html#/2fa;${params}`, false); break; } case "reloadPopup": diff --git a/apps/browser/src/background/service_factories/cipher-file-upload-service.factory.ts b/apps/browser/src/background/service_factories/cipher-file-upload-service.factory.ts new file mode 100644 index 00000000000..ef2be8fa761 --- /dev/null +++ b/apps/browser/src/background/service_factories/cipher-file-upload-service.factory.ts @@ -0,0 +1,31 @@ +import { CipherFileUploadService as CipherFileUploadServiceAbstraction } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service"; +import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service"; + +import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory"; +import { FactoryOptions, CachedServices, factory } from "./factory-options"; +import { + fileUploadServiceFactory, + FileUploadServiceInitOptions, +} from "./file-upload-service.factory"; + +type CipherFileUploadServiceFactoyOptions = FactoryOptions; + +export type CipherFileUploadServiceInitOptions = CipherFileUploadServiceFactoyOptions & + ApiServiceInitOptions & + FileUploadServiceInitOptions; + +export function cipherFileUploadServiceFactory( + cache: { cipherFileUploadService?: CipherFileUploadServiceAbstraction } & CachedServices, + opts: CipherFileUploadServiceInitOptions +): Promise { + return factory( + cache, + "cipherFileUploadService", + opts, + async () => + new CipherFileUploadService( + await apiServiceFactory(cache, opts), + await fileUploadServiceFactory(cache, opts) + ) + ); +} diff --git a/apps/browser/src/background/service_factories/cipher-file-upload.service.factory.ts b/apps/browser/src/background/service_factories/cipher-file-upload.service.factory.ts new file mode 100644 index 00000000000..ef2be8fa761 --- /dev/null +++ b/apps/browser/src/background/service_factories/cipher-file-upload.service.factory.ts @@ -0,0 +1,31 @@ +import { CipherFileUploadService as CipherFileUploadServiceAbstraction } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service"; +import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service"; + +import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory"; +import { FactoryOptions, CachedServices, factory } from "./factory-options"; +import { + fileUploadServiceFactory, + FileUploadServiceInitOptions, +} from "./file-upload-service.factory"; + +type CipherFileUploadServiceFactoyOptions = FactoryOptions; + +export type CipherFileUploadServiceInitOptions = CipherFileUploadServiceFactoyOptions & + ApiServiceInitOptions & + FileUploadServiceInitOptions; + +export function cipherFileUploadServiceFactory( + cache: { cipherFileUploadService?: CipherFileUploadServiceAbstraction } & CachedServices, + opts: CipherFileUploadServiceInitOptions +): Promise { + return factory( + cache, + "cipherFileUploadService", + opts, + async () => + new CipherFileUploadService( + await apiServiceFactory(cache, opts), + await fileUploadServiceFactory(cache, opts) + ) + ); +} diff --git a/apps/browser/src/background/service_factories/event-collection-service.factory.ts b/apps/browser/src/background/service_factories/event-collection-service.factory.ts index 4266db43ece..4008091c222 100644 --- a/apps/browser/src/background/service_factories/event-collection-service.factory.ts +++ b/apps/browser/src/background/service_factories/event-collection-service.factory.ts @@ -1,6 +1,10 @@ import { EventCollectionService as AbstractEventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service"; +import { + organizationServiceFactory, + OrganizationServiceInitOptions, +} from "../../admin-console/background/service-factories/organization-service.factory"; import { cipherServiceFactory, CipherServiceInitOptions, @@ -11,10 +15,6 @@ import { EventUploadServiceInitOptions, } from "./event-upload-service.factory"; import { FactoryOptions, CachedServices, factory } from "./factory-options"; -import { - organizationServiceFactory, - OrganizationServiceInitOptions, -} from "./organization-service.factory"; import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory"; type EventCollectionServiceOptions = FactoryOptions; diff --git a/apps/browser/src/background/service_factories/file-upload-service.factory.ts b/apps/browser/src/background/service_factories/file-upload-service.factory.ts index 0aa04126d92..5ead09f929c 100644 --- a/apps/browser/src/background/service_factories/file-upload-service.factory.ts +++ b/apps/browser/src/background/service_factories/file-upload-service.factory.ts @@ -1,28 +1,21 @@ -import { FileUploadService as AbstractFileUploadService } from "@bitwarden/common/abstractions/fileUpload.service"; -import { FileUploadService } from "@bitwarden/common/services/fileUpload.service"; +import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/abstractions/file-upload/file-upload.service"; +import { FileUploadService } from "@bitwarden/common/services/file-upload/file-upload.service"; -import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory"; -import { FactoryOptions, CachedServices, factory } from "./factory-options"; +import { CachedServices, factory, FactoryOptions } from "./factory-options"; import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory"; -type FileUploadServiceFactoyOptions = FactoryOptions; +type FileUploadServiceFactoryOptions = FactoryOptions; -export type FileUploadServiceInitOptions = FileUploadServiceFactoyOptions & - LogServiceInitOptions & - ApiServiceInitOptions; +export type FileUploadServiceInitOptions = FileUploadServiceFactoryOptions & LogServiceInitOptions; export function fileUploadServiceFactory( - cache: { fileUploadService?: AbstractFileUploadService } & CachedServices, + cache: { fileUploadService?: FileUploadServiceAbstraction } & CachedServices, opts: FileUploadServiceInitOptions -): Promise { +): Promise { return factory( cache, "fileUploadService", opts, - async () => - new FileUploadService( - await logServiceFactory(cache, opts), - await apiServiceFactory(cache, opts) - ) + async () => new FileUploadService(await logServiceFactory(cache, opts)) ); } diff --git a/apps/browser/src/background/service_factories/password-generation-service.factory.ts b/apps/browser/src/background/service_factories/password-generation-service.factory.ts index d69f22401c8..cffbf376d4f 100644 --- a/apps/browser/src/background/service_factories/password-generation-service.factory.ts +++ b/apps/browser/src/background/service_factories/password-generation-service.factory.ts @@ -1,9 +1,15 @@ -import { PasswordGenerationService as AbstractPasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; -import { PasswordGenerationService } from "@bitwarden/common/services/passwordGeneration.service"; +import { + PasswordGenerationService, + PasswordGenerationServiceAbstraction, +} from "@bitwarden/common/tools/generator/password"; + +import { + policyServiceFactory, + PolicyServiceInitOptions, +} from "../../admin-console/background/service-factories/policy-service.factory"; import { cryptoServiceFactory, CryptoServiceInitOptions } from "./crypto-service.factory"; import { CachedServices, factory, FactoryOptions } from "./factory-options"; -import { policyServiceFactory, PolicyServiceInitOptions } from "./policy-service.factory"; import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory"; type PasswordGenerationServiceFactoryOptions = FactoryOptions; @@ -14,9 +20,9 @@ export type PasswordGenerationServiceInitOptions = PasswordGenerationServiceFact StateServiceInitOptions; export function passwordGenerationServiceFactory( - cache: { passwordGenerationService?: AbstractPasswordGenerationService } & CachedServices, + cache: { passwordGenerationService?: PasswordGenerationServiceAbstraction } & CachedServices, opts: PasswordGenerationServiceInitOptions -): Promise { +): Promise { return factory( cache, "passwordGenerationService", diff --git a/apps/browser/src/background/service_factories/send-service.factory.ts b/apps/browser/src/background/service_factories/send-service.factory.ts new file mode 100644 index 00000000000..2da4d88a1d8 --- /dev/null +++ b/apps/browser/src/background/service_factories/send-service.factory.ts @@ -0,0 +1,34 @@ +import { InternalSendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; + +import { BrowserSendService } from "../../services/browser-send.service"; + +import { cryptoFunctionServiceFactory } from "./crypto-function-service.factory"; +import { cryptoServiceFactory, CryptoServiceInitOptions } from "./crypto-service.factory"; +import { FactoryOptions, CachedServices, factory } from "./factory-options"; +import { i18nServiceFactory, I18nServiceInitOptions } from "./i18n-service.factory"; +import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory"; + +type SendServiceFactoryOptions = FactoryOptions; + +export type SendServiceInitOptions = SendServiceFactoryOptions & + CryptoServiceInitOptions & + I18nServiceInitOptions & + StateServiceInitOptions; + +export function sendServiceFactory( + cache: { sendService?: InternalSendService } & CachedServices, + opts: SendServiceInitOptions +): Promise { + return factory( + cache, + "sendService", + opts, + async () => + new BrowserSendService( + await cryptoServiceFactory(cache, opts), + await i18nServiceFactory(cache, opts), + await cryptoFunctionServiceFactory(cache, opts), + await stateServiceFactory(cache, opts) + ) + ); +} diff --git a/apps/browser/src/background/service_factories/vault-timeout-service.factory.ts b/apps/browser/src/background/service_factories/vault-timeout-service.factory.ts index a1529d9e948..b69d8d1d65f 100644 --- a/apps/browser/src/background/service_factories/vault-timeout-service.factory.ts +++ b/apps/browser/src/background/service_factories/vault-timeout-service.factory.ts @@ -1,5 +1,9 @@ import { VaultTimeoutService as AbstractVaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service"; +import { + collectionServiceFactory, + CollectionServiceInitOptions, +} from "../../admin-console/background/service-factories/collection-service.factory"; import { authServiceFactory, AuthServiceInitOptions, @@ -18,10 +22,6 @@ import { FolderServiceInitOptions, } from "../../vault/background/service_factories/folder-service.factory"; -import { - collectionServiceFactory, - CollectionServiceInitOptions, -} from "./collection-service.factory"; import { cryptoServiceFactory, CryptoServiceInitOptions } from "./crypto-service.factory"; import { CachedServices, factory, FactoryOptions } from "./factory-options"; import { messagingServiceFactory, MessagingServiceInitOptions } from "./messaging-service.factory"; diff --git a/apps/browser/src/background/service_factories/vault-timeout-settings-service.factory.ts b/apps/browser/src/background/service_factories/vault-timeout-settings-service.factory.ts index aa9f526f794..d349771f428 100644 --- a/apps/browser/src/background/service_factories/vault-timeout-settings-service.factory.ts +++ b/apps/browser/src/background/service_factories/vault-timeout-settings-service.factory.ts @@ -1,6 +1,10 @@ import { VaultTimeoutSettingsService as AbstractVaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vaultTimeout/vaultTimeoutSettings.service"; +import { + policyServiceFactory, + PolicyServiceInitOptions, +} from "../../admin-console/background/service-factories/policy-service.factory"; import { tokenServiceFactory, TokenServiceInitOptions, @@ -8,7 +12,6 @@ import { import { cryptoServiceFactory, CryptoServiceInitOptions } from "./crypto-service.factory"; import { CachedServices, factory, FactoryOptions } from "./factory-options"; -import { policyServiceFactory, PolicyServiceInitOptions } from "./policy-service.factory"; import { stateServiceFactory as stateServiceFactory, StateServiceInitOptions, diff --git a/apps/browser/src/browser/browserApi.ts b/apps/browser/src/browser/browserApi.ts index 74f5de6e35d..4d8ccf3176f 100644 --- a/apps/browser/src/browser/browserApi.ts +++ b/apps/browser/src/browser/browserApi.ts @@ -117,6 +117,10 @@ export class BrowserApi { return chrome.extension.getBackgroundPage(); } + static isBackgroundPage(window: Window & typeof globalThis): boolean { + return window === chrome.extension.getBackgroundPage(); + } + static getApplicationVersion(): string { return chrome.runtime.getManifest().version; } @@ -125,8 +129,44 @@ export class BrowserApi { return Promise.resolve(chrome.extension.getViews({ type: "popup" }).length > 0); } - static createNewTab(url: string, extensionPage = false, active = true) { - chrome.tabs.create({ url: url, active: active }); + static createNewTab(url: string, active = true, openerTab?: chrome.tabs.Tab) { + chrome.tabs.create({ url: url, active: active, openerTabId: openerTab?.id }); + } + + static openBitwardenExtensionTab( + relativeUrl: string, + active = true, + openerTab?: chrome.tabs.Tab + ) { + if (relativeUrl.includes("uilocation=tab")) { + this.createNewTab(relativeUrl, active, openerTab); + return; + } + + const fullUrl = chrome.extension.getURL(relativeUrl); + const parsedUrl = new URL(fullUrl); + parsedUrl.searchParams.set("uilocation", "tab"); + this.createNewTab(parsedUrl.toString(), active, openerTab); + } + + static async closeBitwardenExtensionTab() { + const tabs = await BrowserApi.tabsQuery({ + active: true, + title: "Bitwarden", + windowType: "normal", + currentWindow: true, + }); + + if (tabs.length === 0) { + return; + } + + const tabToClose = tabs[tabs.length - 1]; + chrome.tabs.remove(tabToClose.id); + + if (tabToClose.openerTabId) { + this.focusTab(tabToClose.openerTabId); + } } static createNewWindow( @@ -161,23 +201,7 @@ export class BrowserApi { return chrome.runtime.sendMessage(message); } - static async closeLoginTab() { - const tabs = await BrowserApi.tabsQuery({ - active: true, - title: "Bitwarden", - windowType: "normal", - currentWindow: true, - }); - - if (tabs.length === 0) { - return; - } - - const tabToClose = tabs[tabs.length - 1].id; - chrome.tabs.remove(tabToClose); - } - - static async focusSpecifiedTab(tabId: number) { + static async focusTab(tabId: number) { chrome.tabs.update(tabId, { active: true, highlighted: true }); } diff --git a/apps/browser/src/browser/webauthn-utils.ts b/apps/browser/src/browser/webauthn-utils.ts index 80b301a799f..16196712762 100644 --- a/apps/browser/src/browser/webauthn-utils.ts +++ b/apps/browser/src/browser/webauthn-utils.ts @@ -122,6 +122,7 @@ export class WebauthnUtils { userHandle: Fido2Utils.stringToBuffer(result.userHandle), } as AuthenticatorAssertionResponse, getClientExtensionResults: () => ({}), + authenticatorAttachment: "hybrid", }; } } diff --git a/apps/browser/src/decorators/session-sync-observable/session-sync.decorator.spec.ts b/apps/browser/src/decorators/session-sync-observable/session-sync.decorator.spec.ts index c6d46b28fd1..7a6e7266081 100644 --- a/apps/browser/src/decorators/session-sync-observable/session-sync.decorator.spec.ts +++ b/apps/browser/src/decorators/session-sync-observable/session-sync.decorator.spec.ts @@ -4,11 +4,10 @@ import { sessionSync } from "./session-sync.decorator"; describe("sessionSync decorator", () => { const initializer = (s: string) => "test"; - const ctor = String; class TestClass { - @sessionSync({ ctor: ctor, initializer: initializer }) + @sessionSync({ initializer: initializer }) private testProperty = new BehaviorSubject(""); - @sessionSync({ ctor: ctor, initializer: initializer, initializeAs: "array" }) + @sessionSync({ initializer: initializer, initializeAs: "array" }) private secondTestProperty = new BehaviorSubject(""); complete() { @@ -23,13 +22,11 @@ describe("sessionSync decorator", () => { expect.objectContaining({ propertyKey: "testProperty", sessionKey: "testProperty_0", - ctor: ctor, initializer: initializer, }), expect.objectContaining({ propertyKey: "secondTestProperty", sessionKey: "secondTestProperty_1", - ctor: ctor, initializer: initializer, initializeAs: "array", }), @@ -38,7 +35,7 @@ describe("sessionSync decorator", () => { }); class TestClass2 { - @sessionSync({ ctor: ctor, initializer: initializer }) + @sessionSync({ initializer: initializer }) private testProperty = new BehaviorSubject(""); complete() { @@ -52,7 +49,6 @@ describe("sessionSync decorator", () => { expect.objectContaining({ propertyKey: "testProperty", sessionKey: "testProperty_2", - ctor: ctor, initializer: initializer, }), ]); diff --git a/apps/browser/src/decorators/session-sync-observable/session-sync.decorator.ts b/apps/browser/src/decorators/session-sync-observable/session-sync.decorator.ts index 6a6b3d33fa1..e439cea45a4 100644 --- a/apps/browser/src/decorators/session-sync-observable/session-sync.decorator.ts +++ b/apps/browser/src/decorators/session-sync-observable/session-sync.decorator.ts @@ -4,7 +4,6 @@ import { SessionStorable } from "./session-storable"; import { InitializeOptions } from "./sync-item-metadata"; class BuildOptions> { - ctor?: new () => T; initializer?: (keyValuePair: TJson) => T; initializeAs?: InitializeOptions; } @@ -48,7 +47,6 @@ export function sessionSync(buildOptions: BuildOptions) { p.__syncedItemMetadata.push({ propertyKey, sessionKey: `${propertyKey}_${index++}`, - ctor: buildOptions.ctor, initializer: buildOptions.initializer, initializeAs: buildOptions.initializeAs ?? "object", }); diff --git a/apps/browser/src/decorators/session-sync-observable/session-syncer.spec.ts b/apps/browser/src/decorators/session-sync-observable/session-syncer.spec.ts index 2de87b551d2..63312376293 100644 --- a/apps/browser/src/decorators/session-sync-observable/session-syncer.spec.ts +++ b/apps/browser/src/decorators/session-sync-observable/session-syncer.spec.ts @@ -53,8 +53,8 @@ describe("session syncer", () => { new SessionSyncer(behaviorSubject, storageService, { propertyKey, sessionKey, - ctor: String, initializeAs: "object", + initializer: () => null, }) ).toBeDefined(); expect( @@ -72,8 +72,9 @@ describe("session syncer", () => { propertyKey, sessionKey, initializeAs: "object", + initializer: null, }); - }).toThrowError("ctor or initializer must be provided"); + }).toThrowError("initializer must be provided"); }); }); @@ -106,7 +107,7 @@ describe("session syncer", () => { it("should grab an initial value from storage if it exists", async () => { storageService.has.mockResolvedValue(true); //Block a call to update - const updateSpy = jest.spyOn(sut as any, "update").mockImplementation(); + const updateSpy = jest.spyOn(sut as any, "updateFromMemory").mockImplementation(); sut.init(); await awaitAsync(); @@ -128,20 +129,15 @@ describe("session syncer", () => { describe("a value is emitted on the observable", () => { let sendMessageSpy: jest.SpyInstance; + const value = "test"; + const serializedValue = JSON.stringify(value); beforeEach(() => { sendMessageSpy = jest.spyOn(BrowserApi, "sendMessage"); sut.init(); - behaviorSubject.next("test"); - }); - - it("should update the session memory", async () => { - // await finishing of fire-and-forget operation - await new Promise((resolve) => setTimeout(resolve, 100)); - expect(storageService.save).toHaveBeenCalledTimes(1); - expect(storageService.save).toHaveBeenCalledWith(sessionKey, "test"); + behaviorSubject.next(value); }); it("should update sessionSyncers in other contexts", async () => { @@ -149,7 +145,10 @@ describe("session syncer", () => { await new Promise((resolve) => setTimeout(resolve, 100)); expect(sendMessageSpy).toHaveBeenCalledTimes(1); - expect(sendMessageSpy).toHaveBeenCalledWith(`${sessionKey}_update`, { id: sut.id }); + expect(sendMessageSpy).toHaveBeenCalledWith(`${sessionKey}_update`, { + id: sut.id, + serializedValue, + }); }); }); @@ -185,26 +184,104 @@ describe("session syncer", () => { it("should update from message on emit from another instance", async () => { const builder = jest.fn(); jest.spyOn(SyncedItemMetadata, "builder").mockReturnValue(builder); - storageService.getBypassCache.mockResolvedValue("test"); + const value = "test"; + const serializedValue = JSON.stringify(value); + builder.mockReturnValue(value); // Expect no circular messaging await awaitAsync(); expect(sendMessageSpy).toHaveBeenCalledTimes(0); - await sut.updateFromMessage({ command: `${sessionKey}_update`, id: "different_id" }); + await sut.updateFromMessage({ + command: `${sessionKey}_update`, + id: "different_id", + serializedValue, + }); await awaitAsync(); - expect(storageService.getBypassCache).toHaveBeenCalledTimes(1); - expect(storageService.getBypassCache).toHaveBeenCalledWith(sessionKey, { - deserializer: builder, - }); + expect(storageService.getBypassCache).toHaveBeenCalledTimes(0); expect(nextSpy).toHaveBeenCalledTimes(1); - expect(nextSpy).toHaveBeenCalledWith("test"); - expect(behaviorSubject.value).toBe("test"); + expect(nextSpy).toHaveBeenCalledWith(value); + expect(behaviorSubject.value).toBe(value); // Expect no circular messaging expect(sendMessageSpy).toHaveBeenCalledTimes(0); }); }); + + describe("memory storage", () => { + const value = "test"; + const serializedValue = JSON.stringify(value); + let saveSpy: jest.SpyInstance; + const builder = jest.fn().mockReturnValue(value); + const manifestVersionSpy = jest.spyOn(BrowserApi, "manifestVersion", "get"); + const isBackgroundPageSpy = jest.spyOn(BrowserApi, "isBackgroundPage"); + + beforeEach(async () => { + jest.spyOn(SyncedItemMetadata, "builder").mockReturnValue(builder); + saveSpy = jest.spyOn(storageService, "save"); + + sut.init(); + await awaitAsync(); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it("should always store on observed next for manifest version 3", async () => { + manifestVersionSpy.mockReturnValue(3); + isBackgroundPageSpy.mockReturnValueOnce(true).mockReturnValueOnce(false); + behaviorSubject.next(value); + await awaitAsync(); + behaviorSubject.next(value); + await awaitAsync(); + + expect(saveSpy).toHaveBeenCalledTimes(2); + }); + + it("should not store on message receive for manifest version 3", async () => { + manifestVersionSpy.mockReturnValue(3); + isBackgroundPageSpy.mockReturnValueOnce(true).mockReturnValueOnce(false); + await sut.updateFromMessage({ + command: `${sessionKey}_update`, + id: "different_id", + serializedValue, + }); + await awaitAsync(); + + expect(saveSpy).toHaveBeenCalledTimes(0); + }); + + it("should store on message receive for manifest version 2 for background page only", async () => { + manifestVersionSpy.mockReturnValue(2); + isBackgroundPageSpy.mockReturnValueOnce(true).mockReturnValueOnce(false); + await sut.updateFromMessage({ + command: `${sessionKey}_update`, + id: "different_id", + serializedValue, + }); + await awaitAsync(); + await sut.updateFromMessage({ + command: `${sessionKey}_update`, + id: "different_id", + serializedValue, + }); + await awaitAsync(); + + expect(saveSpy).toHaveBeenCalledTimes(1); + }); + + it("should store on observed next for manifest version 2 for background page only", async () => { + manifestVersionSpy.mockReturnValue(2); + isBackgroundPageSpy.mockReturnValueOnce(true).mockReturnValueOnce(false); + behaviorSubject.next(value); + await awaitAsync(); + behaviorSubject.next(value); + await awaitAsync(); + + expect(saveSpy).toHaveBeenCalledTimes(1); + }); + }); }); diff --git a/apps/browser/src/decorators/session-sync-observable/session-syncer.ts b/apps/browser/src/decorators/session-sync-observable/session-syncer.ts index 536e8a4871d..8751a12d1df 100644 --- a/apps/browser/src/decorators/session-sync-observable/session-syncer.ts +++ b/apps/browser/src/decorators/session-sync-observable/session-syncer.ts @@ -23,8 +23,8 @@ export class SessionSyncer { throw new Error("subject must inherit from Subject"); } - if (metaData.ctor == null && metaData.initializer == null) { - throw new Error("ctor or initializer must be provided"); + if (metaData.initializer == null) { + throw new Error("initializer must be provided"); } } @@ -45,7 +45,7 @@ export class SessionSyncer { // must be synchronous const hasInSessionMemory = await this.memoryStorageService.has(this.metaData.sessionKey); if (hasInSessionMemory) { - await this.update(); + await this.updateFromMemory(); } this.listenForUpdates(); @@ -83,21 +83,31 @@ export class SessionSyncer { if (message.command != this.updateMessageCommand || message.id === this.id) { return; } - this.update(); + await this.update(message.serializedValue); } - async update() { + async updateFromMemory() { + const value = await this.memoryStorageService.getBypassCache(this.metaData.sessionKey); + await this.update(value); + } + + async update(serializedValue: any) { + const unBuiltValue = JSON.parse(serializedValue); + if (BrowserApi.manifestVersion !== 3 && BrowserApi.isBackgroundPage(self)) { + await this.memoryStorageService.save(this.metaData.sessionKey, serializedValue); + } const builder = SyncedItemMetadata.builder(this.metaData); - const value = await this.memoryStorageService.getBypassCache(this.metaData.sessionKey, { - deserializer: builder, - }); + const value = builder(unBuiltValue); this.ignoreNUpdates = 1; this.subject.next(value); } private async updateSession(value: any) { - await this.memoryStorageService.save(this.metaData.sessionKey, value); - await BrowserApi.sendMessage(this.updateMessageCommand, { id: this.id }); + const serializedValue = JSON.stringify(value); + if (BrowserApi.manifestVersion === 3 || BrowserApi.isBackgroundPage(self)) { + await this.memoryStorageService.save(this.metaData.sessionKey, serializedValue); + } + await BrowserApi.sendMessage(this.updateMessageCommand, { id: this.id, serializedValue }); } private get updateMessageCommand() { diff --git a/apps/browser/src/decorators/session-sync-observable/sync-item-metadata.ts b/apps/browser/src/decorators/session-sync-observable/sync-item-metadata.ts index facfda32fd8..fe2b393923f 100644 --- a/apps/browser/src/decorators/session-sync-observable/sync-item-metadata.ts +++ b/apps/browser/src/decorators/session-sync-observable/sync-item-metadata.ts @@ -3,15 +3,11 @@ export type InitializeOptions = "array" | "record" | "object"; export class SyncedItemMetadata { propertyKey: string; sessionKey: string; - ctor?: new () => any; - initializer?: (keyValuePair: any) => any; + initializer: (keyValuePair: any) => any; initializeAs: InitializeOptions; static builder(metadata: SyncedItemMetadata): (o: any) => any { - const itemBuilder = - metadata.initializer != null - ? metadata.initializer - : (o: any) => Object.assign(new metadata.ctor(), o); + const itemBuilder = metadata.initializer; if (metadata.initializeAs === "array") { return (keyValuePair: any) => keyValuePair.map((o: any) => itemBuilder(o)); } else if (metadata.initializeAs === "record") { diff --git a/apps/browser/src/decorators/session-sync-observable/synced-item-metadata.spec.ts b/apps/browser/src/decorators/session-sync-observable/synced-item-metadata.spec.ts index 12b0b57d523..61eb63eaac0 100644 --- a/apps/browser/src/decorators/session-sync-observable/synced-item-metadata.spec.ts +++ b/apps/browser/src/decorators/session-sync-observable/synced-item-metadata.spec.ts @@ -4,10 +4,8 @@ describe("builder", () => { const propertyKey = "propertyKey"; const key = "key"; const initializer = (s: any) => "used initializer"; - class TestClass {} - const ctor = TestClass; - it("should use initializer if provided", () => { + it("should use initializer", () => { const metadata: SyncedItemMetadata = { propertyKey, sessionKey: key, @@ -18,29 +16,6 @@ describe("builder", () => { expect(builder({})).toBe("used initializer"); }); - it("should use ctor if initializer is not provided", () => { - const metadata: SyncedItemMetadata = { - propertyKey, - sessionKey: key, - ctor, - initializeAs: "object", - }; - const builder = SyncedItemMetadata.builder(metadata); - expect(builder({})).toBeInstanceOf(TestClass); - }); - - it("should prefer initializer over ctor", () => { - const metadata: SyncedItemMetadata = { - propertyKey, - sessionKey: key, - ctor, - initializer, - initializeAs: "object", - }; - const builder = SyncedItemMetadata.builder(metadata); - expect(builder({})).toBe("used initializer"); - }); - it("should honor initialize as array", () => { const metadata: SyncedItemMetadata = { propertyKey, diff --git a/apps/browser/src/flags.ts b/apps/browser/src/flags.ts index 39aad1809c6..5159cac9683 100644 --- a/apps/browser/src/flags.ts +++ b/apps/browser/src/flags.ts @@ -6,7 +6,7 @@ import { SharedDevFlags, } from "@bitwarden/common/misc/flags"; -import { GroupPolicyEnvironment } from "./types/group-policy-environment"; +import { GroupPolicyEnvironment } from "./admin-console/types/group-policy-environment"; // required to avoid linting errors when there are no flags /* eslint-disable-next-line @typescript-eslint/ban-types */ diff --git a/apps/browser/src/manifest.json b/apps/browser/src/manifest.json index c03a0396ff3..158211fded1 100644 --- a/apps/browser/src/manifest.json +++ b/apps/browser/src/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_extName__", "short_name": "__MSG_appName__", - "version": "2023.1.0", + "version": "2023.3.0", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/apps/browser/src/manifest.v3.json b/apps/browser/src/manifest.v3.json index a7dc1b50b9c..dcdc2cfb62a 100644 --- a/apps/browser/src/manifest.v3.json +++ b/apps/browser/src/manifest.v3.json @@ -3,7 +3,7 @@ "minimum_chrome_version": "102.0", "name": "__MSG_extName__", "short_name": "__MSG_appName__", - "version": "2023.1.0", + "version": "2023.3.0", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/apps/browser/src/models/browserGroupingsComponentState.ts b/apps/browser/src/models/browserGroupingsComponentState.ts index a09c336f961..32375463701 100644 --- a/apps/browser/src/models/browserGroupingsComponentState.ts +++ b/apps/browser/src/models/browserGroupingsComponentState.ts @@ -1,5 +1,5 @@ +import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { Utils } from "@bitwarden/common/misc/utils"; -import { CollectionView } from "@bitwarden/common/models/view/collection.view"; import { DeepJsonify } from "@bitwarden/common/types/deep-jsonify"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; diff --git a/apps/browser/src/models/browserSendComponentState.ts b/apps/browser/src/models/browserSendComponentState.ts index 99508737ab1..d4086f3703b 100644 --- a/apps/browser/src/models/browserSendComponentState.ts +++ b/apps/browser/src/models/browserSendComponentState.ts @@ -1,6 +1,6 @@ -import { SendType } from "@bitwarden/common/enums/sendType"; import { Utils } from "@bitwarden/common/misc/utils"; -import { SendView } from "@bitwarden/common/models/view/send.view"; +import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; +import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; import { DeepJsonify } from "@bitwarden/common/types/deep-jsonify"; import { BrowserComponentState } from "./browserComponentState"; diff --git a/apps/browser/src/popup/app-routing.animations.ts b/apps/browser/src/popup/app-routing.animations.ts index 560016ad978..2304944acb0 100644 --- a/apps/browser/src/popup/app-routing.animations.ts +++ b/apps/browser/src/popup/app-routing.animations.ts @@ -197,6 +197,9 @@ export const routerTransition = trigger("routerTransition", [ transition("tabs => lock", inSlideDown), + transition("tabs => help-and-feedback", inSlideLeft), + transition("help-and-feedback => tabs", outSlideRight), + transition("tabs => send-type", inSlideLeft), transition("send-type => tabs", outSlideRight), @@ -205,4 +208,7 @@ export const routerTransition = trigger("routerTransition", [ transition("tabs => edit-send, send-type => edit-send", inSlideUp), transition("edit-send => tabs, edit-send => send-type", outSlideDown), + + transition("tabs => autofill", inSlideLeft), + transition("autofill => tabs", outSlideRight), ]); diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index fe1a9c8f55d..a321c66a8e5 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -18,8 +18,14 @@ import { SsoComponent } from "../auth/popup/sso.component"; import { TwoFactorOptionsComponent } from "../auth/popup/two-factor-options.component"; import { TwoFactorComponent } from "../auth/popup/two-factor.component"; import { UpdateTempPasswordComponent } from "../auth/popup/update-temp-password.component"; +import { GeneratorComponent } from "../tools/popup/generator/generator.component"; +import { PasswordGeneratorHistoryComponent } from "../tools/popup/generator/password-generator-history.component"; +import { SendAddEditComponent } from "../tools/popup/send/send-add-edit.component"; +import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.component"; +import { SendTypeComponent } from "../tools/popup/send/send-type.component"; import { AddEditComponent } from "../vault/popup/components/vault/add-edit.component"; import { AttachmentsComponent } from "../vault/popup/components/vault/attachments.component"; +import { CollectionsComponent } from "../vault/popup/components/vault/collections.component"; import { CurrentTabComponent } from "../vault/popup/components/vault/current-tab.component"; import { PasswordHistoryComponent } from "../vault/popup/components/vault/password-history.component"; import { ShareComponent } from "../vault/popup/components/vault/share.component"; @@ -28,23 +34,18 @@ import { VaultItemsComponent } from "../vault/popup/components/vault/vault-items import { ViewComponent } from "../vault/popup/components/vault/view.component"; import { Fido2Component } from "../webauthn/popup/fido2/fido2.component"; -import { GeneratorComponent } from "./generator/generator.component"; -import { PasswordGeneratorHistoryComponent } from "./generator/password-generator-history.component"; -import { SendAddEditComponent } from "./send/send-add-edit.component"; -import { SendGroupingsComponent } from "./send/send-groupings.component"; -import { SendTypeComponent } from "./send/send-type.component"; import { DebounceNavigationService } from "./services/debounceNavigationService"; import { AutofillComponent } from "./settings/autofill.component"; import { ExcludedDomainsComponent } from "./settings/excluded-domains.component"; import { ExportComponent } from "./settings/export.component"; import { FolderAddEditComponent } from "./settings/folder-add-edit.component"; import { FoldersComponent } from "./settings/folders.component"; +import { HelpAndFeedbackComponent } from "./settings/help-and-feedback.component"; import { OptionsComponent } from "./settings/options.component"; import { PremiumComponent } from "./settings/premium.component"; import { SettingsComponent } from "./settings/settings.component"; import { SyncComponent } from "./settings/sync.component"; import { TabsComponent } from "./tabs.component"; -import { CollectionsComponent } from "./vault/collections.component"; const routes: Routes = [ { @@ -278,6 +279,12 @@ const routes: Routes = [ canActivate: [AuthGuard], data: { state: "update-temp-password" }, }, + { + path: "help-and-feedback", + component: HelpAndFeedbackComponent, + canActivate: [AuthGuard], + data: { state: "help-and-feedback" }, + }, { path: "tabs", component: TabsComponent, diff --git a/apps/browser/src/popup/app.module.ts b/apps/browser/src/popup/app.module.ts index e378af63646..78f2d87e8c4 100644 --- a/apps/browser/src/popup/app.module.ts +++ b/apps/browser/src/popup/app.module.ts @@ -32,13 +32,20 @@ import { SsoComponent } from "../auth/popup/sso.component"; import { TwoFactorOptionsComponent } from "../auth/popup/two-factor-options.component"; import { TwoFactorComponent } from "../auth/popup/two-factor.component"; import { UpdateTempPasswordComponent } from "../auth/popup/update-temp-password.component"; -import { CollectionsComponent } from "../popup/vault/collections.component"; +import { GeneratorComponent } from "../tools/popup/generator/generator.component"; +import { PasswordGeneratorHistoryComponent } from "../tools/popup/generator/password-generator-history.component"; +import { SendListComponent } from "../tools/popup/send/components/send-list.component"; +import { EffluxDatesComponent as SendEffluxDatesComponent } from "../tools/popup/send/efflux-dates.component"; +import { SendAddEditComponent } from "../tools/popup/send/send-add-edit.component"; +import { SendGroupingsComponent } from "../tools/popup/send/send-groupings.component"; +import { SendTypeComponent } from "../tools/popup/send/send-type.component"; import { ActionButtonsComponent } from "../vault/popup/components/action-buttons.component"; import { CipherRowComponent } from "../vault/popup/components/cipher-row.component"; import { PasswordRepromptComponent } from "../vault/popup/components/password-reprompt.component"; import { AddEditCustomFieldsComponent } from "../vault/popup/components/vault/add-edit-custom-fields.component"; import { AddEditComponent } from "../vault/popup/components/vault/add-edit.component"; import { AttachmentsComponent } from "../vault/popup/components/vault/attachments.component"; +import { CollectionsComponent } from "../vault/popup/components/vault/collections.component"; import { CurrentTabComponent } from "../vault/popup/components/vault/current-tab.component"; import { PasswordHistoryComponent } from "../vault/popup/components/vault/password-history.component"; import { ShareComponent } from "../vault/popup/components/vault/share.component"; @@ -53,15 +60,8 @@ import { AppRoutingModule } from "./app-routing.module"; import { AppComponent } from "./app.component"; import { PopOutComponent } from "./components/pop-out.component"; import { PrivateModeWarningComponent } from "./components/private-mode-warning.component"; -import { SendListComponent } from "./components/send-list.component"; import { SetPinComponent } from "./components/set-pin.component"; import { UserVerificationComponent } from "./components/user-verification.component"; -import { GeneratorComponent } from "./generator/generator.component"; -import { PasswordGeneratorHistoryComponent } from "./generator/password-generator-history.component"; -import { EffluxDatesComponent as SendEffluxDatesComponent } from "./send/efflux-dates.component"; -import { SendAddEditComponent } from "./send/send-add-edit.component"; -import { SendGroupingsComponent } from "./send/send-groupings.component"; -import { SendTypeComponent } from "./send/send-type.component"; import { ServicesModule } from "./services/services.module"; import { AboutComponent } from "./settings/about.component"; import { AutofillComponent } from "./settings/autofill.component"; @@ -69,6 +69,7 @@ import { ExcludedDomainsComponent } from "./settings/excluded-domains.component" import { ExportComponent } from "./settings/export.component"; import { FolderAddEditComponent } from "./settings/folder-add-edit.component"; import { FoldersComponent } from "./settings/folders.component"; +import { HelpAndFeedbackComponent } from "./settings/help-and-feedback.component"; import { OptionsComponent } from "./settings/options.component"; import { PremiumComponent } from "./settings/premium.component"; import { SettingsComponent } from "./settings/settings.component"; @@ -153,6 +154,7 @@ import { TabsComponent } from "./tabs.component"; VaultSelectComponent, AboutComponent, Fido2Component, + HelpAndFeedbackComponent, AutofillComponent, ], providers: [CurrencyPipe, DatePipe], diff --git a/apps/browser/src/popup/polyfills.ts b/apps/browser/src/popup/polyfills.ts index 9a30bd23da4..8edc909639d 100644 --- a/apps/browser/src/popup/polyfills.ts +++ b/apps/browser/src/popup/polyfills.ts @@ -1,3 +1,3 @@ import "core-js/stable"; import "date-input-polyfill"; -import "zone.js/dist/zone"; +import "zone.js"; diff --git a/apps/browser/src/popup/scss/base.scss b/apps/browser/src/popup/scss/base.scss index b1b438c8345..66a4f90f157 100644 --- a/apps/browser/src/popup/scss/base.scss +++ b/apps/browser/src/popup/scss/base.scss @@ -222,6 +222,7 @@ header { justify-content: center; align-items: center; height: 100%; + white-space: pre; @include themify($themes) { color: themed("headerColor"); @@ -408,28 +409,10 @@ app-root { } } +// Adds padding on each side of the content if opened in a tab @media only screen and (min-width: 601px) { - app-login header { - padding: 0 calc((100% - 500px) / 2); - } - - app-login main { - padding: 0 calc((100% - 500px) / 2); - } - - app-two-factor header { - padding: 0 calc((100% - 500px) / 2); - } - - app-two-factor main { - padding: 0 calc((100% - 500px) / 2); - } - - app-lock header { - padding: 0 calc((100% - 500px) / 2); - } - - app-lock main { + header, + main { padding: 0 calc((100% - 500px) / 2); } } diff --git a/apps/browser/src/popup/scss/box.scss b/apps/browser/src/popup/scss/box.scss index ef13a7f5455..c026c780889 100644 --- a/apps/browser/src/popup/scss/box.scss +++ b/apps/browser/src/popup/scss/box.scss @@ -354,6 +354,7 @@ &.box-content-row-flex, .box-content-row-flex, &.box-content-row-checkbox, + &.box-content-row-link, &.box-content-row-input, &.box-content-row-slider, &.box-content-row-multi { @@ -398,6 +399,7 @@ } &.box-content-row-checkbox, + &.box-content-row-link, &.box-content-row-input, &.box-content-row-slider { padding-top: 10px; diff --git a/apps/browser/src/popup/scss/buttons.scss b/apps/browser/src/popup/scss/buttons.scss index 4c5141cf8f7..e9af536dc3d 100644 --- a/apps/browser/src/popup/scss/buttons.scss +++ b/apps/browser/src/popup/scss/buttons.scss @@ -28,7 +28,7 @@ &.callout-half { font-weight: bold; - max-width: 45%; + max-width: 50%; } &:hover:not([disabled]) { diff --git a/apps/browser/src/popup/services/popup-utils.service.ts b/apps/browser/src/popup/services/popup-utils.service.ts index 85caff0f3d3..c91038b7d00 100644 --- a/apps/browser/src/popup/services/popup-utils.service.ts +++ b/apps/browser/src/popup/services/popup-utils.service.ts @@ -1,9 +1,12 @@ import { Injectable } from "@angular/core"; +import { fromEvent, Subscription } from "rxjs"; import { BrowserApi } from "../../browser/browserApi"; @Injectable() export class PopupUtilsService { + private unloadSubscription: Subscription; + constructor(private privateMode: boolean = false) {} inSidebar(win: Window): boolean { @@ -86,4 +89,36 @@ export class PopupUtilsService { }); } } + + /** + * Enables a pop-up warning before the user exits the window/tab, or navigates away. + * This warns the user that they may lose unsaved data if they leave the page. + * (Note: navigating within the Angular app will not trigger it because it's an SPA.) + * Make sure you call `disableTabCloseWarning` when it is no longer relevant. + */ + enableCloseTabWarning() { + this.disableCloseTabWarning(); + + this.unloadSubscription = fromEvent(window, "beforeunload").subscribe( + (e: BeforeUnloadEvent) => { + // Recommended method but not widely supported + e.preventDefault(); + + // Modern browsers do not display this message, it just needs to be a non-nullish value + // Exact wording is determined by the browser + const confirmationMessage = ""; + + // Older methods with better support + e.returnValue = confirmationMessage; + return confirmationMessage; + } + ); + } + + /** + * Disables the warning enabled by enableCloseTabWarning. + */ + disableCloseTabWarning() { + this.unloadSubscription?.unsubscribe(); + } } diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 7f4fad3fd93..dae7bb34ae5 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -9,7 +9,6 @@ import { AbstractThemingService } from "@bitwarden/angular/services/theming/them import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AppIdService } from "@bitwarden/common/abstractions/appId.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; -import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { ConfigApiServiceAbstraction } from "@bitwarden/common/abstractions/config/config-api.service.abstraction"; import { ConfigServiceAbstraction } from "@bitwarden/common/abstractions/config/config.service.abstraction"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; @@ -19,23 +18,14 @@ import { EnvironmentService } from "@bitwarden/common/abstractions/environment.s import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service"; import { ExportService } from "@bitwarden/common/abstractions/export.service"; +import { FileUploadService } from "@bitwarden/common/abstractions/file-upload/file-upload.service"; import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service"; -import { FileUploadService } from "@bitwarden/common/abstractions/fileUpload.service"; import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service"; import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; -import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; -import { PolicyApiServiceAbstraction } from "@bitwarden/common/abstractions/policy/policy-api.service.abstraction"; -import { - InternalPolicyService, - PolicyService, -} from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; -import { ProviderService } from "@bitwarden/common/abstractions/provider.service"; import { SearchService as SearchServiceAbstraction } from "@bitwarden/common/abstractions/search.service"; -import { SendService } from "@bitwarden/common/abstractions/send.service"; import { SettingsService } from "@bitwarden/common/abstractions/settings.service"; import { StateService as BaseStateServiceAbstraction, @@ -48,9 +38,17 @@ import { } from "@bitwarden/common/abstractions/storage.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service"; import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification/userVerification.service.abstraction"; -import { UsernameGenerationService } from "@bitwarden/common/abstractions/usernameGeneration.service"; import { VaultTimeoutService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeout.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vaultTimeout/vaultTimeoutSettings.service"; +import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; +import { + InternalPolicyService, + PolicyService, +} from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service"; +import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service"; import { AuthService as AuthServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth.service"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { LoginService as LoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/login.service"; @@ -62,9 +60,17 @@ import { StateFactory } from "@bitwarden/common/factories/stateFactory"; import { GlobalState } from "@bitwarden/common/models/domain/global-state"; import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service"; import { ContainerService } from "@bitwarden/common/services/container.service"; -import { PolicyApiService } from "@bitwarden/common/services/policy/policy-api.service"; import { SearchService } from "@bitwarden/common/services/search.service"; +import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username"; +import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service"; +import { SendApiService as SendApiServiceAbstraction } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; +import { + InternalSendService as InternalSendServiceAbstraction, + SendService, +} from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; +import { CipherFileUploadService } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; import { FolderService, @@ -74,6 +80,8 @@ import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@ import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service"; +import { BrowserOrganizationService } from "../../admin-console/services/browser-organization.service"; +import { BrowserPolicyService } from "../../admin-console/services/browser-policy.service"; import { LockGuardService, UnauthGuardService } from "../../auth/popup/services"; import { AutofillService } from "../../autofill/services/abstractions/autofill.service"; import MainBackground from "../../background/main.background"; @@ -83,8 +91,7 @@ import { BrowserStateService as StateServiceAbstraction } from "../../services/a import { BrowserConfigService } from "../../services/browser-config.service"; import { BrowserEnvironmentService } from "../../services/browser-environment.service"; import { BrowserI18nService } from "../../services/browser-i18n.service"; -import { BrowserOrganizationService } from "../../services/browser-organization.service"; -import { BrowserPolicyService } from "../../services/browser-policy.service"; +import { BrowserSendService } from "../../services/browser-send.service"; import { BrowserSettingsService } from "../../services/browser-settings.service"; import { BrowserStateService } from "../../services/browser-state.service"; import { BrowserFileDownloadService } from "../../services/browserFileDownloadService"; @@ -173,8 +180,8 @@ function getBgService(service: keyof MainBackground) { }, { provide: AuditService, useFactory: getBgService("auditService"), deps: [] }, { - provide: FileUploadService, - useFactory: getBgService("fileUploadService"), + provide: CipherFileUploadService, + useFactory: getBgService("cipherFileUploadService"), deps: [], }, { provide: CipherService, useFactory: getBgService("cipherService"), deps: [] }, @@ -183,6 +190,10 @@ function getBgService(service: keyof MainBackground) { useFactory: getBgService("cryptoFunctionService"), deps: [], }, + { + provide: FileUploadService, + useFactory: getBgService("fileUploadService"), + }, { provide: FolderService, useFactory: ( @@ -280,11 +291,43 @@ function getBgService(service: keyof MainBackground) { deps: [], }, { - provide: PasswordGenerationService, - useFactory: getBgService("passwordGenerationService"), + provide: PasswordGenerationServiceAbstraction, + useFactory: getBgService("passwordGenerationService"), deps: [], }, { provide: ApiService, useFactory: getBgService("apiService"), deps: [] }, + { + provide: SendService, + useFactory: ( + cryptoService: CryptoService, + i18nService: I18nServiceAbstraction, + cryptoFunctionService: CryptoFunctionService, + stateServiceAbstraction: StateServiceAbstraction + ) => { + return new BrowserSendService( + cryptoService, + i18nService, + cryptoFunctionService, + stateServiceAbstraction + ); + }, + deps: [CryptoService, I18nServiceAbstraction, CryptoFunctionService, StateServiceAbstraction], + }, + { + provide: InternalSendServiceAbstraction, + useExisting: SendService, + }, + { + provide: SendApiServiceAbstraction, + useFactory: ( + apiService: ApiService, + fileUploadService: FileUploadService, + sendService: InternalSendServiceAbstraction + ) => { + return new SendApiService(apiService, fileUploadService, sendService); + }, + deps: [ApiService, FileUploadService, InternalSendServiceAbstraction], + }, { provide: SyncService, useFactory: getBgService("syncService"), deps: [] }, { provide: SettingsService, @@ -305,7 +348,6 @@ function getBgService(service: keyof MainBackground) { deps: [], }, { provide: ExportService, useFactory: getBgService("exportService"), deps: [] }, - { provide: SendService, useFactory: getBgService("sendService"), deps: [] }, { provide: KeyConnectorService, useFactory: getBgService("keyConnectorService"), @@ -409,8 +451,8 @@ function getBgService(service: keyof MainBackground) { ], }, { - provide: UsernameGenerationService, - useFactory: getBgService("usernameGenerationService"), + provide: UsernameGenerationServiceAbstraction, + useFactory: getBgService("usernameGenerationService"), deps: [], }, { diff --git a/apps/browser/src/popup/settings/about.component.html b/apps/browser/src/popup/settings/about.component.html index c11b68e9c1f..c8840833cf7 100644 --- a/apps/browser/src/popup/settings/about.component.html +++ b/apps/browser/src/popup/settings/about.component.html @@ -14,7 +14,7 @@

{{ "serverVersion" | i18n }}: {{ this.serverConfig?.version }} - ({{ "lastSeenOn" | i18n: (serverConfig.utcDate | date: "mediumDate") }}) + ({{ "lastSeenOn" | i18n : (serverConfig.utcDate | date : "mediumDate") }})

@@ -24,11 +24,11 @@ {{ "serverVersion" | i18n }} ({{ "thirdParty" | i18n }}): {{ this.serverConfig?.version }} - ({{ "lastSeenOn" | i18n: (serverConfig.utcDate | date: "mediumDate") }}) + ({{ "lastSeenOn" | i18n : (serverConfig.utcDate | date : "mediumDate") }})

- {{ "thirdPartyServerMessage" | i18n: serverConfig.server?.name }} + {{ "thirdPartyServerMessage" | i18n : serverConfig.server?.name }}
@@ -36,7 +36,7 @@ {{ "serverVersion" | i18n }} ({{ "selfHosted" | i18n }}): {{ this.serverConfig?.version }} - ({{ "lastSeenOn" | i18n: (serverConfig.utcDate | date: "mediumDate") }}) + ({{ "lastSeenOn" | i18n : (serverConfig.utcDate | date : "mediumDate") }})

diff --git a/apps/browser/src/popup/settings/autofill.component.html b/apps/browser/src/popup/settings/autofill.component.html index c3a76e145e7..a3ff1936711 100644 --- a/apps/browser/src/popup/settings/autofill.component.html +++ b/apps/browser/src/popup/settings/autofill.component.html @@ -72,4 +72,19 @@ {{ "defaultUriMatchDetectionDesc" | i18n }}
+
+
+ +
+ +
diff --git a/apps/browser/src/popup/settings/autofill.component.ts b/apps/browser/src/popup/settings/autofill.component.ts index 7c949921b87..dfe5925e2e7 100644 --- a/apps/browser/src/popup/settings/autofill.component.ts +++ b/apps/browser/src/popup/settings/autofill.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from "@angular/core"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; +import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { UriMatchType } from "@bitwarden/common/enums/uriMatchType"; @@ -16,8 +17,13 @@ export class AutofillComponent implements OnInit { autoFillOnPageLoadOptions: any[]; defaultUriMatch = UriMatchType.Domain; uriMatchOptions: any[]; + autofillKeyboardHelperText: string; - constructor(private stateService: StateService, i18nService: I18nService) { + constructor( + private stateService: StateService, + private i18nService: I18nService, + private platformUtilsService: PlatformUtilsService + ) { this.autoFillOnPageLoadOptions = [ { name: i18nService.t("autoFillOnPageLoadYes"), value: true }, { name: i18nService.t("autoFillOnPageLoadNo"), value: false }, @@ -40,6 +46,9 @@ export class AutofillComponent implements OnInit { const defaultUriMatch = await this.stateService.getDefaultUriMatch(); this.defaultUriMatch = defaultUriMatch == null ? UriMatchType.Domain : defaultUriMatch; + + const command = await this.platformUtilsService.getAutofillKeyboardShortcut(); + await this.setAutofillKeyboardHelperText(command); } async updateAutoFillOnPageLoad() { @@ -57,4 +66,26 @@ export class AutofillComponent implements OnInit { AboutAutofill() { BrowserApi.createNewTab("https://bitwarden.com/help/auto-fill-browser/"); } + + private async setAutofillKeyboardHelperText(command: string) { + if (command) { + this.autofillKeyboardHelperText = this.i18nService.t("autofillShortcutText", command); + } else { + this.autofillKeyboardHelperText = this.i18nService.t("autofillShortcutNotSet"); + } + } + + async commandSettings() { + if (this.platformUtilsService.isChrome()) { + BrowserApi.createNewTab("chrome://extensions/shortcuts"); + } else if (this.platformUtilsService.isOpera()) { + BrowserApi.createNewTab("opera://extensions/shortcuts"); + } else if (this.platformUtilsService.isEdge()) { + BrowserApi.createNewTab("edge://extensions/shortcuts"); + } else if (this.platformUtilsService.isVivaldi()) { + BrowserApi.createNewTab("vivaldi://extensions/shortcuts"); + } else { + BrowserApi.createNewTab("https://bitwarden.com/help/keyboard-shortcuts"); + } + } } diff --git a/apps/browser/src/popup/settings/excluded-domains.component.html b/apps/browser/src/popup/settings/excluded-domains.component.html index 89981648722..87a3f0a042b 100644 --- a/apps/browser/src/popup/settings/excluded-domains.component.html +++ b/apps/browser/src/popup/settings/excluded-domains.component.html @@ -31,7 +31,7 @@
- + +
+ +
+

+ {{ "helpFeedback" | i18n }} +

+
+ +
+
+
+ + + +
+
+
diff --git a/apps/browser/src/popup/settings/help-and-feedback.component.ts b/apps/browser/src/popup/settings/help-and-feedback.component.ts new file mode 100644 index 00000000000..006f76f48bc --- /dev/null +++ b/apps/browser/src/popup/settings/help-and-feedback.component.ts @@ -0,0 +1,20 @@ +import { Component } from "@angular/core"; + +import { BrowserApi } from "../../browser/browserApi"; + +@Component({ + selector: "app-help-and-feedback", + templateUrl: "help-and-feedback.component.html", +}) +export class HelpAndFeedbackComponent { + launchHelp() { + BrowserApi.createNewTab("https://bitwarden.com/help/"); + } + launchContactForm() { + BrowserApi.createNewTab("https://bitwarden.com/contact/"); + } + + launchForums() { + BrowserApi.createNewTab("https://bitwarden.com/getinvolved/"); + } +} diff --git a/apps/browser/src/popup/settings/settings.component.html b/apps/browser/src/popup/settings/settings.component.html index d371acc450f..539e971b5f1 100644 --- a/apps/browser/src/popup/settings/settings.component.html +++ b/apps/browser/src/popup/settings/settings.component.html @@ -221,8 +221,7 @@
diff --git a/apps/browser/src/popup/generator/password-generator-history.component.ts b/apps/browser/src/tools/popup/generator/password-generator-history.component.ts similarity index 73% rename from apps/browser/src/popup/generator/password-generator-history.component.ts rename to apps/browser/src/tools/popup/generator/password-generator-history.component.ts index ca586d8f99c..18110fc5d96 100644 --- a/apps/browser/src/popup/generator/password-generator-history.component.ts +++ b/apps/browser/src/tools/popup/generator/password-generator-history.component.ts @@ -1,10 +1,10 @@ import { Location } from "@angular/common"; import { Component } from "@angular/core"; -import { PasswordGeneratorHistoryComponent as BasePasswordGeneratorHistoryComponent } from "@bitwarden/angular/components/password-generator-history.component"; +import { PasswordGeneratorHistoryComponent as BasePasswordGeneratorHistoryComponent } from "@bitwarden/angular/tools/generator/components/password-generator-history.component"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; -import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; +import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; @Component({ selector: "app-password-generator-history", @@ -12,7 +12,7 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti }) export class PasswordGeneratorHistoryComponent extends BasePasswordGeneratorHistoryComponent { constructor( - passwordGenerationService: PasswordGenerationService, + passwordGenerationService: PasswordGenerationServiceAbstraction, platformUtilsService: PlatformUtilsService, i18nService: I18nService, private location: Location diff --git a/apps/browser/src/popup/components/send-list.component.html b/apps/browser/src/tools/popup/send/components/send-list.component.html similarity index 97% rename from apps/browser/src/popup/components/send-list.component.html rename to apps/browser/src/tools/popup/send/components/send-list.component.html index 05c8e3e3754..3dc5af0106d 100644 --- a/apps/browser/src/popup/components/send-list.component.html +++ b/apps/browser/src/tools/popup/send/components/send-list.component.html @@ -57,7 +57,7 @@ {{ "pendingDeletion" | i18n }} - {{ s.deletionDate | date: "medium" }} + {{ s.deletionDate | date : "medium" }}
diff --git a/apps/browser/src/popup/components/send-list.component.ts b/apps/browser/src/tools/popup/send/components/send-list.component.ts similarity index 84% rename from apps/browser/src/popup/components/send-list.component.ts rename to apps/browser/src/tools/popup/send/components/send-list.component.ts index 05254729eb3..032ffaa57cb 100644 --- a/apps/browser/src/popup/components/send-list.component.ts +++ b/apps/browser/src/tools/popup/send/components/send-list.component.ts @@ -1,7 +1,7 @@ import { Component, EventEmitter, Input, Output } from "@angular/core"; -import { SendType } from "@bitwarden/common/enums/sendType"; -import { SendView } from "@bitwarden/common/models/view/send.view"; +import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; +import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; @Component({ selector: "app-send-list", diff --git a/apps/browser/src/popup/send/efflux-dates.component.html b/apps/browser/src/tools/popup/send/efflux-dates.component.html similarity index 100% rename from apps/browser/src/popup/send/efflux-dates.component.html rename to apps/browser/src/tools/popup/send/efflux-dates.component.html diff --git a/apps/browser/src/popup/send/efflux-dates.component.ts b/apps/browser/src/tools/popup/send/efflux-dates.component.ts similarity index 93% rename from apps/browser/src/popup/send/efflux-dates.component.ts rename to apps/browser/src/tools/popup/send/efflux-dates.component.ts index 8a58756dadc..0578cce2dda 100644 --- a/apps/browser/src/popup/send/efflux-dates.component.ts +++ b/apps/browser/src/tools/popup/send/efflux-dates.component.ts @@ -2,7 +2,7 @@ import { DatePipe } from "@angular/common"; import { Component, EventEmitter, Input, Output } from "@angular/core"; import { ControlContainer, NgForm } from "@angular/forms"; -import { EffluxDatesComponent as BaseEffluxDatesComponent } from "@bitwarden/angular/components/send/efflux-dates.component"; +import { EffluxDatesComponent as BaseEffluxDatesComponent } from "@bitwarden/angular/tools/send/efflux-dates.component"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; diff --git a/apps/browser/src/popup/send/send-add-edit.component.html b/apps/browser/src/tools/popup/send/send-add-edit.component.html similarity index 100% rename from apps/browser/src/popup/send/send-add-edit.component.html rename to apps/browser/src/tools/popup/send/send-add-edit.component.html diff --git a/apps/browser/src/popup/send/send-add-edit.component.ts b/apps/browser/src/tools/popup/send/send-add-edit.component.ts similarity index 86% rename from apps/browser/src/popup/send/send-add-edit.component.ts rename to apps/browser/src/tools/popup/send/send-add-edit.component.ts index 0355b764c30..1140aa60f93 100644 --- a/apps/browser/src/popup/send/send-add-edit.component.ts +++ b/apps/browser/src/tools/popup/send/send-add-edit.component.ts @@ -3,17 +3,18 @@ import { Component } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; import { first } from "rxjs/operators"; -import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/components/send/add-edit.component"; +import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/tools/send/add-edit.component"; import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; -import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; -import { SendService } from "@bitwarden/common/abstractions/send.service"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; +import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; -import { BrowserStateService } from "../../services/abstractions/browser-state.service"; -import { PopupUtilsService } from "../services/popup-utils.service"; +import { PopupUtilsService } from "../../../popup/services/popup-utils.service"; +import { BrowserStateService } from "../../../services/abstractions/browser-state.service"; @Component({ selector: "app-send-add-edit", @@ -43,7 +44,8 @@ export class SendAddEditComponent extends BaseAddEditComponent { private router: Router, private location: Location, private popupUtilsService: PopupUtilsService, - logService: LogService + logService: LogService, + sendApiService: SendApiService ) { super( i18nService, @@ -54,7 +56,8 @@ export class SendAddEditComponent extends BaseAddEditComponent { messagingService, policyService, logService, - stateService + stateService, + sendApiService ); } diff --git a/apps/browser/src/popup/send/send-groupings.component.html b/apps/browser/src/tools/popup/send/send-groupings.component.html similarity index 100% rename from apps/browser/src/popup/send/send-groupings.component.html rename to apps/browser/src/tools/popup/send/send-groupings.component.html diff --git a/apps/browser/src/popup/send/send-groupings.component.ts b/apps/browser/src/tools/popup/send/send-groupings.component.ts similarity index 86% rename from apps/browser/src/popup/send/send-groupings.component.ts rename to apps/browser/src/tools/popup/send/send-groupings.component.ts index 5e442f71122..c2188c6d4a7 100644 --- a/apps/browser/src/popup/send/send-groupings.component.ts +++ b/apps/browser/src/tools/popup/send/send-groupings.component.ts @@ -1,22 +1,23 @@ import { ChangeDetectorRef, Component, NgZone } from "@angular/core"; import { Router } from "@angular/router"; -import { SendComponent as BaseSendComponent } from "@bitwarden/angular/components/send/send.component"; +import { SendComponent as BaseSendComponent } from "@bitwarden/angular/tools/send/send.component"; import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service"; import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; -import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { SendService } from "@bitwarden/common/abstractions/send.service"; -import { SendType } from "@bitwarden/common/enums/sendType"; -import { SendView } from "@bitwarden/common/models/view/send.view"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; +import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; +import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; +import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; -import { BrowserSendComponentState } from "../../models/browserSendComponentState"; -import { BrowserStateService } from "../../services/abstractions/browser-state.service"; -import { PopupUtilsService } from "../services/popup-utils.service"; +import { BrowserSendComponentState } from "../../../models/browserSendComponentState"; +import { PopupUtilsService } from "../../../popup/services/popup-utils.service"; +import { BrowserStateService } from "../../../services/abstractions/browser-state.service"; const ComponentId = "SendComponent"; @@ -47,7 +48,8 @@ export class SendGroupingsComponent extends BaseSendComponent { private syncService: SyncService, private changeDetectorRef: ChangeDetectorRef, private broadcasterService: BroadcasterService, - logService: LogService + logService: LogService, + sendApiService: SendApiService ) { super( sendService, @@ -57,7 +59,8 @@ export class SendGroupingsComponent extends BaseSendComponent { ngZone, searchService, policyService, - logService + logService, + sendApiService ); super.onSuccessfulLoad = async () => { this.calculateTypeCounts(); diff --git a/apps/browser/src/popup/send/send-type.component.html b/apps/browser/src/tools/popup/send/send-type.component.html similarity index 100% rename from apps/browser/src/popup/send/send-type.component.html rename to apps/browser/src/tools/popup/send/send-type.component.html diff --git a/apps/browser/src/popup/send/send-type.component.ts b/apps/browser/src/tools/popup/send/send-type.component.ts similarity index 84% rename from apps/browser/src/popup/send/send-type.component.ts rename to apps/browser/src/tools/popup/send/send-type.component.ts index e899ab9f00f..836fcef714d 100644 --- a/apps/browser/src/popup/send/send-type.component.ts +++ b/apps/browser/src/tools/popup/send/send-type.component.ts @@ -3,21 +3,22 @@ import { ChangeDetectorRef, Component, NgZone } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; import { first } from "rxjs/operators"; -import { SendComponent as BaseSendComponent } from "@bitwarden/angular/components/send/send.component"; +import { SendComponent as BaseSendComponent } from "@bitwarden/angular/tools/send/send.component"; import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service"; import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; -import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; -import { SendService } from "@bitwarden/common/abstractions/send.service"; -import { SendType } from "@bitwarden/common/enums/sendType"; -import { SendView } from "@bitwarden/common/models/view/send.view"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; +import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; +import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; +import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; -import { BrowserComponentState } from "../../models/browserComponentState"; -import { BrowserStateService } from "../../services/abstractions/browser-state.service"; -import { PopupUtilsService } from "../services/popup-utils.service"; +import { BrowserComponentState } from "../../../models/browserComponentState"; +import { PopupUtilsService } from "../../../popup/services/popup-utils.service"; +import { BrowserStateService } from "../../../services/abstractions/browser-state.service"; const ComponentId = "SendTypeComponent"; @@ -47,7 +48,8 @@ export class SendTypeComponent extends BaseSendComponent { private changeDetectorRef: ChangeDetectorRef, private broadcasterService: BroadcasterService, private router: Router, - logService: LogService + logService: LogService, + sendApiService: SendApiService ) { super( sendService, @@ -57,7 +59,8 @@ export class SendTypeComponent extends BaseSendComponent { ngZone, searchService, policyService, - logService + logService, + sendApiService ); super.onSuccessfulLoad = async () => { this.selectType(this.type); diff --git a/apps/browser/src/vault/background/service_factories/cipher-service.factory.ts b/apps/browser/src/vault/background/service_factories/cipher-service.factory.ts index ad2259f1415..fb677ff115e 100644 --- a/apps/browser/src/vault/background/service_factories/cipher-service.factory.ts +++ b/apps/browser/src/vault/background/service_factories/cipher-service.factory.ts @@ -6,6 +6,10 @@ import { apiServiceFactory, ApiServiceInitOptions, } from "../../../background/service_factories/api-service.factory"; +import { + CipherFileUploadServiceInitOptions, + cipherFileUploadServiceFactory, +} from "../../../background/service_factories/cipher-file-upload-service.factory"; import { cryptoServiceFactory, CryptoServiceInitOptions, @@ -19,10 +23,6 @@ import { factory, FactoryOptions, } from "../../../background/service_factories/factory-options"; -import { - FileUploadServiceInitOptions, - fileUploadServiceFactory, -} from "../../../background/service_factories/file-upload-service.factory"; import { i18nServiceFactory, I18nServiceInitOptions, @@ -50,7 +50,7 @@ export type CipherServiceInitOptions = CipherServiceFactoryOptions & CryptoServiceInitOptions & SettingsServiceInitOptions & ApiServiceInitOptions & - FileUploadServiceInitOptions & + CipherFileUploadServiceInitOptions & I18nServiceInitOptions & LogServiceInitOptions & StateServiceInitOptions & @@ -69,14 +69,14 @@ export function cipherServiceFactory( await cryptoServiceFactory(cache, opts), await settingsServiceFactory(cache, opts), await apiServiceFactory(cache, opts), - await fileUploadServiceFactory(cache, opts), await i18nServiceFactory(cache, opts), opts.cipherServiceOptions?.searchServiceFactory === undefined ? () => cache.searchService as SearchService : opts.cipherServiceOptions.searchServiceFactory, await logServiceFactory(cache, opts), await stateServiceFactory(cache, opts), - await encryptServiceFactory(cache, opts) + await encryptServiceFactory(cache, opts), + await cipherFileUploadServiceFactory(cache, opts) ) ); } diff --git a/apps/browser/src/vault/popup/components/vault/add-edit.component.html b/apps/browser/src/vault/popup/components/vault/add-edit.component.html index 75c1a8695c3..9deda95d365 100644 --- a/apps/browser/src/vault/popup/components/vault/add-edit.component.html +++ b/apps/browser/src/vault/popup/components/vault/add-edit.component.html @@ -228,7 +228,7 @@ type="text" name="Card.ExpYear" [(ngModel)]="cipher.card.expYear" - placeholder="{{ 'ex' | i18n }} {{ currentDate | date: 'yyyy' }}" + placeholder="{{ 'ex' | i18n }} {{ currentDate | date : 'yyyy' }}" [readonly]="!cipher.edit && editMode" />
@@ -470,7 +470,7 @@ class="box-content-row box-content-row-multi" appBoxRow *ngFor="let u of cipher.login.uris; let i = index; trackBy: trackByFunction" - attr.aria-label="{{ 'uriPosition' | i18n: i + 1 }}" + attr.aria-label="{{ 'uriPosition' | i18n : i + 1 }}" >
- + tab.url != null && tab.url !== "").map((tab) => tab.url); } - window.setTimeout(() => { - if (!this.editMode) { - if (this.cipher.name != null && this.cipher.name !== "") { - document.getElementById("loginUsername").focus(); - } else { - document.getElementById("name").focus(); - } - } - }, 200); + this.setFocus(); + + if (this.popupUtilsService.inTab(window)) { + this.popupUtilsService.enableCloseTabWarning(); + } } async load() { @@ -149,16 +148,23 @@ export class AddEditComponent extends BaseAddEditComponent { } async submit(): Promise { - if (await super.submit()) { - if (this.cloneMode) { - this.router.navigate(["/tabs/vault"]); - } else { - this.location.back(); - } + const success = await super.submit(); + if (!success) { + return false; + } + + if (this.popupUtilsService.inTab(window)) { + this.popupUtilsService.disableCloseTabWarning(); + this.messagingService.send("closeTab", { delay: 1000 }); return true; } - return false; + if (this.cloneMode) { + this.router.navigate(["/tabs/vault"]); + } else { + this.location.back(); + } + return true; } attachments() { @@ -184,6 +190,12 @@ export class AddEditComponent extends BaseAddEditComponent { cancel() { super.cancel(); + + if (this.popupUtilsService.inTab(window)) { + this.messagingService.send("closeTab"); + return; + } + this.location.back(); } @@ -235,4 +247,18 @@ export class AddEditComponent extends BaseAddEditComponent { : this.collections.filter((c) => (c as any).checked).map((c) => c.id), }); } + + private setFocus() { + window.setTimeout(() => { + if (this.editMode) { + return; + } + + if (this.cipher.name != null && this.cipher.name !== "") { + document.getElementById("loginUsername").focus(); + } else { + document.getElementById("name").focus(); + } + }, 200); + } } diff --git a/apps/browser/src/popup/vault/collections.component.html b/apps/browser/src/vault/popup/components/vault/collections.component.html similarity index 100% rename from apps/browser/src/popup/vault/collections.component.html rename to apps/browser/src/vault/popup/components/vault/collections.component.html diff --git a/apps/browser/src/popup/vault/collections.component.ts b/apps/browser/src/vault/popup/components/vault/collections.component.ts similarity index 90% rename from apps/browser/src/popup/vault/collections.component.ts rename to apps/browser/src/vault/popup/components/vault/collections.component.ts index 766b51e2ec9..3f61c1f23ff 100644 --- a/apps/browser/src/popup/vault/collections.component.ts +++ b/apps/browser/src/vault/popup/components/vault/collections.component.ts @@ -3,11 +3,11 @@ import { Component } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { first } from "rxjs/operators"; -import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/components/collections.component"; -import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; +import { CollectionsComponent as BaseCollectionsComponent } from "@bitwarden/angular/admin-console/components/collections.component"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; +import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @Component({ diff --git a/apps/browser/src/vault/popup/components/vault/current-tab.component.html b/apps/browser/src/vault/popup/components/vault/current-tab.component.html index f2cc0305720..bec06919433 100644 --- a/apps/browser/src/vault/popup/components/vault/current-tab.component.html +++ b/apps/browser/src/vault/popup/components/vault/current-tab.component.html @@ -36,27 +36,20 @@
- -

{{ "autofillPageLoadInfo" | i18n }}

+ +

{{ autofillCalloutText }}

-
- -

{{ "autofillSelectInfo" | i18n }}

-

{{ "typeLogins" | i18n }} diff --git a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts b/apps/browser/src/vault/popup/components/vault/current-tab.component.ts index 177c3124bbc..1a83142cf11 100644 --- a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts +++ b/apps/browser/src/vault/popup/components/vault/current-tab.component.ts @@ -5,10 +5,10 @@ import { debounceTime, takeUntil } from "rxjs/operators"; import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { Utils } from "@bitwarden/common/misc/utils"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service"; @@ -42,8 +42,8 @@ export class CurrentTabComponent implements OnInit, OnDestroy { loaded = false; isLoading = false; showOrganizations = false; - showTryAutofillOnPageLoad = false; - showSelectAutofillCallout = false; + showHowToAutofill = false; + autofillCalloutText: string; protected search$ = new Subject(); private destroy$ = new Subject(); @@ -103,10 +103,12 @@ export class CurrentTabComponent implements OnInit, OnDestroy { if (!this.syncService.syncInProgress) { await this.load(); + await this.setCallout(); } else { this.loadedTimeout = window.setTimeout(async () => { if (!this.isLoading) { await this.load(); + await this.setCallout(); } }, 5000); } @@ -115,10 +117,16 @@ export class CurrentTabComponent implements OnInit, OnDestroy { .pipe(debounceTime(500), takeUntil(this.destroy$)) .subscribe(() => this.searchVault()); - this.showTryAutofillOnPageLoad = - this.loginCiphers.length > 0 && - !(await this.stateService.getEnableAutoFillOnPageLoad()) && - !(await this.stateService.getDismissedAutofillCallout()); + // activate autofill on page load if policy is set + if (await this.stateService.getActivateAutoFillOnPageLoadFromPolicy()) { + await this.stateService.setEnableAutoFillOnPageLoad(true); + await this.stateService.setActivateAutoFillOnPageLoadFromPolicy(false); + this.platformUtilsService.showToast( + "info", + null, + this.i18nService.t("autofillPageLoadPolicyActivated") + ); + } } ngOnDestroy() { @@ -274,17 +282,32 @@ export class CurrentTabComponent implements OnInit, OnDestroy { this.isLoading = this.loaded = true; } - async setAutofillOnPageLoad() { - await this.stateService.setEnableAutoFillOnPageLoad(true); - this.platformUtilsService.showToast("success", null, this.i18nService.t("autofillTurnedOn")); - await this.fillCipher(this.loginCiphers[0], 3000); - await this.stateService.setDismissedAutofillCallout(true); - this.showTryAutofillOnPageLoad = false; + async goToSettings() { + this.router.navigate(["autofill"]); } - async notNow() { + async dismissCallout() { await this.stateService.setDismissedAutofillCallout(true); - this.showTryAutofillOnPageLoad = false; - this.showSelectAutofillCallout = true; + this.showHowToAutofill = false; + } + + private async setCallout() { + this.showHowToAutofill = + this.loginCiphers.length > 0 && + !(await this.stateService.getEnableAutoFillOnPageLoad()) && + !(await this.stateService.getDismissedAutofillCallout()); + + if (this.showHowToAutofill) { + const autofillCommand = await this.platformUtilsService.getAutofillKeyboardShortcut(); + await this.setAutofillCalloutText(autofillCommand); + } + } + + private setAutofillCalloutText(command: string) { + if (command) { + this.autofillCalloutText = this.i18nService.t("autofillSelectInfoWithCommand", command); + } else { + this.autofillCalloutText = this.i18nService.t("autofillSelectInfoWithoutCommand"); + } } } diff --git a/apps/browser/src/vault/popup/components/vault/password-history.component.html b/apps/browser/src/vault/popup/components/vault/password-history.component.html index 6286aa1022d..7d468c87f25 100644 --- a/apps/browser/src/vault/popup/components/vault/password-history.component.html +++ b/apps/browser/src/vault/popup/components/vault/password-history.component.html @@ -17,7 +17,7 @@ class="text monospaced no-ellipsis" [innerHTML]="h.password | colorPassword" > - {{ h.lastUsedDate | date: "medium" }} + {{ h.lastUsedDate | date : "medium" }}

diff --git a/apps/browser/src/vault/popup/components/vault/share.component.ts b/apps/browser/src/vault/popup/components/vault/share.component.ts index 23f5e91ca26..c7dde9ab78d 100644 --- a/apps/browser/src/vault/popup/components/vault/share.component.ts +++ b/apps/browser/src/vault/popup/components/vault/share.component.ts @@ -3,11 +3,11 @@ import { ActivatedRoute, Router } from "@angular/router"; import { first } from "rxjs/operators"; import { ShareComponent as BaseShareComponent } from "@bitwarden/angular/components/share.component"; -import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; +import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @Component({ diff --git a/apps/browser/src/vault/popup/components/vault/vault-filter.component.ts b/apps/browser/src/vault/popup/components/vault/vault-filter.component.ts index e40040c0521..a5eaa8bc383 100644 --- a/apps/browser/src/vault/popup/components/vault/vault-filter.component.ts +++ b/apps/browser/src/vault/popup/components/vault/vault-filter.component.ts @@ -6,10 +6,11 @@ import { first } from "rxjs/operators"; import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model"; import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service"; +import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; +import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { TreeNode } from "@bitwarden/common/models/domain/tree-node"; -import { CollectionView } from "@bitwarden/common/models/view/collection.view"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; @@ -72,6 +73,7 @@ export class VaultFilterComponent implements OnInit, OnDestroy { private allCiphers: CipherView[] = null; constructor( + private i18nService: I18nService, private cipherService: CipherService, private router: Router, private ngZone: NgZone, diff --git a/apps/browser/src/vault/popup/components/vault/vault-items.component.ts b/apps/browser/src/vault/popup/components/vault/vault-items.component.ts index b4141abbf33..2bc40d0d57a 100644 --- a/apps/browser/src/vault/popup/components/vault/vault-items.component.ts +++ b/apps/browser/src/vault/popup/components/vault/vault-items.component.ts @@ -6,13 +6,13 @@ import { first } from "rxjs/operators"; import { VaultItemsComponent as BaseVaultItemsComponent } from "@bitwarden/angular/vault/components/vault-items.component"; import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model"; import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service"; -import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; +import { CollectionService } from "@bitwarden/common/admin-console/abstractions/collection.service"; +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view"; import { TreeNode } from "@bitwarden/common/models/domain/tree-node"; -import { CollectionView } from "@bitwarden/common/models/view/collection.view"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { CipherType } from "@bitwarden/common/vault/enums/cipher-type"; diff --git a/apps/browser/src/vault/popup/components/vault/vault-select.component.ts b/apps/browser/src/vault/popup/components/vault/vault-select.component.ts index 2a0cd1b23e3..eb058913c78 100644 --- a/apps/browser/src/vault/popup/components/vault/vault-select.component.ts +++ b/apps/browser/src/vault/popup/components/vault/vault-select.component.ts @@ -16,12 +16,12 @@ import { import { BehaviorSubject, concatMap, map, merge, Observable, Subject, takeUntil } from "rxjs"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; +import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { isNotProviderUser, OrganizationService, -} from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; -import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; -import { Organization } from "@bitwarden/common/models/domain/organization"; +} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { VaultFilterService } from "../../../services/vault-filter.service"; diff --git a/apps/browser/src/vault/popup/components/vault/view.component.html b/apps/browser/src/vault/popup/components/vault/view.component.html index 6e6f2c6c89b..d33536fd36e 100644 --- a/apps/browser/src/vault/popup/components/vault/view.component.html +++ b/apps/browser/src/vault/popup/components/vault/view.component.html @@ -224,10 +224,10 @@ >{{ "number" | i18n }} {{ - cipher.card.maskedNumber | creditCardNumber: cipher.card.brand + cipher.card.maskedNumber | creditCardNumber : cipher.card.brand }} {{ - cipher.card.number | creditCardNumber: cipher.card.brand + cipher.card.number | creditCardNumber : cipher.card.brand }}
@@ -669,15 +669,15 @@