From 999ade9707f87b4fbe8d933f132c70092a695285 Mon Sep 17 00:00:00 2001 From: Kyle Denney <4227399+kdenney@users.noreply.github.com> Date: Wed, 20 Aug 2025 10:31:20 -0500 Subject: [PATCH 001/167] [PM-24552] - remove code for feature flag (#16022) --- .../providers/setup/setup.component.html | 64 +++++++------------ .../providers/setup/setup.component.ts | 21 +----- libs/common/src/enums/feature-flag.enum.ts | 2 - 3 files changed, 25 insertions(+), 62 deletions(-) diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup.component.html b/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup.component.html index 4c5a35ea58d..daae7e2ed2e 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup.component.html +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup.component.html @@ -12,50 +12,30 @@

{{ "setupProviderDesc" | i18n }}

- @if (!(requireProviderPaymentMethodDuringSetup$ | async)) { -

{{ "generalInformation" | i18n }}

-
-
- - {{ "providerName" | i18n }} - - -
-
- - {{ "billingEmail" | i18n }} - - {{ "providerBillingEmailHint" | i18n }} - -
+

{{ "billingInformation" | i18n }}

+
+
+ + {{ "providerName" | i18n }} + +
- - } @else { -

{{ "billingInformation" | i18n }}

-
-
- - {{ "providerName" | i18n }} - - -
-
- - {{ "billingEmail" | i18n }} - - {{ "providerBillingEmailHint" | i18n }} - -
+
+ + {{ "billingEmail" | i18n }} + + {{ "providerBillingEmailHint" | i18n }} +
-

{{ "paymentMethod" | i18n }}

- - - } +
+

{{ "paymentMethod" | i18n }}

+ + diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup.component.ts index 53b54e459ea..edad6616fb3 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup.component.ts @@ -3,7 +3,7 @@ import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core"; import { FormBuilder, Validators } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; -import { firstValueFrom, Subject, switchMap } from "rxjs"; +import { Subject, switchMap } from "rxjs"; import { first, takeUntil } from "rxjs/operators"; import { ManageTaxInformationComponent } from "@bitwarden/angular/billing/components"; @@ -11,8 +11,6 @@ import { ProviderApiServiceAbstraction } from "@bitwarden/common/admin-console/a import { ProviderSetupRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-setup.request"; import { PaymentMethodType } from "@bitwarden/common/billing/enums"; import { ExpandedTaxInfoUpdateRequest } from "@bitwarden/common/billing/models/request/expanded-tax-info-update.request"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { ProviderKey } from "@bitwarden/common/types/key"; @@ -41,10 +39,6 @@ export class SetupComponent implements OnInit, OnDestroy { private destroy$ = new Subject(); - requireProviderPaymentMethodDuringSetup$ = this.configService.getFeatureFlag$( - FeatureFlag.PM19956_RequireProviderPaymentMethodDuringSetup, - ); - constructor( private router: Router, private i18nService: I18nService, @@ -52,7 +46,6 @@ export class SetupComponent implements OnInit, OnDestroy { private keyService: KeyService, private syncService: SyncService, private validationService: ValidationService, - private configService: ConfigService, private providerApiService: ProviderApiServiceAbstraction, private formBuilder: FormBuilder, private toastService: ToastService, @@ -117,15 +110,9 @@ export class SetupComponent implements OnInit, OnDestroy { submit = async () => { try { - const requireProviderPaymentMethodDuringSetup = await firstValueFrom( - this.requireProviderPaymentMethodDuringSetup$, - ); - this.formGroup.markAllAsTouched(); - const paymentValid = requireProviderPaymentMethodDuringSetup - ? this.paymentComponent.validate() - : true; + const paymentValid = this.paymentComponent.validate(); const taxInformationValid = this.taxInformationComponent.validate(); if (!paymentValid || !taxInformationValid || !this.formGroup.valid) { @@ -152,9 +139,7 @@ export class SetupComponent implements OnInit, OnDestroy { request.taxInfo.city = taxInformation.city; request.taxInfo.state = taxInformation.state; - if (requireProviderPaymentMethodDuringSetup) { - request.paymentSource = await this.paymentComponent.tokenize(); - } + request.paymentSource = await this.paymentComponent.tokenize(); const provider = await this.providerApiService.postProviderSetup(this.providerId, request); diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 5a4e5ff5dde..81cc3b305dc 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -27,7 +27,6 @@ export enum FeatureFlag { TrialPaymentOptional = "PM-8163-trial-payment", PM12276_BreadcrumbEventLogs = "pm-12276-breadcrumbing-for-business-features", PM17772_AdminInitiatedSponsorships = "pm-17772-admin-initiated-sponsorships", - PM19956_RequireProviderPaymentMethodDuringSetup = "pm-19956-require-provider-payment-method-during-setup", UseOrganizationWarningsService = "use-organization-warnings-service", AllowTrialLengthZero = "pm-20322-allow-trial-length-0", PM21881_ManagePaymentDetailsOutsideCheckout = "pm-21881-manage-payment-details-outside-checkout", @@ -104,7 +103,6 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.TrialPaymentOptional]: FALSE, [FeatureFlag.PM12276_BreadcrumbEventLogs]: FALSE, [FeatureFlag.PM17772_AdminInitiatedSponsorships]: FALSE, - [FeatureFlag.PM19956_RequireProviderPaymentMethodDuringSetup]: FALSE, [FeatureFlag.UseOrganizationWarningsService]: FALSE, [FeatureFlag.AllowTrialLengthZero]: FALSE, [FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout]: FALSE, From c1fab79ae3146a520a1a4cb4924c96c244d45632 Mon Sep 17 00:00:00 2001 From: Konrad <11725227+mKoonrad@users.noreply.github.com> Date: Wed, 20 Aug 2025 18:09:19 +0200 Subject: [PATCH 002/167] [PM-24774] importTargetHint variable inflection fix (#16025) * Prepare full string * Format fix * Fix lint: Execute `npm run prettier` --------- Co-authored-by: Daniel James Smith <2670567+djsmith85@users.noreply.github.com> Co-authored-by: Daniel James Smith --- apps/browser/src/_locales/en/messages.json | 14 +++++--------- apps/desktop/src/locales/en/messages.json | 14 +++++--------- apps/web/src/locales/en/messages.json | 14 +++++--------- libs/importer/src/components/import.component.html | 4 +--- 4 files changed, 16 insertions(+), 30 deletions(-) diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 1c27fab6971..8390bc59633 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index d99d3686d12..83c021341b8 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index cdb6bdc1e7e..e60d81d1982 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -2051,15 +2051,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." diff --git a/libs/importer/src/components/import.component.html b/libs/importer/src/components/import.component.html index f6d6603dca9..d0107bb5808 100644 --- a/libs/importer/src/components/import.component.html +++ b/libs/importer/src/components/import.component.html @@ -54,9 +54,7 @@ {{ - "importTargetHint" - | i18n - : (organizationId ? ("collection" | i18n | lowercase) : ("folder" | i18n | lowercase)) + organizationId ? ("importTargetHintCollection" | i18n) : ("importTargetHintFolder" | i18n) }} From bcd73a9c00fba83725f0815e0083034e18ed1a8a Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Wed, 20 Aug 2025 18:18:59 +0200 Subject: [PATCH 003/167] Move auth key-generation-service imports (#16078) --- libs/common/src/auth/services/token.service.spec.ts | 2 +- libs/common/src/auth/services/token.service.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/common/src/auth/services/token.service.spec.ts b/libs/common/src/auth/services/token.service.spec.ts index 7ed375da377..7274954c950 100644 --- a/libs/common/src/auth/services/token.service.spec.ts +++ b/libs/common/src/auth/services/token.service.spec.ts @@ -8,13 +8,13 @@ import { firstValueFrom } from "rxjs"; import { LogoutReason } from "@bitwarden/auth/common"; import { FakeSingleUserStateProvider, FakeGlobalStateProvider } from "../../../spec"; +import { KeyGenerationService } from "../../key-management/crypto"; import { EncryptService } from "../../key-management/crypto/abstractions/encrypt.service"; import { VaultTimeout, VaultTimeoutAction, VaultTimeoutStringType, } from "../../key-management/vault-timeout"; -import { KeyGenerationService } from "../../platform/abstractions/key-generation.service"; import { LogService } from "../../platform/abstractions/log.service"; import { AbstractStorageService } from "../../platform/abstractions/storage.service"; import { StorageLocation } from "../../platform/enums"; diff --git a/libs/common/src/auth/services/token.service.ts b/libs/common/src/auth/services/token.service.ts index 80e61d4636f..21ccd672056 100644 --- a/libs/common/src/auth/services/token.service.ts +++ b/libs/common/src/auth/services/token.service.ts @@ -7,6 +7,7 @@ import { Opaque } from "type-fest"; // eslint-disable-next-line no-restricted-imports import { LogoutReason, decodeJwtTokenToJson } from "@bitwarden/auth/common"; +import { KeyGenerationService } from "../../key-management/crypto"; import { EncryptService } from "../../key-management/crypto/abstractions/encrypt.service"; import { EncString, EncryptedString } from "../../key-management/crypto/models/enc-string"; import { @@ -14,7 +15,6 @@ import { VaultTimeoutAction, VaultTimeoutStringType, } from "../../key-management/vault-timeout"; -import { KeyGenerationService } from "../../platform/abstractions/key-generation.service"; import { LogService } from "../../platform/abstractions/log.service"; import { AbstractStorageService } from "../../platform/abstractions/storage.service"; import { StorageLocation } from "../../platform/enums"; From 719a43d050333ab14d30e5cc0bb8416e42669559 Mon Sep 17 00:00:00 2001 From: Patrick-Pimentel-Bitwarden Date: Wed, 20 Aug 2025 12:42:16 -0400 Subject: [PATCH 004/167] Feat PM-19877 System Notification Processing (#15611) * feat(notification-processing): [PM-19877] System Notification Implementation - Minor changes to popup logic and removed content in login component. * docs(notification-processing): [PM-19877] System Notification Implementation - Added more docs. * docs(notification-processing): [PM-19877] System Notification Implementation - Added markdown document. * fix(notification-processing): [PM-19877] System Notification Implementation - Updated condition for if notification is supported. * fix(notification-processing): [PM-19877] System Notification Implementation - Updated services module with correct platform utils service. --- .../browser/src/background/idle.background.ts | 8 +-- .../browser/src/background/main.background.ts | 50 +++++++++++----- .../src/background/runtime.background.ts | 9 ++- .../actions/browser-actions.service.ts | 48 +++++++++++++++ .../src/platform/browser/from-chrome-event.ts | 6 +- ...oreground-server-notifications.service.ts} | 6 +- .../browser-platform-utils.service.spec.ts | 6 +- .../browser-platform-utils.service.ts | 2 +- .../browser-system-notification.service.ts | 60 +++++++++++++++++++ .../src/popup/services/services.module.ts | 22 +++++-- .../services/cli-platform-utils.service.ts | 2 +- apps/desktop/src/app/app.component.ts | 4 +- apps/desktop/src/app/services/init.service.ts | 4 +- .../electron-platform-utils.service.ts | 2 +- apps/web/src/app/app.component.ts | 12 ++-- apps/web/src/app/core/core.module.ts | 2 +- apps/web/src/app/core/init.service.ts | 6 +- .../app/core/web-platform-utils.service.ts | 2 +- .../permissions-webpush-connection.service.ts | 2 +- .../vault/individual-vault/vault.component.ts | 2 +- .../src/services/jslib-services.module.ts | 37 +++++++----- .../auth-request.service.abstraction.ts | 4 +- .../auth-request/auth-request-api.service.ts | 2 +- libs/common/src/enums/push-technology.enum.ts | 4 +- .../services/vault-timeout.service.spec.ts | 4 +- .../services/vault-timeout.service.ts | 2 +- .../abstractions/platform-utils.service.ts | 2 +- libs/common/src/platform/actions/README.md | 40 +++++++++++++ .../src/platform/actions/actions-service.ts | 6 ++ libs/common/src/platform/actions/index.ts | 1 + .../actions/unsupported-actions.service.ts | 7 +++ .../src/platform/notifications/index.ts | 1 - .../platform/server-notifications/index.ts | 1 + .../default-notifications.service.spec.ts | 16 ++--- .../default-server-notifications.service.ts} | 28 ++++----- .../internal/index.ts | 4 +- .../noop-server-notifications.service.ts} | 6 +- .../internal/signalr-connection.service.ts | 0 .../unsupported-webpush-connection.service.ts | 0 .../web-push-notifications-api.service.ts | 2 +- .../internal/web-push.request.ts | 0 .../internal/webpush-connection.service.ts | 0 .../websocket-webpush-connection.service.ts | 0 .../worker-webpush-connection.service.spec.ts | 0 .../worker-webpush-connection.service.ts | 4 +- .../server-notifications.service.ts} | 8 +-- .../src/platform/sync/core-sync.service.ts | 2 +- .../platform/system-notifications/index.ts | 1 + .../system-notifications.service.ts | 58 ++++++++++++++++++ ...nsupported-system-notifications.service.ts | 23 +++++++ ...ault-end-user-notification.service.spec.ts | 16 ++--- .../default-end-user-notification.service.ts | 4 +- .../services/default-task.service.spec.ts | 6 +- .../tasks/services/default-task.service.ts | 6 +- .../src/lock/components/lock.component.ts | 2 +- 55 files changed, 420 insertions(+), 132 deletions(-) create mode 100644 apps/browser/src/platform/actions/browser-actions.service.ts rename apps/browser/src/platform/notifications/{foreground-notifications.service.ts => foreground-server-notifications.service.ts} (80%) create mode 100644 apps/browser/src/platform/system-notifications/browser-system-notification.service.ts create mode 100644 libs/common/src/platform/actions/README.md create mode 100644 libs/common/src/platform/actions/actions-service.ts create mode 100644 libs/common/src/platform/actions/index.ts create mode 100644 libs/common/src/platform/actions/unsupported-actions.service.ts delete mode 100644 libs/common/src/platform/notifications/index.ts create mode 100644 libs/common/src/platform/server-notifications/index.ts rename libs/common/src/platform/{notifications => server-notifications}/internal/default-notifications.service.spec.ts (95%) rename libs/common/src/platform/{notifications/internal/default-notifications.service.ts => server-notifications/internal/default-server-notifications.service.ts} (91%) rename libs/common/src/platform/{notifications => server-notifications}/internal/index.ts (74%) rename libs/common/src/platform/{notifications/internal/noop-notifications.service.ts => server-notifications/internal/noop-server-notifications.service.ts} (74%) rename libs/common/src/platform/{notifications => server-notifications}/internal/signalr-connection.service.ts (100%) rename libs/common/src/platform/{notifications => server-notifications}/internal/unsupported-webpush-connection.service.ts (100%) rename libs/common/src/platform/{notifications => server-notifications}/internal/web-push-notifications-api.service.ts (94%) rename libs/common/src/platform/{notifications => server-notifications}/internal/web-push.request.ts (100%) rename libs/common/src/platform/{notifications => server-notifications}/internal/webpush-connection.service.ts (100%) rename libs/common/src/platform/{notifications => server-notifications}/internal/websocket-webpush-connection.service.ts (100%) rename libs/common/src/platform/{notifications => server-notifications}/internal/worker-webpush-connection.service.spec.ts (100%) rename libs/common/src/platform/{notifications => server-notifications}/internal/worker-webpush-connection.service.ts (98%) rename libs/common/src/platform/{notifications/notifications.service.ts => server-notifications/server-notifications.service.ts} (76%) create mode 100644 libs/common/src/platform/system-notifications/index.ts create mode 100644 libs/common/src/platform/system-notifications/system-notifications.service.ts create mode 100644 libs/common/src/platform/system-notifications/unsupported-system-notifications.service.ts diff --git a/apps/browser/src/background/idle.background.ts b/apps/browser/src/background/idle.background.ts index 5b3a7f7d163..81a869917a6 100644 --- a/apps/browser/src/background/idle.background.ts +++ b/apps/browser/src/background/idle.background.ts @@ -7,7 +7,7 @@ import { VaultTimeoutSettingsService, VaultTimeoutStringType, } from "@bitwarden/common/key-management/vault-timeout"; -import { NotificationsService } from "@bitwarden/common/platform/notifications"; +import { ServerNotificationsService } from "@bitwarden/common/platform/server-notifications"; const IdleInterval = 60 * 5; // 5 minutes @@ -18,7 +18,7 @@ export default class IdleBackground { constructor( private vaultTimeoutService: VaultTimeoutService, - private notificationsService: NotificationsService, + private serverNotificationsService: ServerNotificationsService, private accountService: AccountService, private vaultTimeoutSettingsService: VaultTimeoutSettingsService, ) { @@ -32,9 +32,9 @@ export default class IdleBackground { const idleHandler = (newState: string) => { if (newState === "active") { - this.notificationsService.reconnectFromActivity(); + this.serverNotificationsService.reconnectFromActivity(); } else { - this.notificationsService.disconnectFromInactivity(); + this.serverNotificationsService.disconnectFromInactivity(); } }; if (this.idle.onStateChanged && this.idle.setDetectionInterval) { diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 1558d9926fa..a5fb9397125 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -111,21 +111,22 @@ import { ObservableStorageService, } from "@bitwarden/common/platform/abstractions/storage.service"; import { SystemService as SystemServiceAbstraction } from "@bitwarden/common/platform/abstractions/system.service"; +import { ActionsService } from "@bitwarden/common/platform/actions/actions-service"; import { IpcService } from "@bitwarden/common/platform/ipc"; import { Message, MessageListener, MessageSender } from "@bitwarden/common/platform/messaging"; // eslint-disable-next-line no-restricted-imports -- Used for dependency creation import { SubjectMessageSender } from "@bitwarden/common/platform/messaging/internal"; import { Lazy } from "@bitwarden/common/platform/misc/lazy"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; -import { NotificationsService } from "@bitwarden/common/platform/notifications"; +import { ServerNotificationsService } from "@bitwarden/common/platform/server-notifications"; // eslint-disable-next-line no-restricted-imports -- Needed for service creation import { - DefaultNotificationsService, + DefaultServerNotificationsService, SignalRConnectionService, UnsupportedWebPushConnectionService, WebPushNotificationsApiService, WorkerWebPushConnectionService, -} from "@bitwarden/common/platform/notifications/internal"; +} from "@bitwarden/common/platform/server-notifications/internal"; import { AppIdService } from "@bitwarden/common/platform/services/app-id.service"; import { ConfigApiService } from "@bitwarden/common/platform/services/config/config-api.service"; import { DefaultConfigService } from "@bitwarden/common/platform/services/config/default-config.service"; @@ -164,6 +165,8 @@ import { WindowStorageService } from "@bitwarden/common/platform/storage/window- import { SyncService } from "@bitwarden/common/platform/sync"; // eslint-disable-next-line no-restricted-imports -- Needed for service creation import { DefaultSyncService } from "@bitwarden/common/platform/sync/internal"; +import { SystemNotificationsService } from "@bitwarden/common/platform/system-notifications/"; +import { UnsupportedSystemNotificationsService } from "@bitwarden/common/platform/system-notifications/unsupported-system-notifications.service"; import { DefaultThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; import { ApiService } from "@bitwarden/common/services/api.service"; import { AuditService } from "@bitwarden/common/services/audit.service"; @@ -264,6 +267,7 @@ import { InlineMenuFieldQualificationService } from "../autofill/services/inline import { SafariApp } from "../browser/safariApp"; import { BackgroundBrowserBiometricsService } from "../key-management/biometrics/background-browser-biometrics.service"; import VaultTimeoutService from "../key-management/vault-timeout/vault-timeout.service"; +import { BrowserActionsService } from "../platform/actions/browser-actions.service"; import { DefaultBadgeBrowserApi } from "../platform/badge/badge-browser-api"; import { BadgeService } from "../platform/badge/badge.service"; import { BrowserApi } from "../platform/browser/browser-api"; @@ -292,6 +296,7 @@ import { BackgroundMemoryStorageService } from "../platform/storage/background-m import { BrowserStorageServiceProvider } from "../platform/storage/browser-storage-service.provider"; import { OffscreenStorageService } from "../platform/storage/offscreen-storage.service"; import { SyncServiceListener } from "../platform/sync/sync-service.listener"; +import { BrowserSystemNotificationService } from "../platform/system-notifications/browser-system-notification.service"; import { fromChromeRuntimeMessaging } from "../platform/utils/from-chrome-runtime-messaging"; import { VaultFilterService } from "../vault/services/vault-filter.service"; @@ -337,7 +342,9 @@ export default class MainBackground { importService: ImportServiceAbstraction; exportService: VaultExportServiceAbstraction; searchService: SearchServiceAbstraction; - notificationsService: NotificationsService; + serverNotificationsService: ServerNotificationsService; + systemNotificationService: SystemNotificationsService; + actionsService: ActionsService; stateService: StateServiceAbstraction; userNotificationSettingsService: UserNotificationSettingsServiceAbstraction; autofillSettingsService: AutofillSettingsServiceAbstraction; @@ -439,7 +446,6 @@ export default class MainBackground { private webRequestBackground: WebRequestBackground; private syncTimeout: any; - private isSafari: boolean; private nativeMessagingBackground: NativeMessagingBackground; private popupViewCacheBackgroundService: PopupViewCacheBackgroundService; @@ -1109,7 +1115,18 @@ export default class MainBackground { this.webPushConnectionService = new UnsupportedWebPushConnectionService(); } - this.notificationsService = new DefaultNotificationsService( + this.actionsService = new BrowserActionsService(this.logService, this.platformUtilsService); + + if ("notifications" in chrome) { + this.systemNotificationService = new BrowserSystemNotificationService( + this.logService, + this.platformUtilsService, + ); + } else { + this.systemNotificationService = new UnsupportedSystemNotificationsService(); + } + + this.serverNotificationsService = new DefaultServerNotificationsService( this.logService, this.syncService, this.appIdService, @@ -1163,9 +1180,6 @@ export default class MainBackground { this.logService, ); - // Other fields - this.isSafari = this.platformUtilsService.isSafari(); - // Background this.fido2Background = new Fido2Background( @@ -1183,7 +1197,6 @@ export default class MainBackground { this, this.autofillService, this.platformUtilsService as BrowserPlatformUtilsService, - this.notificationsService, this.autofillSettingsService, this.processReloadService, this.environmentService, @@ -1222,7 +1235,7 @@ export default class MainBackground { this.apiService, this.organizationService, this.authService, - this.notificationsService, + this.serverNotificationsService, messageListener, ); @@ -1296,7 +1309,7 @@ export default class MainBackground { this.idleBackground = new IdleBackground( this.vaultTimeoutService, - this.notificationsService, + this.serverNotificationsService, this.accountService, this.vaultTimeoutSettingsService, ); @@ -1354,7 +1367,7 @@ export default class MainBackground { this.endUserNotificationService = new DefaultEndUserNotificationService( this.stateProvider, this.apiService, - this.notificationsService, + this.serverNotificationsService, this.authService, this.logService, ); @@ -1433,7 +1446,7 @@ export default class MainBackground { setTimeout(async () => { await this.fullSync(false); this.backgroundSyncService.init(); - this.notificationsService.startListening(); + this.serverNotificationsService.startListening(); this.taskService.listenForTaskNotifications(); this.endUserNotificationService.listenForEndUserNotifications(); @@ -1656,6 +1669,11 @@ export default class MainBackground { ); } + /** + * Opens the popup. + * + * @deprecated Migrating to the browser actions service. + */ async openPopup() { const browserAction = BrowserApi.getBrowserAction(); @@ -1664,7 +1682,7 @@ export default class MainBackground { return; } - if (this.isSafari) { + if (this.platformUtilsService.isSafari()) { await SafariApp.sendMessageToApp("showPopover", null, true); } } @@ -1691,7 +1709,9 @@ export default class MainBackground { /** * Opens the popup to the given page + * * @default ExtensionPageUrls.Index + * @deprecated Migrating to the browser actions service. */ async openTheExtensionToPage(url: ExtensionPageUrls = ExtensionPageUrls.Index) { const isValidUrl = Object.values(ExtensionPageUrls).includes(url); diff --git a/apps/browser/src/background/runtime.background.ts b/apps/browser/src/background/runtime.background.ts index 725ca1b2780..8a154c72bba 100644 --- a/apps/browser/src/background/runtime.background.ts +++ b/apps/browser/src/background/runtime.background.ts @@ -15,7 +15,6 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag import { MessageListener, isExternalMessage } from "@bitwarden/common/platform/messaging"; import { devFlagEnabled } from "@bitwarden/common/platform/misc/flags"; import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { NotificationsService } from "@bitwarden/common/platform/notifications"; import { CipherType } from "@bitwarden/common/vault/enums"; import { VaultMessages } from "@bitwarden/common/vault/enums/vault-messages.enum"; import { BiometricsCommands } from "@bitwarden/key-management"; @@ -46,7 +45,6 @@ export default class RuntimeBackground { private main: MainBackground, private autofillService: AutofillService, private platformUtilsService: BrowserPlatformUtilsService, - private notificationsService: NotificationsService, private autofillSettingsService: AutofillSettingsServiceAbstraction, private processReloadService: ProcessReloadServiceAbstraction, private environmentService: BrowserEnvironmentService, @@ -424,6 +422,11 @@ export default class RuntimeBackground { return await BrowserApi.tabsQuery({ url: `${urlObj.href}*` }); } + /** + * Opens the popup. + * + * @deprecated Migrating to the browser actions service. + */ private async openPopup() { await this.main.openPopup(); } @@ -450,7 +453,7 @@ export default class RuntimeBackground { /** Sends a message to each tab that the popup was opened */ private announcePopupOpen() { const announceToAllTabs = async () => { - const isOpen = await this.platformUtilsService.isViewOpen(); + const isOpen = await this.platformUtilsService.isPopupOpen(); const tabs = await this.getBwTabs(); if (isOpen && tabs.length > 0) { diff --git a/apps/browser/src/platform/actions/browser-actions.service.ts b/apps/browser/src/platform/actions/browser-actions.service.ts new file mode 100644 index 00000000000..112a76cbe3f --- /dev/null +++ b/apps/browser/src/platform/actions/browser-actions.service.ts @@ -0,0 +1,48 @@ +import { DeviceType } from "@bitwarden/common/enums"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { ActionsService } from "@bitwarden/common/platform/actions/actions-service"; +import { LogService } from "@bitwarden/logging"; + +import { SafariApp } from "../../browser/safariApp"; +import { BrowserApi } from "../browser/browser-api"; + +export class BrowserActionsService implements ActionsService { + constructor( + private logService: LogService, + private platformUtilsService: PlatformUtilsService, + ) {} + + async openPopup(): Promise { + const deviceType = this.platformUtilsService.getDevice(); + + try { + switch (deviceType) { + case DeviceType.FirefoxExtension: + case DeviceType.ChromeExtension: { + const browserAction = BrowserApi.getBrowserAction(); + + if ("openPopup" in browserAction && typeof browserAction.openPopup === "function") { + await browserAction.openPopup(); + return; + } else { + this.logService.warning( + `No openPopup function found on browser actions. On browser: ${deviceType} and manifest version: ${BrowserApi.manifestVersion}`, + ); + } + break; + } + case DeviceType.SafariExtension: + await SafariApp.sendMessageToApp("showPopover", null, true); + return; + default: + this.logService.warning( + `Tried to open the popup from an unsupported device type: ${deviceType}`, + ); + } + } catch (e) { + this.logService.error( + `Failed to open the popup on ${DeviceType[deviceType]} with manifest ${BrowserApi.manifestVersion} and error: ${e}`, + ); + } + } +} diff --git a/apps/browser/src/platform/browser/from-chrome-event.ts b/apps/browser/src/platform/browser/from-chrome-event.ts index 28e57f58132..e0cd7a10b83 100644 --- a/apps/browser/src/platform/browser/from-chrome-event.ts +++ b/apps/browser/src/platform/browser/from-chrome-event.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { Observable } from "rxjs"; import { BrowserApi } from "./browser-api"; @@ -26,13 +24,13 @@ export function fromChromeEvent( event: chrome.events.Event<(...args: T) => void>, ): Observable { return new Observable((subscriber) => { - const handler = (...args: T) => { + const handler = (...args: readonly unknown[]) => { if (chrome.runtime.lastError) { subscriber.error(chrome.runtime.lastError); return; } - subscriber.next(args); + subscriber.next(args as T); }; BrowserApi.addListener(event, handler); diff --git a/apps/browser/src/platform/notifications/foreground-notifications.service.ts b/apps/browser/src/platform/notifications/foreground-server-notifications.service.ts similarity index 80% rename from apps/browser/src/platform/notifications/foreground-notifications.service.ts rename to apps/browser/src/platform/notifications/foreground-server-notifications.service.ts index e7685d3fe50..6ab164d9c63 100644 --- a/apps/browser/src/platform/notifications/foreground-notifications.service.ts +++ b/apps/browser/src/platform/notifications/foreground-server-notifications.service.ts @@ -2,12 +2,12 @@ import { Observable, Subscription } from "rxjs"; import { NotificationResponse } from "@bitwarden/common/models/response/notification.response"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { NotificationsService } from "@bitwarden/common/platform/notifications"; +import { ServerNotificationsService } from "@bitwarden/common/platform/server-notifications"; import { UserId } from "@bitwarden/common/types/guid"; -// Eventually if we want to support listening to notifications from browser foreground we +// Eventually if we want to support listening to server notifications from browser foreground we // will only ever create a single SignalR connection, likely messaging to the background to reuse its connection. -export class ForegroundNotificationsService implements NotificationsService { +export class ForegroundServerNotificationsService implements ServerNotificationsService { notifications$: Observable; constructor(private readonly logService: LogService) { diff --git a/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.spec.ts b/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.spec.ts index f75e9cc29a5..f9a4221b3ef 100644 --- a/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.spec.ts +++ b/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.spec.ts @@ -150,7 +150,7 @@ describe("Browser Utils Service", () => { callback(undefined); }); - const isViewOpen = await browserPlatformUtilsService.isViewOpen(); + const isViewOpen = await browserPlatformUtilsService.isPopupOpen(); expect(isViewOpen).toBe(false); }); @@ -160,7 +160,7 @@ describe("Browser Utils Service", () => { callback(message.command === "checkVaultPopupHeartbeat"); }); - const isViewOpen = await browserPlatformUtilsService.isViewOpen(); + const isViewOpen = await browserPlatformUtilsService.isPopupOpen(); expect(isViewOpen).toBe(true); }); @@ -173,7 +173,7 @@ describe("Browser Utils Service", () => { callback(undefined); }); - const isViewOpen = await browserPlatformUtilsService.isViewOpen(); + const isViewOpen = await browserPlatformUtilsService.isPopupOpen(); expect(isViewOpen).toBe(false); diff --git a/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.ts b/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.ts index beac7616d8d..4c5869054b2 100644 --- a/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.ts +++ b/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.ts @@ -150,7 +150,7 @@ export abstract class BrowserPlatformUtilsService implements PlatformUtilsServic * message to the popup and waiting for a response. If a response is received, * the view is open. */ - async isViewOpen(): Promise { + async isPopupOpen(): Promise { if (this.isSafari()) { // Query views on safari since chrome.runtime.sendMessage does not timeout and will hang. return BrowserApi.isPopupOpen(); diff --git a/apps/browser/src/platform/system-notifications/browser-system-notification.service.ts b/apps/browser/src/platform/system-notifications/browser-system-notification.service.ts new file mode 100644 index 00000000000..26b49515b82 --- /dev/null +++ b/apps/browser/src/platform/system-notifications/browser-system-notification.service.ts @@ -0,0 +1,60 @@ +import { map, merge, Observable } from "rxjs"; + +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { + ButtonLocation, + SystemNotificationClearInfo, + SystemNotificationCreateInfo, + SystemNotificationEvent, + SystemNotificationsService, +} from "@bitwarden/common/platform/system-notifications/system-notifications.service"; + +import { fromChromeEvent } from "../browser/from-chrome-event"; + +export class BrowserSystemNotificationService implements SystemNotificationsService { + notificationClicked$: Observable; + + constructor( + private logService: LogService, + private platformUtilsService: PlatformUtilsService, + ) { + this.notificationClicked$ = merge( + fromChromeEvent(chrome.notifications.onButtonClicked).pipe( + map(([notificationId, buttonIndex]) => ({ + id: notificationId, + buttonIdentifier: buttonIndex, + })), + ), + fromChromeEvent(chrome.notifications.onClicked).pipe( + map(([notificationId]: [string]) => ({ + id: notificationId, + buttonIdentifier: ButtonLocation.NotificationButton, + })), + ), + ); + } + + async create(createInfo: SystemNotificationCreateInfo): Promise { + return new Promise((resolve) => { + chrome.notifications.create( + { + iconUrl: chrome.runtime.getURL("images/icon128.png"), + message: createInfo.body, + type: "basic", + title: createInfo.title, + buttons: createInfo.buttons.map((value) => ({ title: value.title })), + }, + (notificationId) => resolve(notificationId), + ); + }); + } + + async clear(clearInfo: SystemNotificationClearInfo): Promise { + chrome.notifications.clear(clearInfo.id); + } + + isSupported(): boolean { + return "notifications" in chrome; + } +} diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index f531ebd5ca7..358ed33408c 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -92,12 +92,13 @@ import { AbstractStorageService, ObservableStorageService, } from "@bitwarden/common/platform/abstractions/storage.service"; +import { ActionsService } from "@bitwarden/common/platform/actions"; import { Message, MessageListener, MessageSender } from "@bitwarden/common/platform/messaging"; // eslint-disable-next-line no-restricted-imports -- Used for dependency injection import { SubjectMessageSender } from "@bitwarden/common/platform/messaging/internal"; import { flagEnabled } from "@bitwarden/common/platform/misc/flags"; -import { NotificationsService } from "@bitwarden/common/platform/notifications"; import { TaskSchedulerService } from "@bitwarden/common/platform/scheduling"; +import { ServerNotificationsService } from "@bitwarden/common/platform/server-notifications"; import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service"; import { ContainerService } from "@bitwarden/common/platform/services/container.service"; import { DefaultSdkClientFactory } from "@bitwarden/common/platform/services/sdk/default-sdk-client-factory"; @@ -113,6 +114,7 @@ import { InlineDerivedStateProvider } from "@bitwarden/common/platform/state/imp import { PrimarySecondaryStorageService } from "@bitwarden/common/platform/storage/primary-secondary-storage.service"; import { WindowStorageService } from "@bitwarden/common/platform/storage/window-storage.service"; import { SyncService } from "@bitwarden/common/platform/sync"; +import { SystemNotificationsService } from "@bitwarden/common/platform/system-notifications/system-notifications.service"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { InternalSendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -160,13 +162,14 @@ import { InlineMenuFieldQualificationService } from "../../autofill/services/inl import { ForegroundBrowserBiometricsService } from "../../key-management/biometrics/foreground-browser-biometrics"; import { ExtensionLockComponentService } from "../../key-management/lock/services/extension-lock-component.service"; import { ForegroundVaultTimeoutService } from "../../key-management/vault-timeout/foreground-vault-timeout.service"; +import { BrowserActionsService } from "../../platform/actions/browser-actions.service"; import { BrowserApi } from "../../platform/browser/browser-api"; import { runInsideAngular } from "../../platform/browser/run-inside-angular.operator"; /* eslint-disable no-restricted-imports */ import { ZonedMessageListenerService } from "../../platform/browser/zoned-message-listener.service"; import { ChromeMessageSender } from "../../platform/messaging/chrome-message.sender"; /* eslint-enable no-restricted-imports */ -import { ForegroundNotificationsService } from "../../platform/notifications/foreground-notifications.service"; +import { ForegroundServerNotificationsService } from "../../platform/notifications/foreground-server-notifications.service"; import { OffscreenDocumentService } from "../../platform/offscreen-document/abstractions/offscreen-document"; import { DefaultOffscreenDocumentService } from "../../platform/offscreen-document/offscreen-document.service"; import { PopupCompactModeService } from "../../platform/popup/layout/popup-compact-mode.service"; @@ -184,6 +187,7 @@ import { ForegroundTaskSchedulerService } from "../../platform/services/task-sch import { BrowserStorageServiceProvider } from "../../platform/storage/browser-storage-service.provider"; import { ForegroundMemoryStorageService } from "../../platform/storage/foreground-memory-storage.service"; import { ForegroundSyncService } from "../../platform/sync/foreground-sync.service"; +import { BrowserSystemNotificationService } from "../../platform/system-notifications/browser-system-notification.service"; import { fromChromeRuntimeMessaging } from "../../platform/utils/from-chrome-runtime-messaging"; import { FilePopoutUtilsService } from "../../tools/popup/services/file-popout-utils.service"; import { Fido2UserVerificationService } from "../../vault/services/fido2-user-verification.service"; @@ -253,6 +257,11 @@ const safeProviders: SafeProvider[] = [ }, deps: [GlobalStateProvider], }), + safeProvider({ + provide: ActionsService, + useClass: BrowserActionsService, + deps: [LogService, PlatformUtilsService], + }), safeProvider({ provide: KeyService, useFactory: ( @@ -609,6 +618,11 @@ const safeProviders: SafeProvider[] = [ useClass: SsoUrlService, deps: [], }), + safeProvider({ + provide: SystemNotificationsService, + useClass: BrowserSystemNotificationService, + deps: [LogService, PlatformUtilsService], + }), safeProvider({ provide: LoginComponentService, useClass: ExtensionLoginComponentService, @@ -674,8 +688,8 @@ const safeProviders: SafeProvider[] = [ deps: [KeyService, MasterPasswordApiService, InternalMasterPasswordServiceAbstraction, WINDOW], }), safeProvider({ - provide: NotificationsService, - useClass: ForegroundNotificationsService, + provide: ServerNotificationsService, + useClass: ForegroundServerNotificationsService, deps: [LogService], }), safeProvider({ diff --git a/apps/cli/src/platform/services/cli-platform-utils.service.ts b/apps/cli/src/platform/services/cli-platform-utils.service.ts index 7bed495bbf5..9e02b9dcca9 100644 --- a/apps/cli/src/platform/services/cli-platform-utils.service.ts +++ b/apps/cli/src/platform/services/cli-platform-utils.service.ts @@ -75,7 +75,7 @@ export class CliPlatformUtilsService implements PlatformUtilsService { return false; } - isViewOpen() { + isPopupOpen() { return Promise.resolve(false); } diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts index 04651ed0c10..197290cf690 100644 --- a/apps/desktop/src/app/app.component.ts +++ b/apps/desktop/src/app/app.component.ts @@ -62,7 +62,7 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { SystemService } from "@bitwarden/common/platform/abstractions/system.service"; -import { NotificationsService } from "@bitwarden/common/platform/notifications"; +import { ServerNotificationsService } from "@bitwarden/common/platform/server-notifications"; import { StateEventRunnerService } from "@bitwarden/common/platform/state"; import { SyncService } from "@bitwarden/common/platform/sync"; import { UserId } from "@bitwarden/common/types/guid"; @@ -155,7 +155,7 @@ export class AppComponent implements OnInit, OnDestroy { private messagingService: MessagingService, private collectionService: CollectionService, private searchService: SearchService, - private notificationsService: NotificationsService, + private notificationsService: ServerNotificationsService, private platformUtilsService: PlatformUtilsService, private systemService: SystemService, private processReloadService: ProcessReloadServiceAbstraction, diff --git a/apps/desktop/src/app/services/init.service.ts b/apps/desktop/src/app/services/init.service.ts index 2c68821b6c7..6b511ff366d 100644 --- a/apps/desktop/src/app/services/init.service.ts +++ b/apps/desktop/src/app/services/init.service.ts @@ -13,7 +13,7 @@ import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platfor import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { SdkLoadService } from "@bitwarden/common/platform/abstractions/sdk/sdk-load.service"; import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service"; -import { NotificationsService } from "@bitwarden/common/platform/notifications"; +import { ServerNotificationsService } from "@bitwarden/common/platform/server-notifications"; import { ContainerService } from "@bitwarden/common/platform/services/container.service"; import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner"; import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service"; @@ -38,7 +38,7 @@ export class InitService { private i18nService: I18nServiceAbstraction, private eventUploadService: EventUploadServiceAbstraction, private twoFactorService: TwoFactorServiceAbstraction, - private notificationsService: NotificationsService, + private notificationsService: ServerNotificationsService, private platformUtilsService: PlatformUtilsServiceAbstraction, private stateService: StateServiceAbstraction, private keyService: KeyServiceAbstraction, diff --git a/apps/desktop/src/platform/services/electron-platform-utils.service.ts b/apps/desktop/src/platform/services/electron-platform-utils.service.ts index 43b867b7a68..23fb29e932a 100644 --- a/apps/desktop/src/platform/services/electron-platform-utils.service.ts +++ b/apps/desktop/src/platform/services/electron-platform-utils.service.ts @@ -59,7 +59,7 @@ export class ElectronPlatformUtilsService implements PlatformUtilsService { return ipc.platform.isMacAppStore; } - isViewOpen(): Promise { + isPopupOpen(): Promise { return Promise.resolve(false); } diff --git a/apps/web/src/app/app.component.ts b/apps/web/src/app/app.component.ts index ae20670c2dd..1cb95250611 100644 --- a/apps/web/src/app/app.component.ts +++ b/apps/web/src/app/app.component.ts @@ -22,7 +22,7 @@ import { ConfigService } from "@bitwarden/common/platform/abstractions/config/co import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { NotificationsService } from "@bitwarden/common/platform/notifications"; +import { ServerNotificationsService } from "@bitwarden/common/platform/server-notifications"; import { StateEventRunnerService } from "@bitwarden/common/platform/state"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; @@ -76,7 +76,7 @@ export class AppComponent implements OnDestroy, OnInit { private keyService: KeyService, private collectionService: CollectionService, private searchService: SearchService, - private notificationsService: NotificationsService, + private serverNotificationsService: ServerNotificationsService, private stateService: StateService, private eventUploadService: EventUploadService, protected policyListService: PolicyListService, @@ -88,14 +88,14 @@ export class AppComponent implements OnDestroy, OnInit { private accountService: AccountService, private processReloadService: ProcessReloadServiceAbstraction, private deviceTrustToastService: DeviceTrustToastService, - private readonly destoryRef: DestroyRef, + private readonly destroy: DestroyRef, private readonly documentLangSetter: DocumentLangSetter, private readonly tokenService: TokenService, ) { this.deviceTrustToastService.setupListeners$.pipe(takeUntilDestroyed()).subscribe(); const langSubscription = this.documentLangSetter.start(); - this.destoryRef.onDestroy(() => langSubscription.unsubscribe()); + this.destroy.onDestroy(() => langSubscription.unsubscribe()); } ngOnInit() { @@ -347,9 +347,9 @@ export class AppComponent implements OnDestroy, OnInit { private idleStateChanged() { if (this.isIdle) { - this.notificationsService.disconnectFromInactivity(); + this.serverNotificationsService.disconnectFromInactivity(); } else { - this.notificationsService.reconnectFromActivity(); + this.serverNotificationsService.reconnectFromActivity(); } } } diff --git a/apps/web/src/app/core/core.module.ts b/apps/web/src/app/core/core.module.ts index a222b668043..965a9d5c99d 100644 --- a/apps/web/src/app/core/core.module.ts +++ b/apps/web/src/app/core/core.module.ts @@ -84,7 +84,7 @@ import { IpcService } from "@bitwarden/common/platform/ipc"; import { UnsupportedWebPushConnectionService, WebPushConnectionService, -} from "@bitwarden/common/platform/notifications/internal"; +} from "@bitwarden/common/platform/server-notifications/internal"; import { AppIdService as DefaultAppIdService } from "@bitwarden/common/platform/services/app-id.service"; import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service"; import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service"; diff --git a/apps/web/src/app/core/init.service.ts b/apps/web/src/app/core/init.service.ts index 57d9918aad7..a3358ff7253 100644 --- a/apps/web/src/app/core/init.service.ts +++ b/apps/web/src/app/core/init.service.ts @@ -12,7 +12,7 @@ import { DefaultVaultTimeoutService } from "@bitwarden/common/key-management/vau import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service"; import { SdkLoadService } from "@bitwarden/common/platform/abstractions/sdk/sdk-load.service"; import { IpcService } from "@bitwarden/common/platform/ipc"; -import { NotificationsService } from "@bitwarden/common/platform/notifications"; +import { ServerNotificationsService } from "@bitwarden/common/platform/server-notifications"; import { ContainerService } from "@bitwarden/common/platform/services/container.service"; import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner"; import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service"; @@ -26,7 +26,7 @@ import { VersionService } from "../platform/version.service"; export class InitService { constructor( @Inject(WINDOW) private win: Window, - private notificationsService: NotificationsService, + private serverNotificationsService: ServerNotificationsService, private vaultTimeoutService: DefaultVaultTimeoutService, private i18nService: I18nServiceAbstraction, private eventUploadService: EventUploadServiceAbstraction, @@ -56,7 +56,7 @@ export class InitService { await this.userAutoUnlockKeyService.setUserKeyInMemoryIfAutoUserKeySet(activeAccount.id); } - this.notificationsService.startListening(); + this.serverNotificationsService.startListening(); await this.vaultTimeoutService.init(true); await this.i18nService.init(); (this.eventUploadService as EventUploadService).init(true); diff --git a/apps/web/src/app/core/web-platform-utils.service.ts b/apps/web/src/app/core/web-platform-utils.service.ts index c3d1f5e3c1a..ada0b09aa17 100644 --- a/apps/web/src/app/core/web-platform-utils.service.ts +++ b/apps/web/src/app/core/web-platform-utils.service.ts @@ -98,7 +98,7 @@ export class WebPlatformUtilsService implements PlatformUtilsService { return false; } - isViewOpen(): Promise { + isPopupOpen(): Promise { return Promise.resolve(false); } diff --git a/apps/web/src/app/platform/notifications/permissions-webpush-connection.service.ts b/apps/web/src/app/platform/notifications/permissions-webpush-connection.service.ts index 44866285251..c0bc9ed3e77 100644 --- a/apps/web/src/app/platform/notifications/permissions-webpush-connection.service.ts +++ b/apps/web/src/app/platform/notifications/permissions-webpush-connection.service.ts @@ -5,7 +5,7 @@ import { SupportStatus } from "@bitwarden/common/platform/misc/support-status"; import { WebPushConnector, WorkerWebPushConnectionService, -} from "@bitwarden/common/platform/notifications/internal"; +} from "@bitwarden/common/platform/server-notifications/internal"; import { UserId } from "@bitwarden/common/types/guid"; export class PermissionsWebPushConnectionService extends WorkerWebPushConnectionService { diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index 658f829128d..ca8b05c2701 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -565,7 +565,7 @@ export class VaultComponent implements OnInit, OnDestr this.refreshing = false; // Explicitly mark for check to ensure the view is updated - // Some sources are not always emitted within the Angular zone (e.g. ciphers updated via WS notifications) + // Some sources are not always emitted within the Angular zone (e.g. ciphers updated via WS server notifications) this.changeDetectorRef.markForCheck(); }, ); diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index d6e4e901b50..50d1c477c96 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -196,24 +196,26 @@ import { SdkService } from "@bitwarden/common/platform/abstractions/sdk/sdk.serv import { StateService as StateServiceAbstraction } from "@bitwarden/common/platform/abstractions/state.service"; import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service"; import { ValidationService as ValidationServiceAbstraction } from "@bitwarden/common/platform/abstractions/validation.service"; +import { ActionsService } from "@bitwarden/common/platform/actions"; +import { UnsupportedActionsService } from "@bitwarden/common/platform/actions/unsupported-actions.service"; import { Message, MessageListener, MessageSender } from "@bitwarden/common/platform/messaging"; // eslint-disable-next-line no-restricted-imports -- Used for dependency injection import { SubjectMessageSender } from "@bitwarden/common/platform/messaging/internal"; import { devFlagEnabled } from "@bitwarden/common/platform/misc/flags"; -import { NotificationsService } from "@bitwarden/common/platform/notifications"; -// eslint-disable-next-line no-restricted-imports -- Needed for service creation -import { - DefaultNotificationsService, - NoopNotificationsService, - SignalRConnectionService, - UnsupportedWebPushConnectionService, - WebPushConnectionService, - WebPushNotificationsApiService, -} from "@bitwarden/common/platform/notifications/internal"; import { DefaultTaskSchedulerService, TaskSchedulerService, } from "@bitwarden/common/platform/scheduling"; +import { ServerNotificationsService } from "@bitwarden/common/platform/server-notifications"; +// eslint-disable-next-line no-restricted-imports -- Needed for service creation +import { + DefaultServerNotificationsService, + NoopServerNotificationsService, + SignalRConnectionService, + UnsupportedWebPushConnectionService, + WebPushConnectionService, + WebPushNotificationsApiService, +} from "@bitwarden/common/platform/server-notifications/internal"; import { AppIdService } from "@bitwarden/common/platform/services/app-id.service"; import { ConfigApiService } from "@bitwarden/common/platform/services/config/config-api.service"; import { DefaultConfigService } from "@bitwarden/common/platform/services/config/default-config.service"; @@ -919,10 +921,15 @@ const safeProviders: SafeProvider[] = [ deps: [], }), safeProvider({ - provide: NotificationsService, + provide: ActionsService, + useClass: UnsupportedActionsService, + deps: [], + }), + safeProvider({ + provide: ServerNotificationsService, useClass: devFlagEnabled("noopNotifications") - ? NoopNotificationsService - : DefaultNotificationsService, + ? NoopServerNotificationsService + : DefaultServerNotificationsService, deps: [ LogService, SyncService, @@ -1513,7 +1520,7 @@ const safeProviders: SafeProvider[] = [ ApiServiceAbstraction, OrganizationServiceAbstraction, AuthServiceAbstraction, - NotificationsService, + ServerNotificationsService, MessageListener, ], }), @@ -1523,7 +1530,7 @@ const safeProviders: SafeProvider[] = [ deps: [ StateProvider, ApiServiceAbstraction, - NotificationsService, + ServerNotificationsService, AuthServiceAbstraction, LogService, ], diff --git a/libs/auth/src/common/abstractions/auth-request.service.abstraction.ts b/libs/auth/src/common/abstractions/auth-request.service.abstraction.ts index 9eea3fe7bb0..10cc643fd45 100644 --- a/libs/auth/src/common/abstractions/auth-request.service.abstraction.ts +++ b/libs/auth/src/common/abstractions/auth-request.service.abstraction.ts @@ -109,9 +109,9 @@ export abstract class AuthRequestServiceAbstraction { ): Promise<{ masterKey: MasterKey; masterKeyHash: string }>; /** - * Handles incoming auth request push notifications. + * Handles incoming auth request push server notifications. * @param notification push notification. - * @remark We should only be receiving approved push notifications to prevent enumeration. + * @remark We should only be receiving approved push server notifications to prevent enumeration. */ abstract sendAuthRequestPushNotification(notification: AuthRequestPushNotification): void; diff --git a/libs/auth/src/common/services/auth-request/auth-request-api.service.ts b/libs/auth/src/common/services/auth-request/auth-request-api.service.ts index 15517a9a0e5..52c8cff1b7f 100644 --- a/libs/auth/src/common/services/auth-request/auth-request-api.service.ts +++ b/libs/auth/src/common/services/auth-request/auth-request-api.service.ts @@ -63,7 +63,7 @@ export class DefaultAuthRequestApiService implements AuthRequestApiServiceAbstra try { // Submit the current device identifier in the header as well as in the POST body. // The value in the header will be used to build the request context and ensure that the resulting - // notifications have the current device as a source. + // server notifications have the current device as a source. const response = await this.apiService.send( "POST", "/auth-requests/", diff --git a/libs/common/src/enums/push-technology.enum.ts b/libs/common/src/enums/push-technology.enum.ts index 1bc4e62cc9d..83de1f5849a 100644 --- a/libs/common/src/enums/push-technology.enum.ts +++ b/libs/common/src/enums/push-technology.enum.ts @@ -5,11 +5,11 @@ // eslint-disable-next-line @bitwarden/platform/no-enums export enum PushTechnology { /** - * Indicates that we should use SignalR over web sockets to receive push notifications from the server. + * Indicates that we should use SignalR over web sockets to receive push server notifications from the server. */ SignalR = 0, /** - * Indicatates that we should use WebPush to receive push notifications from the server. + * Indicates that we should use WebPush to receive push server notifications from the server. */ WebPush = 1, } diff --git a/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.spec.ts b/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.spec.ts index 26d263d7e72..da815f76f79 100644 --- a/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.spec.ts +++ b/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.spec.ts @@ -185,7 +185,7 @@ describe("VaultTimeoutService", () => { ), ); - platformUtilsService.isViewOpen.mockResolvedValue(globalSetups?.isViewOpen ?? false); + platformUtilsService.isPopupOpen.mockResolvedValue(globalSetups?.isViewOpen ?? false); vaultTimeoutSettingsService.getVaultTimeoutActionByUserId$.mockImplementation((userId) => { return new BehaviorSubject(accounts[userId]?.timeoutAction); @@ -225,7 +225,7 @@ describe("VaultTimeoutService", () => { it.each([AuthenticationStatus.Locked, AuthenticationStatus.LoggedOut])( "should not try to log out or lock any user that has authStatus === %s.", async (authStatus) => { - platformUtilsService.isViewOpen.mockResolvedValue(false); + platformUtilsService.isPopupOpen.mockResolvedValue(false); setupAccounts({ 1: { authStatus: authStatus, diff --git a/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.ts b/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.ts index 98f6f76fbe7..8b523498c31 100644 --- a/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.ts +++ b/libs/common/src/key-management/vault-timeout/services/vault-timeout.service.ts @@ -84,7 +84,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { async checkVaultTimeout(): Promise { // Get whether or not the view is open a single time so it can be compared for each user - const isViewOpen = await this.platformUtilsService.isViewOpen(); + const isViewOpen = await this.platformUtilsService.isPopupOpen(); await firstValueFrom( combineLatest([ diff --git a/libs/common/src/platform/abstractions/platform-utils.service.ts b/libs/common/src/platform/abstractions/platform-utils.service.ts index 7586da5a564..4d3f032052b 100644 --- a/libs/common/src/platform/abstractions/platform-utils.service.ts +++ b/libs/common/src/platform/abstractions/platform-utils.service.ts @@ -22,7 +22,7 @@ export abstract class PlatformUtilsService { abstract isVivaldi(): boolean; abstract isSafari(): boolean; abstract isMacAppStore(): boolean; - abstract isViewOpen(): Promise; + abstract isPopupOpen(): Promise; abstract launchUri(uri: string, options?: any): void; abstract getApplicationVersion(): Promise; abstract getApplicationVersionNumber(): Promise; diff --git a/libs/common/src/platform/actions/README.md b/libs/common/src/platform/actions/README.md new file mode 100644 index 00000000000..19165d88b56 --- /dev/null +++ b/libs/common/src/platform/actions/README.md @@ -0,0 +1,40 @@ +# Platform Actions API + +## ActionsService.openPopup() + +This document outlines the current behavior of `ActionsService.openPopup()` across different browsers, specifically in two contexts: + +- **Window Context**: When the call is triggered from an active browser window (e.g., from a tab's script). +- **Background Service Worker Context**: When the call is made from a background context, such as a service worker. + +The `openPopup()` method has limitations in some environments due to browser-specific restrictions or bugs. Below is a compatibility chart detailing the observed behavior. + +--- + +## Compatibility Table + +| Browser | Window Context | Background Service Worker Context | +| ------- | ------------------- | --------------------------------- | +| Safari | ✅ Works | ❌ Fails | +| Firefox | ❌ Fails | ❌ Fails | +| Chrome | ✅ Works | ✅ Works | +| Edge | 🟡 Untested | 🟡 Untested | +| Vivaldi | ⚠️ Ambiguous (Bug?) | ⚠️ Ambiguous (Bug?) | +| Opera | ✅ Works | ❌ Fails silently | + +--- + +## Notes + +- **Safari**: Only works when `openPopup()` is triggered from a window context. Attempts from background service workers fail. +- **Firefox**: Does not appear to support `openPopup()` in either context. +- **Chrome**: Fully functional in both contexts, but only on Mac. Windows it does not work in. +- **Edge**: Behavior has not been tested. +- **Vivaldi**: `openPopup()` results in an error that _might_ be related to running in a background context, but the cause is currently unclear. +- **Opera**: Works from window context. Background calls fail silently with no error message. + +--- + +## Summary + +When implementing `ActionsService.openPopup()`, prefer triggering it from a window context whenever possible to maximize cross-browser compatibility. Full background service worker support is only reliable in **Chrome**. diff --git a/libs/common/src/platform/actions/actions-service.ts b/libs/common/src/platform/actions/actions-service.ts new file mode 100644 index 00000000000..499f727ac81 --- /dev/null +++ b/libs/common/src/platform/actions/actions-service.ts @@ -0,0 +1,6 @@ +export abstract class ActionsService { + /** + * Opens the popup if it is supported. + */ + abstract openPopup(): Promise; +} diff --git a/libs/common/src/platform/actions/index.ts b/libs/common/src/platform/actions/index.ts new file mode 100644 index 00000000000..4c3a6f2bf23 --- /dev/null +++ b/libs/common/src/platform/actions/index.ts @@ -0,0 +1 @@ +export { ActionsService } from "./actions-service"; diff --git a/libs/common/src/platform/actions/unsupported-actions.service.ts b/libs/common/src/platform/actions/unsupported-actions.service.ts new file mode 100644 index 00000000000..15a8fa39261 --- /dev/null +++ b/libs/common/src/platform/actions/unsupported-actions.service.ts @@ -0,0 +1,7 @@ +import { ActionsService } from "./actions-service"; + +export class UnsupportedActionsService implements ActionsService { + openPopup(): Promise { + throw new Error("Open Popup unsupported."); + } +} diff --git a/libs/common/src/platform/notifications/index.ts b/libs/common/src/platform/notifications/index.ts deleted file mode 100644 index b1b842f5152..00000000000 --- a/libs/common/src/platform/notifications/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { NotificationsService } from "./notifications.service"; diff --git a/libs/common/src/platform/server-notifications/index.ts b/libs/common/src/platform/server-notifications/index.ts new file mode 100644 index 00000000000..a53fde948cf --- /dev/null +++ b/libs/common/src/platform/server-notifications/index.ts @@ -0,0 +1 @@ +export { ServerNotificationsService } from "./server-notifications.service"; diff --git a/libs/common/src/platform/notifications/internal/default-notifications.service.spec.ts b/libs/common/src/platform/server-notifications/internal/default-notifications.service.spec.ts similarity index 95% rename from libs/common/src/platform/notifications/internal/default-notifications.service.spec.ts rename to libs/common/src/platform/server-notifications/internal/default-notifications.service.spec.ts index 9dca079bdba..567e0fbfc3d 100644 --- a/libs/common/src/platform/notifications/internal/default-notifications.service.spec.ts +++ b/libs/common/src/platform/server-notifications/internal/default-notifications.service.spec.ts @@ -21,9 +21,9 @@ import { SupportStatus } from "../../misc/support-status"; import { SyncService } from "../../sync"; import { - DefaultNotificationsService, + DefaultServerNotificationsService, DISABLED_NOTIFICATIONS_URL, -} from "./default-notifications.service"; +} from "./default-server-notifications.service"; import { SignalRConnectionService, SignalRNotification } from "./signalr-connection.service"; import { WebPushConnectionService, WebPushConnector } from "./webpush-connection.service"; import { WorkerWebPushConnectionService } from "./worker-webpush-connection.service"; @@ -52,7 +52,7 @@ describe("NotificationsService", () => { notificationsUrl: string, ) => Subject; - let sut: DefaultNotificationsService; + let sut: DefaultServerNotificationsService; beforeEach(() => { syncService = mock(); @@ -93,7 +93,7 @@ describe("NotificationsService", () => { () => new Subject(), ); - sut = new DefaultNotificationsService( + sut = new DefaultServerNotificationsService( mock(), syncService, appIdService, @@ -134,7 +134,7 @@ describe("NotificationsService", () => { expect(actualNotification.type).toBe(expectedType); }; - it("emits notifications through WebPush when supported", async () => { + it("emits server notifications through WebPush when supported", async () => { const notificationsPromise = firstValueFrom(sut.notifications$.pipe(bufferCount(2))); emitActiveUser(mockUser1); @@ -227,7 +227,7 @@ describe("NotificationsService", () => { }); it.each([ - // Temporarily rolling back notifications being connected while locked + // Temporarily rolling back server notifications being connected while locked // { initialStatus: AuthenticationStatus.Locked, updatedStatus: AuthenticationStatus.Unlocked }, // { initialStatus: AuthenticationStatus.Unlocked, updatedStatus: AuthenticationStatus.Locked }, // { initialStatus: AuthenticationStatus.Locked, updatedStatus: AuthenticationStatus.Locked }, @@ -256,7 +256,7 @@ describe("NotificationsService", () => { ); it.each([ - // Temporarily disabling notifications connecting while in a locked state + // Temporarily disabling server notifications connecting while in a locked state // AuthenticationStatus.Locked, AuthenticationStatus.Unlocked, ])( @@ -282,7 +282,7 @@ describe("NotificationsService", () => { }, ); - it("does not connect to any notification stream when notifications are disabled through special url", () => { + it("does not connect to any notification stream when server notifications are disabled through special url", () => { const subscription = sut.notifications$.subscribe(); emitActiveUser(mockUser1); emitNotificationUrl(DISABLED_NOTIFICATIONS_URL); diff --git a/libs/common/src/platform/notifications/internal/default-notifications.service.ts b/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.ts similarity index 91% rename from libs/common/src/platform/notifications/internal/default-notifications.service.ts rename to libs/common/src/platform/server-notifications/internal/default-server-notifications.service.ts index ff22173a26e..4502d9663a3 100644 --- a/libs/common/src/platform/notifications/internal/default-notifications.service.ts +++ b/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.ts @@ -32,14 +32,14 @@ import { EnvironmentService } from "../../abstractions/environment.service"; import { LogService } from "../../abstractions/log.service"; import { MessagingService } from "../../abstractions/messaging.service"; import { supportSwitch } from "../../misc/support-status"; -import { NotificationsService as NotificationsServiceAbstraction } from "../notifications.service"; +import { ServerNotificationsService } from "../server-notifications.service"; import { ReceiveMessage, SignalRConnectionService } from "./signalr-connection.service"; import { WebPushConnectionService } from "./webpush-connection.service"; export const DISABLED_NOTIFICATIONS_URL = "http://-"; -export class DefaultNotificationsService implements NotificationsServiceAbstraction { +export class DefaultServerNotificationsService implements ServerNotificationsService { notifications$: Observable; private activitySubject = new BehaviorSubject<"active" | "inactive">("active"); @@ -61,7 +61,7 @@ export class DefaultNotificationsService implements NotificationsServiceAbstract distinctUntilChanged(), switchMap((activeAccountId) => { if (activeAccountId == null) { - // We don't emit notifications for inactive accounts currently + // We don't emit server-notifications for inactive accounts currently return EMPTY; } @@ -74,8 +74,8 @@ export class DefaultNotificationsService implements NotificationsServiceAbstract } /** - * Retrieves a stream of push notifications for the given user. - * @param userId The user id of the user to get the push notifications for. + * Retrieves a stream of push server notifications for the given user. + * @param userId The user id of the user to get the push server notifications for. */ private userNotifications$(userId: UserId) { return this.environmentService.environment$.pipe( @@ -109,7 +109,7 @@ export class DefaultNotificationsService implements NotificationsServiceAbstract }), supportSwitch({ supported: (service) => { - this.logService.info("Using WebPush for notifications"); + this.logService.info("Using WebPush for server notifications"); return service.notifications$.pipe( catchError((err: unknown) => { this.logService.warning("Issue with web push, falling back to SignalR", err); @@ -118,7 +118,7 @@ export class DefaultNotificationsService implements NotificationsServiceAbstract ); }, notSupported: () => { - this.logService.info("Using SignalR for notifications"); + this.logService.info("Using SignalR for server notifications"); return this.connectSignalR$(userId, notificationsUrl); }, }), @@ -188,7 +188,6 @@ export class DefaultNotificationsService implements NotificationsServiceAbstract case NotificationType.SyncCiphers: case NotificationType.SyncSettings: await this.syncService.fullSync(false); - break; case NotificationType.SyncOrganizations: // An organization update may not have bumped the user's account revision date, so force a sync @@ -214,11 +213,11 @@ export class DefaultNotificationsService implements NotificationsServiceAbstract await this.syncService.syncDeleteSend(notification.payload as SyncSendNotification); break; case NotificationType.AuthRequest: - { - this.messagingService.send("openLoginApproval", { - notificationId: notification.payload.id, - }); - } + // create notification + + this.messagingService.send("openLoginApproval", { + notificationId: notification.payload.id, + }); break; case NotificationType.SyncOrganizationStatusChanged: await this.syncService.fullSync(true); @@ -237,7 +236,8 @@ export class DefaultNotificationsService implements NotificationsServiceAbstract mergeMap(async ([notification, userId]) => this.processNotification(notification, userId)), ) .subscribe({ - error: (e: unknown) => this.logService.warning("Error in notifications$ observable", e), + error: (e: unknown) => + this.logService.warning("Error in server notifications$ observable", e), }); } diff --git a/libs/common/src/platform/notifications/internal/index.ts b/libs/common/src/platform/server-notifications/internal/index.ts similarity index 74% rename from libs/common/src/platform/notifications/internal/index.ts rename to libs/common/src/platform/server-notifications/internal/index.ts index 067320ee56c..daa89a79468 100644 --- a/libs/common/src/platform/notifications/internal/index.ts +++ b/libs/common/src/platform/server-notifications/internal/index.ts @@ -1,7 +1,7 @@ export * from "./worker-webpush-connection.service"; export * from "./signalr-connection.service"; -export * from "./default-notifications.service"; -export * from "./noop-notifications.service"; +export * from "./default-server-notifications.service"; +export * from "./noop-server-notifications.service"; export * from "./unsupported-webpush-connection.service"; export * from "./webpush-connection.service"; export * from "./websocket-webpush-connection.service"; diff --git a/libs/common/src/platform/notifications/internal/noop-notifications.service.ts b/libs/common/src/platform/server-notifications/internal/noop-server-notifications.service.ts similarity index 74% rename from libs/common/src/platform/notifications/internal/noop-notifications.service.ts rename to libs/common/src/platform/server-notifications/internal/noop-server-notifications.service.ts index 9c2435fb1a7..6a6bb9e19ed 100644 --- a/libs/common/src/platform/notifications/internal/noop-notifications.service.ts +++ b/libs/common/src/platform/server-notifications/internal/noop-server-notifications.service.ts @@ -4,16 +4,16 @@ import { NotificationResponse } from "@bitwarden/common/models/response/notifica import { UserId } from "@bitwarden/common/types/guid"; import { LogService } from "../../abstractions/log.service"; -import { NotificationsService } from "../notifications.service"; +import { ServerNotificationsService } from "../server-notifications.service"; -export class NoopNotificationsService implements NotificationsService { +export class NoopServerNotificationsService implements ServerNotificationsService { notifications$: Observable = new Subject(); constructor(private logService: LogService) {} startListening(): Subscription { this.logService.info( - "Initializing no-op notification service, no push notifications will be received", + "Initializing no-op notification service, no push server notifications will be received", ); return Subscription.EMPTY; } diff --git a/libs/common/src/platform/notifications/internal/signalr-connection.service.ts b/libs/common/src/platform/server-notifications/internal/signalr-connection.service.ts similarity index 100% rename from libs/common/src/platform/notifications/internal/signalr-connection.service.ts rename to libs/common/src/platform/server-notifications/internal/signalr-connection.service.ts diff --git a/libs/common/src/platform/notifications/internal/unsupported-webpush-connection.service.ts b/libs/common/src/platform/server-notifications/internal/unsupported-webpush-connection.service.ts similarity index 100% rename from libs/common/src/platform/notifications/internal/unsupported-webpush-connection.service.ts rename to libs/common/src/platform/server-notifications/internal/unsupported-webpush-connection.service.ts diff --git a/libs/common/src/platform/notifications/internal/web-push-notifications-api.service.ts b/libs/common/src/platform/server-notifications/internal/web-push-notifications-api.service.ts similarity index 94% rename from libs/common/src/platform/notifications/internal/web-push-notifications-api.service.ts rename to libs/common/src/platform/server-notifications/internal/web-push-notifications-api.service.ts index b824b8c7d65..891dab2c069 100644 --- a/libs/common/src/platform/notifications/internal/web-push-notifications-api.service.ts +++ b/libs/common/src/platform/server-notifications/internal/web-push-notifications-api.service.ts @@ -10,7 +10,7 @@ export class WebPushNotificationsApiService { ) {} /** - * Posts a device-user association to the server and ensures it's installed for push notifications + * Posts a device-user association to the server and ensures it's installed for push server notifications */ async putSubscription(pushSubscription: PushSubscriptionJSON): Promise { const request = WebPushRequest.from(pushSubscription); diff --git a/libs/common/src/platform/notifications/internal/web-push.request.ts b/libs/common/src/platform/server-notifications/internal/web-push.request.ts similarity index 100% rename from libs/common/src/platform/notifications/internal/web-push.request.ts rename to libs/common/src/platform/server-notifications/internal/web-push.request.ts diff --git a/libs/common/src/platform/notifications/internal/webpush-connection.service.ts b/libs/common/src/platform/server-notifications/internal/webpush-connection.service.ts similarity index 100% rename from libs/common/src/platform/notifications/internal/webpush-connection.service.ts rename to libs/common/src/platform/server-notifications/internal/webpush-connection.service.ts diff --git a/libs/common/src/platform/notifications/internal/websocket-webpush-connection.service.ts b/libs/common/src/platform/server-notifications/internal/websocket-webpush-connection.service.ts similarity index 100% rename from libs/common/src/platform/notifications/internal/websocket-webpush-connection.service.ts rename to libs/common/src/platform/server-notifications/internal/websocket-webpush-connection.service.ts diff --git a/libs/common/src/platform/notifications/internal/worker-webpush-connection.service.spec.ts b/libs/common/src/platform/server-notifications/internal/worker-webpush-connection.service.spec.ts similarity index 100% rename from libs/common/src/platform/notifications/internal/worker-webpush-connection.service.spec.ts rename to libs/common/src/platform/server-notifications/internal/worker-webpush-connection.service.spec.ts diff --git a/libs/common/src/platform/notifications/internal/worker-webpush-connection.service.ts b/libs/common/src/platform/server-notifications/internal/worker-webpush-connection.service.ts similarity index 98% rename from libs/common/src/platform/notifications/internal/worker-webpush-connection.service.ts rename to libs/common/src/platform/server-notifications/internal/worker-webpush-connection.service.ts index 528ad90ed61..d8a2c33568e 100644 --- a/libs/common/src/platform/notifications/internal/worker-webpush-connection.service.ts +++ b/libs/common/src/platform/server-notifications/internal/worker-webpush-connection.service.ts @@ -40,7 +40,7 @@ interface PushEvent { } /** - * An implementation for connecting to web push based notifications running in a Worker. + * An implementation for connecting to web push based server notifications running in a Worker. */ export class WorkerWebPushConnectionService implements WebPushConnectionService { private pushEvent = new Subject(); @@ -75,7 +75,7 @@ export class WorkerWebPushConnectionService implements WebPushConnectionService } supportStatus$(userId: UserId): Observable> { - // Check the server config to see if it supports sending WebPush notifications + // Check the server config to see if it supports sending WebPush server notifications // FIXME: get config of server for the specified userId, once ConfigService supports it return this.configService.serverConfig$.pipe( map((config) => diff --git a/libs/common/src/platform/notifications/notifications.service.ts b/libs/common/src/platform/server-notifications/server-notifications.service.ts similarity index 76% rename from libs/common/src/platform/notifications/notifications.service.ts rename to libs/common/src/platform/server-notifications/server-notifications.service.ts index 9e72b4de493..97431290d7a 100644 --- a/libs/common/src/platform/notifications/notifications.service.ts +++ b/libs/common/src/platform/server-notifications/server-notifications.service.ts @@ -4,20 +4,20 @@ import { NotificationResponse } from "@bitwarden/common/models/response/notifica import { UserId } from "@bitwarden/common/types/guid"; // eslint-disable-next-line @typescript-eslint/no-unused-vars -- Needed to link to API -import type { DefaultNotificationsService } from "./internal"; +import type { DefaultServerNotificationsService } from "./internal"; /** * A service offering abilities to interact with push notifications from the server. */ -export abstract class NotificationsService { +export abstract class ServerNotificationsService { /** * @deprecated This method should not be consumed, an observable to listen to server * notifications will be available one day but it is not ready to be consumed generally. - * Please add code reacting to notifications in {@link DefaultNotificationsService.processNotification} + * Please add code reacting to server notifications in {@link DefaultServerNotificationsService.processNotification} */ abstract notifications$: Observable; /** - * Starts automatic listening and processing of notifications, should only be called once per application, + * Starts automatic listening and processing of server notifications, should only be called once per application, * or you will risk notifications being processed multiple times. */ abstract startListening(): Subscription; diff --git a/libs/common/src/platform/sync/core-sync.service.ts b/libs/common/src/platform/sync/core-sync.service.ts index 45a127c599a..30831fd73ef 100644 --- a/libs/common/src/platform/sync/core-sync.service.ts +++ b/libs/common/src/platform/sync/core-sync.service.ts @@ -230,7 +230,7 @@ export abstract class CoreSyncService implements SyncService { }), ), ); - // Process only notifications for currently active user when user is not logged out + // Process only server notifications for currently active user when user is not logged out // TODO: once send service allows data manipulation of non-active users, this should process any received notification if (activeUserId === notification.userId && status !== AuthenticationStatus.LoggedOut) { try { diff --git a/libs/common/src/platform/system-notifications/index.ts b/libs/common/src/platform/system-notifications/index.ts new file mode 100644 index 00000000000..1209f1b42eb --- /dev/null +++ b/libs/common/src/platform/system-notifications/index.ts @@ -0,0 +1 @@ +export { SystemNotificationsService } from "./system-notifications.service"; diff --git a/libs/common/src/platform/system-notifications/system-notifications.service.ts b/libs/common/src/platform/system-notifications/system-notifications.service.ts new file mode 100644 index 00000000000..54369231967 --- /dev/null +++ b/libs/common/src/platform/system-notifications/system-notifications.service.ts @@ -0,0 +1,58 @@ +import { Observable } from "rxjs"; + +// This is currently tailored for chrome extension's api, if safari works +// differently where clicking a notification button produces a different +// identifier we need to reconcile that here. +export const ButtonLocation = Object.freeze({ + FirstOptionalButton: 0, // this is the first optional button we can set + SecondOptionalButton: 1, // this is the second optional button we can set + NotificationButton: 2, // this is when you click the notification as a whole +}); + +export type ButtonLocationKeys = (typeof ButtonLocation)[keyof typeof ButtonLocation]; + +export type SystemNotificationsButton = { + title: string; +}; + +export type SystemNotificationCreateInfo = { + id?: string; + title: string; + body: string; + buttons: SystemNotificationsButton[]; +}; + +export type SystemNotificationClearInfo = { + id: string; +}; + +export type SystemNotificationEvent = { + id: string; + buttonIdentifier: number; +}; + +/** + * A service responsible for displaying operating system level server notifications. + */ +export abstract class SystemNotificationsService { + abstract notificationClicked$: Observable; + + /** + * Creates a notification. + * @param createInfo + * @returns If a notification is successfully created it will respond back with an + * id that refers to a notification. + */ + abstract create(createInfo: SystemNotificationCreateInfo): Promise; + + /** + * Clears a notification. + * @param clearInfo Any info needed required to clear a notification. + */ + abstract clear(clearInfo: SystemNotificationClearInfo): Promise; + + /** + * Used to know if a given platform supports server notifications. + */ + abstract isSupported(): boolean; +} diff --git a/libs/common/src/platform/system-notifications/unsupported-system-notifications.service.ts b/libs/common/src/platform/system-notifications/unsupported-system-notifications.service.ts new file mode 100644 index 00000000000..b3627b2b07b --- /dev/null +++ b/libs/common/src/platform/system-notifications/unsupported-system-notifications.service.ts @@ -0,0 +1,23 @@ +import { throwError } from "rxjs"; + +import { + SystemNotificationClearInfo, + SystemNotificationCreateInfo, + SystemNotificationsService, +} from "./system-notifications.service"; + +export class UnsupportedSystemNotificationsService implements SystemNotificationsService { + notificationClicked$ = throwError(() => new Error("Notification clicked is not supported.")); + + async create(createInfo: SystemNotificationCreateInfo): Promise { + throw new Error("Create OS Notification unsupported."); + } + + clear(clearInfo: SystemNotificationClearInfo): Promise { + throw new Error("Clear OS Notification unsupported."); + } + + isSupported(): boolean { + return false; + } +} diff --git a/libs/common/src/vault/notifications/services/default-end-user-notification.service.spec.ts b/libs/common/src/vault/notifications/services/default-end-user-notification.service.spec.ts index 89a78d6f7d2..9eecf5eb496 100644 --- a/libs/common/src/vault/notifications/services/default-end-user-notification.service.spec.ts +++ b/libs/common/src/vault/notifications/services/default-end-user-notification.service.spec.ts @@ -4,7 +4,7 @@ import { firstValueFrom, of } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { NotificationsService } from "@bitwarden/common/platform/notifications"; +import { ServerNotificationsService } from "@bitwarden/common/platform/server-notifications"; import { StateProvider } from "@bitwarden/common/platform/state"; import { NotificationId, UserId } from "@bitwarden/common/types/guid"; @@ -20,7 +20,7 @@ import { describe("End User Notification Center Service", () => { let fakeStateProvider: FakeStateProvider; let mockApiService: jest.Mocked; - let mockNotificationsService: jest.Mocked; + let mockNotificationsService: jest.Mocked; let mockAuthService: jest.Mocked; let mockLogService: jest.Mocked; let service: DefaultEndUserNotificationService; @@ -48,7 +48,7 @@ describe("End User Notification Center Service", () => { }); describe("notifications$", () => { - it("should return notifications from state when not null", async () => { + it("should return server notifications from state when not null", async () => { fakeStateProvider.singleUser.mockFor("user-id" as UserId, NOTIFICATIONS, [ { id: "notification-id" as NotificationId, @@ -62,7 +62,7 @@ describe("End User Notification Center Service", () => { expect(mockLogService.warning).not.toHaveBeenCalled(); }); - it("should return notifications API when state is null", async () => { + it("should return server notifications API when state is null", async () => { mockApiService.send.mockResolvedValue({ data: [ { @@ -86,7 +86,7 @@ describe("End User Notification Center Service", () => { expect(mockLogService.warning).not.toHaveBeenCalled(); }); - it("should log a warning if there are more notifications available", async () => { + it("should log a warning if there are more server notifications available", async () => { mockApiService.send.mockResolvedValue({ data: [ ...new Array(DEFAULT_NOTIFICATION_PAGE_SIZE + 1).fill({ id: "notification-id" }), @@ -120,7 +120,7 @@ describe("End User Notification Center Service", () => { }); describe("unreadNotifications$", () => { - it("should return unread notifications from state when read value is null", async () => { + it("should return unread server notifications from state when read value is null", async () => { fakeStateProvider.singleUser.mockFor("user-id" as UserId, NOTIFICATIONS, [ { id: "notification-id" as NotificationId, @@ -136,7 +136,7 @@ describe("End User Notification Center Service", () => { }); describe("getNotifications", () => { - it("should call getNotifications returning notifications from API", async () => { + it("should call getNotifications returning server notifications from API", async () => { mockApiService.send.mockResolvedValue({ data: [ { @@ -156,7 +156,7 @@ describe("End User Notification Center Service", () => { ); }); - it("should update local state when notifications are updated", async () => { + it("should update local state when server notifications are updated", async () => { mockApiService.send.mockResolvedValue({ data: [ { diff --git a/libs/common/src/vault/notifications/services/default-end-user-notification.service.ts b/libs/common/src/vault/notifications/services/default-end-user-notification.service.ts index 87f97b48c27..e3be4c19b0a 100644 --- a/libs/common/src/vault/notifications/services/default-end-user-notification.service.ts +++ b/libs/common/src/vault/notifications/services/default-end-user-notification.service.ts @@ -6,7 +6,7 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authenticatio import { NotificationType } from "@bitwarden/common/enums"; import { ListResponse } from "@bitwarden/common/models/response/list.response"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { NotificationsService } from "@bitwarden/common/platform/notifications"; +import { ServerNotificationsService } from "@bitwarden/common/platform/server-notifications"; import { StateProvider } from "@bitwarden/common/platform/state"; import { NotificationId, UserId } from "@bitwarden/common/types/guid"; import { @@ -36,7 +36,7 @@ export class DefaultEndUserNotificationService implements EndUserNotificationSer constructor( private stateProvider: StateProvider, private apiService: ApiService, - private notificationService: NotificationsService, + private notificationService: ServerNotificationsService, private authService: AuthService, private logService: LogService, ) {} diff --git a/libs/common/src/vault/tasks/services/default-task.service.spec.ts b/libs/common/src/vault/tasks/services/default-task.service.spec.ts index a1f9872266e..df755dd9f90 100644 --- a/libs/common/src/vault/tasks/services/default-task.service.spec.ts +++ b/libs/common/src/vault/tasks/services/default-task.service.spec.ts @@ -8,7 +8,7 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authenticatio import { NotificationType } from "@bitwarden/common/enums"; import { NotificationResponse } from "@bitwarden/common/models/response/notification.response"; import { Message, MessageListener } from "@bitwarden/common/platform/messaging"; -import { NotificationsService } from "@bitwarden/common/platform/notifications"; +import { ServerNotificationsService } from "@bitwarden/common/platform/server-notifications"; import { SecurityTaskId, UserId } from "@bitwarden/common/types/guid"; import { FakeStateProvider, mockAccountServiceWith } from "../../../../spec"; @@ -39,7 +39,9 @@ describe("Default task service", () => { { send: mockApiSend } as unknown as ApiService, { organizations$: mockGetAllOrgs$ } as unknown as OrganizationService, { authStatuses$: mockAuthStatuses$.asObservable() } as unknown as AuthService, - { notifications$: mockNotifications$.asObservable() } as unknown as NotificationsService, + { + notifications$: mockNotifications$.asObservable(), + } as unknown as ServerNotificationsService, { allMessages$: mockMessages$.asObservable() } as unknown as MessageListener, ); }); diff --git a/libs/common/src/vault/tasks/services/default-task.service.ts b/libs/common/src/vault/tasks/services/default-task.service.ts index 35a7561d63d..6238076ccf5 100644 --- a/libs/common/src/vault/tasks/services/default-task.service.ts +++ b/libs/common/src/vault/tasks/services/default-task.service.ts @@ -17,7 +17,7 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authenticatio import { NotificationType } from "@bitwarden/common/enums"; import { ListResponse } from "@bitwarden/common/models/response/list.response"; import { MessageListener } from "@bitwarden/common/platform/messaging"; -import { NotificationsService } from "@bitwarden/common/platform/notifications"; +import { ServerNotificationsService } from "@bitwarden/common/platform/server-notifications"; import { StateProvider } from "@bitwarden/common/platform/state"; import { SecurityTaskId, UserId } from "@bitwarden/common/types/guid"; import { @@ -42,7 +42,7 @@ export class DefaultTaskService implements TaskService { private apiService: ApiService, private organizationService: OrganizationService, private authService: AuthService, - private notificationService: NotificationsService, + private notificationService: ServerNotificationsService, private messageListener: MessageListener, ) {} @@ -171,7 +171,7 @@ export class DefaultTaskService implements TaskService { } /** - * Creates a subscription for pending security task notifications or completed syncs for unlocked users. + * Creates a subscription for pending security task server notifications or completed syncs for unlocked users. */ listenForTaskNotifications(): Subscription { return this.authService.authStatuses$ diff --git a/libs/key-management-ui/src/lock/components/lock.component.ts b/libs/key-management-ui/src/lock/components/lock.component.ts index 92c8004e4c9..c7aa8969660 100644 --- a/libs/key-management-ui/src/lock/components/lock.component.ts +++ b/libs/key-management-ui/src/lock/components/lock.component.ts @@ -625,7 +625,7 @@ export class LockComponent implements OnInit, OnDestroy { } } - // Vault can be de-synced since notifications get ignored while locked. Need to check whether sync is required using the sync service. + // Vault can be de-synced since server notifications get ignored while locked. Need to check whether sync is required using the sync service. const startSync = new Date().getTime(); // TODO: This should probably not be blocking await this.syncService.fullSync(false); From 487a04f579ca7d7af17318be619532df3d2f495a Mon Sep 17 00:00:00 2001 From: Vicki League Date: Wed, 20 Aug 2025 13:41:39 -0400 Subject: [PATCH 005/167] [PM-25022] Fix squished avatar (#16097) --- libs/components/src/avatar/avatar.component.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/components/src/avatar/avatar.component.ts b/libs/components/src/avatar/avatar.component.ts index 59a9492f8c8..6f83c9ca101 100644 --- a/libs/components/src/avatar/avatar.component.ts +++ b/libs/components/src/avatar/avatar.component.ts @@ -7,11 +7,11 @@ import { Utils } from "@bitwarden/common/platform/misc/utils"; type SizeTypes = "xlarge" | "large" | "default" | "small" | "xsmall"; const SizeClasses: Record = { - xlarge: ["tw-h-24", "tw-w-24"], - large: ["tw-h-16", "tw-w-16"], - default: ["tw-h-10", "tw-w-10"], - small: ["tw-h-7", "tw-w-7"], - xsmall: ["tw-h-6", "tw-w-6"], + xlarge: ["tw-h-24", "tw-w-24", "tw-min-w-24"], + large: ["tw-h-16", "tw-w-16", "tw-min-w-16"], + default: ["tw-h-10", "tw-w-10", "tw-min-w-10"], + small: ["tw-h-7", "tw-w-7", "tw-min-w-7"], + xsmall: ["tw-h-6", "tw-w-6", "tw-min-w-6"], }; /** From 3901cf2859706b8994c3f362ad9ef343a7c74785 Mon Sep 17 00:00:00 2001 From: Bryan Cunningham Date: Wed, 20 Aug 2025 15:06:24 -0400 Subject: [PATCH 006/167] [CL-805] [CL-521] anon layout illustrations (#16002) * Add illustrations to anon layout * update ids and fill classes * Add illustrations to 404 page * update svg sizes * update logo size and placement to match loaded state * update anon layout logo size to match loading screens * update 404 logo size and spacing * update svgIcon imports * remove 404 footer * absolutely position svg to fix random positioning issues * update logo placement * add padding to battom of logo container * add back tw-link class * update anon layout padding --- apps/web/src/404.html | 217 ++++++++++++++++-- apps/web/src/app/app.component.html | 190 ++++++++++++++- apps/web/src/index.html | 190 ++++++++++++++- .../anon-layout/anon-layout.component.html | 21 +- .../src/anon-layout/anon-layout.component.ts | 5 + .../src/anon-layout/illustrations/index.ts | 2 + .../illustrations/left-illustration.ts | 5 + .../illustrations/right-illustration.ts | 5 + .../src/navigation/nav-logo.component.html | 4 +- 9 files changed, 610 insertions(+), 29 deletions(-) create mode 100644 libs/components/src/anon-layout/illustrations/index.ts create mode 100644 libs/components/src/anon-layout/illustrations/left-illustration.ts create mode 100644 libs/components/src/anon-layout/illustrations/right-illustration.ts diff --git a/apps/web/src/404.html b/apps/web/src/404.html index 75e4641a0cc..b3b5a5713ca 100644 --- a/apps/web/src/404.html +++ b/apps/web/src/404.html @@ -15,25 +15,206 @@ - - Bitwarden + + Bitwarden +
+
+

Sorry, this page isn't available.

-
-

Sorry, this page isn't available.

+

+ The link you followed may be broken, or the page may have been removed. Try going back to + the previous page or see our + Help Center + for more information. +

+ Go to your web vault +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + `; +
-

- The link you followed may be broken, or the page may have been removed. Try going back to - the previous page or see our - Help Center - for more information. -

- - Go to your web vault -
-
- -
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/apps/web/src/app/app.component.html b/apps/web/src/app/app.component.html index 471d89be1c1..638ad47fe4e 100644 --- a/apps/web/src/app/app.component.html +++ b/apps/web/src/app/app.component.html @@ -2,8 +2,10 @@ -
- Bitwarden +
+
+ Bitwarden +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + `; +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/apps/web/src/index.html b/apps/web/src/index.html index 1c81ae7a4e6..06f7587a123 100644 --- a/apps/web/src/index.html +++ b/apps/web/src/index.html @@ -16,8 +16,10 @@ -
- Bitwarden +
+
+ Bitwarden +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + `; +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
diff --git a/libs/components/src/anon-layout/anon-layout.component.html b/libs/components/src/anon-layout/anon-layout.component.html index e56c14165e4..4be11b607c6 100644 --- a/libs/components/src/anon-layout/anon-layout.component.html +++ b/libs/components/src/anon-layout/anon-layout.component.html @@ -1,5 +1,5 @@
@@ -20,11 +20,11 @@ -

+

{{ title() }}

-

+

{{ title() }}

@@ -33,7 +33,7 @@
@if (hideCardWrapper()) { @@ -62,6 +62,17 @@
{{ version }}
+ +
+ +
+
+ +
diff --git a/libs/components/src/anon-layout/anon-layout.component.ts b/libs/components/src/anon-layout/anon-layout.component.ts index 8b002cae7f0..c70ae1a8c90 100644 --- a/libs/components/src/anon-layout/anon-layout.component.ts +++ b/libs/components/src/anon-layout/anon-layout.component.ts @@ -21,6 +21,8 @@ import { AnonLayoutBitwardenShield } from "../icon/logos"; import { SharedModule } from "../shared"; import { TypographyModule } from "../typography"; +import { LeftIllustration, RightIllustration } from "./illustrations"; + export type AnonLayoutMaxWidth = "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl"; @Component({ @@ -35,6 +37,9 @@ export class AnonLayoutComponent implements OnInit, OnChanges { return ["tw-h-full"]; } + readonly leftIllustration = LeftIllustration; + readonly rightIllustration = RightIllustration; + readonly title = input(); readonly subtitle = input(); readonly icon = model(); diff --git a/libs/components/src/anon-layout/illustrations/index.ts b/libs/components/src/anon-layout/illustrations/index.ts new file mode 100644 index 00000000000..a107eb7cd15 --- /dev/null +++ b/libs/components/src/anon-layout/illustrations/index.ts @@ -0,0 +1,2 @@ +export * from "./left-illustration"; +export * from "./right-illustration"; diff --git a/libs/components/src/anon-layout/illustrations/left-illustration.ts b/libs/components/src/anon-layout/illustrations/left-illustration.ts new file mode 100644 index 00000000000..26fe9f6076b --- /dev/null +++ b/libs/components/src/anon-layout/illustrations/left-illustration.ts @@ -0,0 +1,5 @@ +import { svgIcon } from "../../icon"; + +export const LeftIllustration = svgIcon` + +`; diff --git a/libs/components/src/anon-layout/illustrations/right-illustration.ts b/libs/components/src/anon-layout/illustrations/right-illustration.ts new file mode 100644 index 00000000000..ba3003ee01f --- /dev/null +++ b/libs/components/src/anon-layout/illustrations/right-illustration.ts @@ -0,0 +1,5 @@ +import { svgIcon } from "../../icon"; + +export const RightIllustration = svgIcon` + +`; diff --git a/libs/components/src/navigation/nav-logo.component.html b/libs/components/src/navigation/nav-logo.component.html index fa59724aad5..89507503a41 100644 --- a/libs/components/src/navigation/nav-logo.component.html +++ b/libs/components/src/navigation/nav-logo.component.html @@ -1,9 +1,9 @@
Date: Wed, 20 Aug 2025 16:00:48 -0400 Subject: [PATCH 007/167] [CL-691] Update style of the menu component (#15890) --- .../product-switcher-content.component.html | 2 +- libs/components/src/menu/menu-divider.component.html | 2 +- libs/components/src/menu/menu.component.html | 2 +- libs/components/src/multi-select/scss/bw.theme.scss | 9 ++++++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.html b/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.html index 204737eee2e..aa853796971 100644 --- a/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.html +++ b/apps/web/src/app/layouts/product-switcher/product-switcher-content.component.html @@ -31,7 +31,7 @@
{{ "moreFromBitwarden" | i18n }} diff --git a/libs/components/src/menu/menu-divider.component.html b/libs/components/src/menu/menu-divider.component.html index 98048261cff..d3edb442ba6 100644 --- a/libs/components/src/menu/menu-divider.component.html +++ b/libs/components/src/menu/menu-divider.component.html @@ -1,5 +1,5 @@ diff --git a/libs/components/src/menu/menu.component.html b/libs/components/src/menu/menu.component.html index f5c60660775..38e9991f8ea 100644 --- a/libs/components/src/menu/menu.component.html +++ b/libs/components/src/menu/menu.component.html @@ -1,7 +1,7 @@
Date: Thu, 21 Aug 2025 09:45:49 +0200 Subject: [PATCH 008/167] Remove platform keygen service re-exports (#16081) --- libs/common/src/platform/abstractions/key-generation.service.ts | 2 -- libs/common/src/platform/services/key-generation.service.ts | 2 -- 2 files changed, 4 deletions(-) delete mode 100644 libs/common/src/platform/abstractions/key-generation.service.ts delete mode 100644 libs/common/src/platform/services/key-generation.service.ts diff --git a/libs/common/src/platform/abstractions/key-generation.service.ts b/libs/common/src/platform/abstractions/key-generation.service.ts deleted file mode 100644 index 8a230fb5b86..00000000000 --- a/libs/common/src/platform/abstractions/key-generation.service.ts +++ /dev/null @@ -1,2 +0,0 @@ -/** Temporary re-export. This should not be used for new imports */ -export { KeyGenerationService } from "../../key-management/crypto/key-generation/key-generation.service"; diff --git a/libs/common/src/platform/services/key-generation.service.ts b/libs/common/src/platform/services/key-generation.service.ts deleted file mode 100644 index 55d1f96e7df..00000000000 --- a/libs/common/src/platform/services/key-generation.service.ts +++ /dev/null @@ -1,2 +0,0 @@ -/** Temporary re-export. This should not be used for new imports */ -export { DefaultKeyGenerationService as KeyGenerationService } from "../../key-management/crypto/key-generation/default-key-generation.service"; From 89bae6bb74917fca420a91b4bec352eaa0de42c0 Mon Sep 17 00:00:00 2001 From: cyprain-okeke <108260115+cyprain-okeke@users.noreply.github.com> Date: Thu, 21 Aug 2025 10:25:48 +0100 Subject: [PATCH 009/167] Remove the VAT field for family plan (#16098) --- .../trial-initiation/trial-billing-step.component.html | 1 + .../trial-initiation/trial-billing-step.component.ts | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.html b/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.html index 64a9781b7cf..0c1a4270662 100644 --- a/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.html +++ b/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.html @@ -51,6 +51,7 @@

{{ "paymentType" | i18n }}

diff --git a/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.ts b/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.ts index e13fac41f75..7e25a422477 100644 --- a/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.ts +++ b/apps/web/src/app/billing/accounts/trial-initiation/trial-billing-step.component.ts @@ -259,6 +259,15 @@ export class TrialBillingStepComponent implements OnInit, OnDestroy { return planType ? this.applicablePlans.find((plan) => plan.type === planType) : null; } + protected get showTaxIdField(): boolean { + switch (this.organizationInfo.type) { + case ProductTierType.Families: + return false; + default: + return true; + } + } + private getBillingInformationFromTaxInfoComponent(): BillingInformation { return { postalCode: this.taxInfoComponent.getTaxInformation()?.postalCode, From 0daa6913d2f6529f489c5127c16215a1270f8fe5 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Thu, 21 Aug 2025 14:42:56 +0200 Subject: [PATCH 010/167] feat: add ipc service usage docs (#16000) --- libs/common/src/platform/ipc/ipc.service.ts | 123 +++++++++++++++++++- 1 file changed, 120 insertions(+), 3 deletions(-) diff --git a/libs/common/src/platform/ipc/ipc.service.ts b/libs/common/src/platform/ipc/ipc.service.ts index 2fba4380706..0da13c8f3d8 100644 --- a/libs/common/src/platform/ipc/ipc.service.ts +++ b/libs/common/src/platform/ipc/ipc.service.ts @@ -2,25 +2,136 @@ import { Observable, shareReplay } from "rxjs"; import { IpcClient, IncomingMessage, OutgoingMessage } from "@bitwarden/sdk-internal"; +/** + * Entry point for inter-process communication (IPC). + * + * - {@link IpcService.init} should be called in the initialization phase of the client. + * - This service owns the underlying {@link IpcClient} lifecycle and starts it during initialization. + * + * ## Usage + * + * ### Publish / Subscribe + * There are 2 main ways of sending and receiving messages over IPC in TypeScript: + * + * #### 1. TypeScript only JSON-based messages + * This is the simplest form of IPC, where messages are sent as untyped JSON objects. + * This is useful for simple message passing without the need for Rust code. + * + * ```typescript + * // Send a message + * await ipcService.send(OutgoingMessage.new_json_payload({ my: "data" }, "BrowserBackground", "my-topic")); + * + * // Receive messages + * ipcService.messages$.subscribe((message: IncomingMessage) => { + * if (message.topic === "my-topic") { + * const data = incomingMessage.parse_payload_as_json(); + * console.log("Received message:", data); + * } + * }); + * ``` + * + * #### 2. Rust compatible messages + * If you need to send messages that can also be handled by Rust code you can use typed Rust structs + * together with Rust functions to send and receive messages. For more information on typed structs + * refer to `TypedOutgoingMessage` and `TypedIncomingMessage` in the SDK. + * + * For examples on how to use the RPC framework with Rust see the section below. + * + * ### RPC (Request / Response) + * The RPC functionality is more complex than simple message passing and requires Rust code + * to send and receive calls. For this reason, the service also exposes the underlying + * {@link IpcClient} so it can be passed directly into Rust code. + * + * #### Rust code + * ```rust + * #[wasm_bindgen(js_name = ipcRegisterPingHandler)] + * pub async fn ipc_register_ping_handler(ipc_client: &JsIpcClient) { + * ipc_client + * .client + * // See Rust docs for more information on how to implement a handler + * .register_rpc_handler(PingHandler::new()) + * .await; + * } + * + * #[wasm_bindgen(js_name = ipcRequestPing)] + * pub async fn ipc_request_ping( + * ipc_client: &JsIpcClient, + * destination: Endpoint, + * abort_signal: Option, + * ) -> Result { + * ipc_client + * .client + * .request( + * PingRequest, + * destination, + * abort_signal.map(|c| c.to_cancellation_token()), + * ) + * .await + * } + * ``` + * + * #### TypeScript code + * ```typescript + * import { IpcService } from "@bitwarden/common/platform/ipc"; + * import { IpcClient, ipcRegisterPingHandler, ipcRequestPing } from "@bitwarden/sdk-internal"; + * + * class MyService { + * constructor(private ipcService: IpcService) {} + * + * async init() { + * await ipcRegisterPingHandler(this.ipcService.client); + * } + * + * async ping(destination: Endpoint): Promise { + * return await ipcRequestPing(this.ipcService.client, destination); + * } + * } + */ export abstract class IpcService { private _client?: IpcClient; + + /** + * Access to the underlying {@link IpcClient} for advanced/Rust RPC usage. + * + * @throws If the service has not been initialized. + */ get client(): IpcClient { if (!this._client) { - throw new Error("IpcService not initialized"); + throw new Error("IpcService not initialized. Call init() first."); } return this._client; } private _messages$?: Observable; - protected get messages$(): Observable { + + /** + * Hot stream of {@link IncomingMessage} from the IPC layer. + * + * @remarks + * - Uses `shareReplay({ bufferSize: 0, refCount: true })`, so no events are replayed to late subscribers. + * Subscribe early if you must not miss messages. + * + * @throws If the service has not been initialized. + */ + get messages$(): Observable { if (!this._messages$) { - throw new Error("IpcService not initialized"); + throw new Error("IpcService not initialized. Call init() first."); } return this._messages$; } + /** + * Initializes the service and starts the IPC client. + */ abstract init(): Promise; + /** + * Wires the provided {@link IpcClient}, starts it, and sets up the message stream. + * + * - Starts the client via `client.start()`. + * - Subscribes to the client's receive loop and exposes it through {@link messages$}. + * - Implementations may override `init` but should call this helper exactly once. + */ protected async initWithClient(client: IpcClient): Promise { this._client = client; await this._client.start(); @@ -47,6 +158,12 @@ export abstract class IpcService { }).pipe(shareReplay({ bufferSize: 0, refCount: true })); } + /** + * Sends an {@link OutgoingMessage} over IPC. + * + * @param message The message to send. + * @throws If the service is not initialized or the underlying client fails to send. + */ async send(message: OutgoingMessage) { await this.client.send(message); } From b0f46004ff0ef30323ff4a181178eae752543020 Mon Sep 17 00:00:00 2001 From: Bryan Cunningham Date: Thu, 21 Aug 2025 09:14:08 -0400 Subject: [PATCH 011/167] [CL-796] unrevert aria disabled buttons (#15924) * Use aria-disabled for button disabled state * remove import from testing story * use aria-disabled attr on bitLink button * remove unnecessary story attrs * remove disabled attr if on button element * create caprture click util * use caprture click util and fix tests * fix lint errors * fix event type * combine click capture and attr modification * fix lint error. Commit spec changes left out of last commit in error * inject element ref * move aria-disabled styles to common * move disabled logic into util * fix broken async actions stories * fix broken tests asserting disabled attr * have test check for string true vlalue * fix Signal type * fix form-field story import * remove injector left in error * aria-disable icon buttons * update form component css selector to look for aria-disabled buttons * use correct types. pass nativeElement directly * add JSDoc comment for util function * WIP * WIP * inject service in directive * remove console log * remove disabled attr left in error * update comments * remove unnecessary logic * remove :disabled psuedo selector as its apparently not needed * fix event type * coerce disabled attr to boolean * remove duplicate style concat left by conflict resolution * add back buttonStyles default * move reactive logic back to helper * add test to ensure menu button doesn't open when trigger is disabled * remove menu toggle to fix tests * remove disabled menu story * Fix usage of bitLink in verify email component * Update varaible name * no longer pass destroyRef --- .../vault-generator-dialog.component.spec.ts | 18 +++----- .../auth/settings/verify-email.component.html | 3 +- .../web-generator-dialog.component.spec.ts | 18 +++----- .../src/a11y/aria-disable.directive.ts | 12 ++++++ .../aria-disabled-click-capture.service.ts | 30 ++++++++++++++ libs/components/src/a11y/index.ts | 2 + .../src/button/button.component.spec.ts | 14 ++++--- .../components/src/button/button.component.ts | 41 +++++++++++++------ .../src/form-field/form-field.component.html | 2 +- .../src/icon-button/icon-button.component.ts | 29 ++++++++++--- libs/components/src/link/link.directive.ts | 20 ++++++++- .../src/menu/menu.component.spec.ts | 8 ++++ libs/components/src/toast/toast.stories.ts | 1 + .../src/utils/aria-disable-element.ts | 19 +++++++++ libs/components/src/utils/index.ts | 1 + 15 files changed, 165 insertions(+), 53 deletions(-) create mode 100644 libs/components/src/a11y/aria-disable.directive.ts create mode 100644 libs/components/src/a11y/aria-disabled-click-capture.service.ts create mode 100644 libs/components/src/utils/aria-disable-element.ts diff --git a/apps/browser/src/vault/popup/components/vault-v2/vault-generator-dialog/vault-generator-dialog.component.spec.ts b/apps/browser/src/vault/popup/components/vault-v2/vault-generator-dialog/vault-generator-dialog.component.spec.ts index b5d35e2005e..b65138dac3a 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/vault-generator-dialog/vault-generator-dialog.component.spec.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/vault-generator-dialog/vault-generator-dialog.component.spec.ts @@ -76,10 +76,8 @@ describe("VaultGeneratorDialogComponent", () => { component.onValueGenerated("test-password"); fixture.detectChanges(); - const button = fixture.debugElement.query( - By.css("[data-testid='select-button']"), - ).nativeElement; - expect(button.disabled).toBe(false); + const button = fixture.debugElement.query(By.css("[data-testid='select-button']")); + expect(button.attributes["aria-disabled"]).toBe(undefined); }); it("should disable the button if no value has been generated", () => { @@ -90,10 +88,8 @@ describe("VaultGeneratorDialogComponent", () => { generator.algorithmSelected.emit({ useGeneratedValue: "Use Password" } as any); fixture.detectChanges(); - const button = fixture.debugElement.query( - By.css("[data-testid='select-button']"), - ).nativeElement; - expect(button.disabled).toBe(true); + const button = fixture.debugElement.query(By.css("[data-testid='select-button']")); + expect(button.attributes["aria-disabled"]).toBe("true"); }); it("should disable the button if no algorithm is selected", () => { @@ -104,10 +100,8 @@ describe("VaultGeneratorDialogComponent", () => { generator.valueGenerated.emit("test-password"); fixture.detectChanges(); - const button = fixture.debugElement.query( - By.css("[data-testid='select-button']"), - ).nativeElement; - expect(button.disabled).toBe(true); + const button = fixture.debugElement.query(By.css("[data-testid='select-button']")); + expect(button.attributes["aria-disabled"]).toBe("true"); }); it("should update button text when algorithm is selected", () => { diff --git a/apps/web/src/app/auth/settings/verify-email.component.html b/apps/web/src/app/auth/settings/verify-email.component.html index a691c30695c..42a546fc281 100644 --- a/apps/web/src/app/auth/settings/verify-email.component.html +++ b/apps/web/src/app/auth/settings/verify-email.component.html @@ -4,10 +4,9 @@ id="sendBtn" bitLink linkType="secondary" - bitButton type="button" buttonType="unstyled" - [bitAction]="send" + (click)="send()" > {{ "sendEmail" | i18n }} diff --git a/apps/web/src/app/vault/components/web-generator-dialog/web-generator-dialog.component.spec.ts b/apps/web/src/app/vault/components/web-generator-dialog/web-generator-dialog.component.spec.ts index 085a3d0d4b0..afb32738901 100644 --- a/apps/web/src/app/vault/components/web-generator-dialog/web-generator-dialog.component.spec.ts +++ b/apps/web/src/app/vault/components/web-generator-dialog/web-generator-dialog.component.spec.ts @@ -70,10 +70,8 @@ describe("WebVaultGeneratorDialogComponent", () => { generator.valueGenerated.emit("test-password"); fixture.detectChanges(); - const button = fixture.debugElement.query( - By.css("[data-testid='select-button']"), - ).nativeElement; - expect(button.disabled).toBe(false); + const button = fixture.debugElement.query(By.css("[data-testid='select-button']")); + expect(button.attributes["aria-disabled"]).toBe(undefined); }); it("should disable the button if no value has been generated", () => { @@ -84,10 +82,8 @@ describe("WebVaultGeneratorDialogComponent", () => { generator.algorithmSelected.emit({ useGeneratedValue: "Use Password" } as any); fixture.detectChanges(); - const button = fixture.debugElement.query( - By.css("[data-testid='select-button']"), - ).nativeElement; - expect(button.disabled).toBe(true); + const button = fixture.debugElement.query(By.css("[data-testid='select-button']")); + expect(button.attributes["aria-disabled"]).toBe("true"); }); it("should disable the button if no algorithm is selected", () => { @@ -98,10 +94,8 @@ describe("WebVaultGeneratorDialogComponent", () => { generator.valueGenerated.emit("test-password"); fixture.detectChanges(); - const button = fixture.debugElement.query( - By.css("[data-testid='select-button']"), - ).nativeElement; - expect(button.disabled).toBe(true); + const button = fixture.debugElement.query(By.css("[data-testid='select-button']")); + expect(button.attributes["aria-disabled"]).toBe("true"); }); it("should close with selected value when confirmed", () => { diff --git a/libs/components/src/a11y/aria-disable.directive.ts b/libs/components/src/a11y/aria-disable.directive.ts new file mode 100644 index 00000000000..8236e178994 --- /dev/null +++ b/libs/components/src/a11y/aria-disable.directive.ts @@ -0,0 +1,12 @@ +import { Directive, inject } from "@angular/core"; + +import { AriaDisabledClickCaptureService } from "./aria-disabled-click-capture.service"; + +@Directive({ + host: { + "[attr.bit-aria-disable]": "true", + }, +}) +export class AriaDisableDirective { + protected ariaDisabledClickCaptureService = inject(AriaDisabledClickCaptureService); +} diff --git a/libs/components/src/a11y/aria-disabled-click-capture.service.ts b/libs/components/src/a11y/aria-disabled-click-capture.service.ts new file mode 100644 index 00000000000..d828d15c873 --- /dev/null +++ b/libs/components/src/a11y/aria-disabled-click-capture.service.ts @@ -0,0 +1,30 @@ +import { DOCUMENT } from "@angular/common"; +import { Injectable, Inject, NgZone, OnDestroy } from "@angular/core"; + +@Injectable({ providedIn: "root" }) +export class AriaDisabledClickCaptureService implements OnDestroy { + private listener!: (e: MouseEvent | KeyboardEvent) => void; + + constructor( + @Inject(DOCUMENT) private document: Document, + private ngZone: NgZone, + ) { + this.ngZone.runOutsideAngular(() => { + this.listener = (e: MouseEvent | KeyboardEvent) => { + const btn = (e.target as HTMLElement).closest( + '[aria-disabled="true"][bit-aria-disable="true"]', + ); + if (btn) { + e.stopPropagation(); + e.preventDefault(); + return false; + } + }; + this.document.addEventListener("click", this.listener, /* capture */ true); + }); + } + + ngOnDestroy() { + this.document.removeEventListener("click", this.listener, true); + } +} diff --git a/libs/components/src/a11y/index.ts b/libs/components/src/a11y/index.ts index 6090fb65d4e..2a723f14c93 100644 --- a/libs/components/src/a11y/index.ts +++ b/libs/components/src/a11y/index.ts @@ -1 +1,3 @@ export * from "./a11y-title.directive"; +export * from "./aria-disabled-click-capture.service"; +export * from "./aria-disable.directive"; diff --git a/libs/components/src/button/button.component.spec.ts b/libs/components/src/button/button.component.spec.ts index 6ddbc172803..1651b6cf12a 100644 --- a/libs/components/src/button/button.component.spec.ts +++ b/libs/components/src/button/button.component.spec.ts @@ -34,23 +34,25 @@ describe("Button", () => { expect(buttonDebugElement.nativeElement.disabled).toBeFalsy(); }); - it("should be disabled when disabled is true", () => { + it("should be aria-disabled and not html attribute disabled when disabled is true", () => { testAppComponent.disabled = true; fixture.detectChanges(); - - expect(buttonDebugElement.nativeElement.disabled).toBeTruthy(); + expect(buttonDebugElement.attributes["aria-disabled"]).toBe("true"); + expect(buttonDebugElement.nativeElement.disabled).toBeFalsy(); // Anchor tags cannot be disabled. }); - it("should be disabled when attribute disabled is true", () => { - expect(disabledButtonDebugElement.nativeElement.disabled).toBeTruthy(); + it("should be aria-disabled not html attribute disabled when attribute disabled is true", () => { + fixture.detectChanges(); + expect(disabledButtonDebugElement.attributes["aria-disabled"]).toBe("true"); + expect(disabledButtonDebugElement.nativeElement.disabled).toBeFalsy(); }); it("should be disabled when loading is true", () => { testAppComponent.loading = true; fixture.detectChanges(); - expect(buttonDebugElement.nativeElement.disabled).toBeTruthy(); + expect(buttonDebugElement.attributes["aria-disabled"]).toBe("true"); }); }); diff --git a/libs/components/src/button/button.component.ts b/libs/components/src/button/button.component.ts index 635c269bd0f..1dce792c963 100644 --- a/libs/components/src/button/button.component.ts +++ b/libs/components/src/button/button.component.ts @@ -1,9 +1,20 @@ import { NgClass } from "@angular/common"; -import { input, HostBinding, Component, model, computed, booleanAttribute } from "@angular/core"; +import { + input, + HostBinding, + Component, + model, + computed, + booleanAttribute, + inject, + ElementRef, +} from "@angular/core"; import { toObservable, toSignal } from "@angular/core/rxjs-interop"; import { debounce, interval } from "rxjs"; +import { AriaDisableDirective } from "../a11y"; import { ButtonLikeAbstraction, ButtonType, ButtonSize } from "../shared/button-like.abstraction"; +import { ariaDisableElement } from "../utils"; const focusRing = [ "focus-visible:tw-ring-2", @@ -50,9 +61,7 @@ const buttonStyles: Record = { templateUrl: "button.component.html", providers: [{ provide: ButtonLikeAbstraction, useExisting: ButtonComponent }], imports: [NgClass], - host: { - "[attr.disabled]": "disabledAttr()", - }, + hostDirectives: [AriaDisableDirective], }) export class ButtonComponent implements ButtonLikeAbstraction { @HostBinding("class") get classList() { @@ -72,14 +81,15 @@ export class ButtonComponent implements ButtonLikeAbstraction { .concat( this.showDisabledStyles() || this.disabled() ? [ - "disabled:tw-bg-secondary-300", - "disabled:hover:tw-bg-secondary-300", - "disabled:tw-border-secondary-300", - "disabled:hover:tw-border-secondary-300", - "disabled:!tw-text-muted", - "disabled:hover:!tw-text-muted", - "disabled:tw-cursor-not-allowed", - "disabled:hover:tw-no-underline", + "aria-disabled:!tw-bg-secondary-300", + "hover:tw-bg-secondary-300", + "aria-disabled:tw-border-secondary-300", + "hover:tw-border-secondary-300", + "aria-disabled:!tw-text-muted", + "hover:!tw-text-muted", + "aria-disabled:tw-cursor-not-allowed", + "hover:tw-no-underline", + "aria-disabled:tw-pointer-events-none", ] : [], ) @@ -88,7 +98,7 @@ export class ButtonComponent implements ButtonLikeAbstraction { protected disabledAttr = computed(() => { const disabled = this.disabled() != null && this.disabled() !== false; - return disabled || this.loading() ? true : null; + return disabled || this.loading(); }); /** @@ -128,4 +138,9 @@ export class ButtonComponent implements ButtonLikeAbstraction { ); disabled = model(false); + private el = inject(ElementRef); + + constructor() { + ariaDisableElement(this.el.nativeElement, this.disabledAttr); + } } diff --git a/libs/components/src/form-field/form-field.component.html b/libs/components/src/form-field/form-field.component.html index b40e16d4cd4..ae3bad40698 100644 --- a/libs/components/src/form-field/form-field.component.html +++ b/libs/components/src/form-field/form-field.component.html @@ -46,7 +46,7 @@
= { ], imports: [NgClass], host: { - "[attr.disabled]": "disabledAttr()", /** * When the `bitIconButton` input is dynamic from a consumer, Angular doesn't put the * `bitIconButton` attribute into the DOM. We use the attribute as a css selector in @@ -87,6 +97,7 @@ const sizes: Record = { */ "[attr.bitIconButton]": "icon()", }, + hostDirectives: [AriaDisableDirective], }) export class BitIconButtonComponent implements ButtonLikeAbstraction, FocusableElement { readonly icon = model.required({ alias: "bitIconButton" }); @@ -118,7 +129,7 @@ export class BitIconButtonComponent implements ButtonLikeAbstraction, FocusableE .concat(sizes[this.size()]) .concat( this.showDisabledStyles() || this.disabled() - ? ["disabled:tw-opacity-60", "disabled:hover:!tw-bg-transparent"] + ? ["aria-disabled:tw-opacity-60", "aria-disabled:hover:!tw-bg-transparent"] : [], ); } @@ -129,7 +140,7 @@ export class BitIconButtonComponent implements ButtonLikeAbstraction, FocusableE protected disabledAttr = computed(() => { const disabled = this.disabled() != null && this.disabled() !== false; - return disabled || this.loading() ? true : null; + return disabled || this.loading(); }); /** @@ -168,8 +179,14 @@ export class BitIconButtonComponent implements ButtonLikeAbstraction, FocusableE return this.elementRef.nativeElement; } - constructor(private elementRef: ElementRef) { - const originalTitle = this.elementRef.nativeElement.getAttribute("title"); + private elementRef = inject(ElementRef); + + constructor() { + const element = this.elementRef.nativeElement; + + ariaDisableElement(element, this.disabledAttr); + + const originalTitle = element.getAttribute("title"); effect(() => { setA11yTitleAndAriaLabel({ diff --git a/libs/components/src/link/link.directive.ts b/libs/components/src/link/link.directive.ts index f2eb44bc3a4..7c93b185a79 100644 --- a/libs/components/src/link/link.directive.ts +++ b/libs/components/src/link/link.directive.ts @@ -1,4 +1,7 @@ -import { input, HostBinding, Directive } from "@angular/core"; +import { input, HostBinding, Directive, inject, ElementRef, booleanAttribute } from "@angular/core"; + +import { AriaDisableDirective } from "../a11y"; +import { ariaDisableElement } from "../utils"; export type LinkType = "primary" | "secondary" | "contrast" | "light"; @@ -58,6 +61,11 @@ const commonStyles = [ "before:tw-transition", "focus-visible:before:tw-ring-2", "focus-visible:tw-z-10", + "aria-disabled:tw-no-underline", + "aria-disabled:tw-pointer-events-none", + "aria-disabled:!tw-text-secondary-300", + "aria-disabled:hover:!tw-text-secondary-300", + "aria-disabled:hover:tw-no-underline", ]; @Directive() @@ -86,11 +94,21 @@ export class AnchorLinkDirective extends LinkDirective { @Directive({ selector: "button[bitLink]", + hostDirectives: [AriaDisableDirective], }) export class ButtonLinkDirective extends LinkDirective { + private el = inject(ElementRef); + + disabled = input(false, { transform: booleanAttribute }); + @HostBinding("class") get classList() { return ["before:-tw-inset-y-[0.25rem]"] .concat(commonStyles) .concat(linkStyles[this.linkType()] ?? []); } + + constructor() { + super(); + ariaDisableElement(this.el.nativeElement, this.disabled); + } } diff --git a/libs/components/src/menu/menu.component.spec.ts b/libs/components/src/menu/menu.component.spec.ts index c6a54f1afae..3153fd4eb37 100644 --- a/libs/components/src/menu/menu.component.spec.ts +++ b/libs/components/src/menu/menu.component.spec.ts @@ -58,6 +58,14 @@ describe("Menu", () => { expect(getBitMenuPanel()).toBeFalsy(); }); + + it("should not open when the trigger button is disabled", () => { + const buttonDebugElement = fixture.debugElement.query(By.directive(MenuTriggerForDirective)); + buttonDebugElement.nativeElement.setAttribute("disabled", "true"); + (buttonDebugElement.nativeElement as HTMLButtonElement).click(); + + expect(getBitMenuPanel()).toBeFalsy(); + }); }); @Component({ diff --git a/libs/components/src/toast/toast.stories.ts b/libs/components/src/toast/toast.stories.ts index bd2c59a191b..dee31f1d6ac 100644 --- a/libs/components/src/toast/toast.stories.ts +++ b/libs/components/src/toast/toast.stories.ts @@ -20,6 +20,7 @@ const toastServiceExampleTemplate = ` @Component({ selector: "toast-service-example", template: toastServiceExampleTemplate, + imports: [ButtonModule], }) export class ToastServiceExampleComponent { @Input() diff --git a/libs/components/src/utils/aria-disable-element.ts b/libs/components/src/utils/aria-disable-element.ts new file mode 100644 index 00000000000..0f7fb4ca205 --- /dev/null +++ b/libs/components/src/utils/aria-disable-element.ts @@ -0,0 +1,19 @@ +import { Signal } from "@angular/core"; +import { toObservable, takeUntilDestroyed } from "@angular/core/rxjs-interop"; + +/** + * a11y helper util used to `aria-disable` elements as opposed to using the HTML `disabled` attr. + * - Removes HTML `disabled` attr and replaces it with `aria-disabled="true"` + */ +export function ariaDisableElement(el: HTMLElement, disabled: Signal) { + toObservable(disabled) + .pipe(takeUntilDestroyed()) + .subscribe((isDisabled) => { + if (isDisabled) { + el.removeAttribute("disabled"); + el.setAttribute("aria-disabled", "true"); + } else { + el.removeAttribute("aria-disabled"); + } + }); +} diff --git a/libs/components/src/utils/index.ts b/libs/components/src/utils/index.ts index afadd6b3b41..91fa71cf0e0 100644 --- a/libs/components/src/utils/index.ts +++ b/libs/components/src/utils/index.ts @@ -1,2 +1,3 @@ +export * from "./aria-disable-element"; export * from "./function-to-observable"; export * from "./i18n-mock.service"; From f07518084f0f34a578565f7b86f5d73a3a9b1024 Mon Sep 17 00:00:00 2001 From: Kyle Denney <4227399+kdenney@users.noreply.github.com> Date: Thu, 21 Aug 2025 09:36:57 -0500 Subject: [PATCH 012/167] [PM-24554] remove code for feature flag (#16092) --- .../complete-trial-initiation.component.ts | 14 ++++---------- libs/common/src/enums/feature-flag.enum.ts | 2 -- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.ts b/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.ts index ce02ee8715a..799577fc7c4 100644 --- a/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.ts +++ b/apps/web/src/app/billing/trial-initiation/complete-trial-initiation/complete-trial-initiation.component.ts @@ -4,7 +4,7 @@ import { StepperSelectionEvent } from "@angular/cdk/stepper"; import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core"; import { FormBuilder, Validators } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; -import { combineLatest, firstValueFrom, map, Subject, switchMap, takeUntil } from "rxjs"; +import { firstValueFrom, map, Subject, switchMap, takeUntil } from "rxjs"; import { InputPasswordFlow, @@ -101,9 +101,6 @@ export class CompleteTrialInitiationComponent implements OnInit, OnDestroy { protected trialPaymentOptional$ = this.configService.getFeatureFlag$( FeatureFlag.TrialPaymentOptional, ); - protected allowTrialLengthZero$ = this.configService.getFeatureFlag$( - FeatureFlag.AllowTrialLengthZero, - ); constructor( protected router: Router, @@ -337,14 +334,11 @@ export class CompleteTrialInitiationComponent implements OnInit, OnDestroy { return this.productTier; } - readonly showBillingStep$ = combineLatest([ - this.trialPaymentOptional$, - this.allowTrialLengthZero$, - ]).pipe( - map(([trialPaymentOptional, allowTrialLengthZero]) => { + readonly showBillingStep$ = this.trialPaymentOptional$.pipe( + map((trialPaymentOptional) => { return ( (!trialPaymentOptional && !this.isSecretsManagerFree) || - (trialPaymentOptional && allowTrialLengthZero && this.trialLength === 0) + (trialPaymentOptional && this.trialLength === 0) ); }), ); diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 81cc3b305dc..a36eb68dc71 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -28,7 +28,6 @@ export enum FeatureFlag { PM12276_BreadcrumbEventLogs = "pm-12276-breadcrumbing-for-business-features", PM17772_AdminInitiatedSponsorships = "pm-17772-admin-initiated-sponsorships", UseOrganizationWarningsService = "use-organization-warnings-service", - AllowTrialLengthZero = "pm-20322-allow-trial-length-0", PM21881_ManagePaymentDetailsOutsideCheckout = "pm-21881-manage-payment-details-outside-checkout", PM21821_ProviderPortalTakeover = "pm-21821-provider-portal-takeover", PM22415_TaxIDWarnings = "pm-22415-tax-id-warnings", @@ -104,7 +103,6 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.PM12276_BreadcrumbEventLogs]: FALSE, [FeatureFlag.PM17772_AdminInitiatedSponsorships]: FALSE, [FeatureFlag.UseOrganizationWarningsService]: FALSE, - [FeatureFlag.AllowTrialLengthZero]: FALSE, [FeatureFlag.PM21881_ManagePaymentDetailsOutsideCheckout]: FALSE, [FeatureFlag.PM21821_ProviderPortalTakeover]: FALSE, [FeatureFlag.PM22415_TaxIDWarnings]: FALSE, From 805b6fe7aaf812fad0f9063023011223c01a85fc Mon Sep 17 00:00:00 2001 From: Vicki League Date: Thu, 21 Aug 2025 12:35:59 -0400 Subject: [PATCH 013/167] [CL-573] Move all svg icons to new libs/assets (#16020) * create libs/assets * treeshake lib and filter out non-icons from icon story * update docs * fix icon colors in browser and desktop * better name for vault icon * move illustrations --- .github/CODEOWNERS | 1 + .../autofill/popup/fido2/fido2.component.ts | 4 +- .../popup/layout/popup-layout.stories.ts | 27 ++++--- .../layout/popup-tab-navigation.component.ts | 3 +- apps/browser/src/popup/app-routing.module.ts | 19 ++--- ...extension-anon-layout-wrapper.component.ts | 5 +- .../extension-anon-layout-wrapper.stories.ts | 12 ++-- apps/browser/src/popup/tabs-v2.component.ts | 27 ++++--- .../send-created/send-created.component.ts | 2 +- .../tools/popup/send-v2/send-v2.component.ts | 6 +- .../intro-carousel.component.ts | 11 +-- .../components/vault-v2/vault-v2.component.ts | 10 +-- .../popup/settings/folders-v2.component.ts | 5 +- .../vault/popup/settings/trash.component.ts | 4 +- apps/browser/tailwind.config.js | 1 + apps/desktop/src/app/app-routing.module.ts | 21 +++--- apps/desktop/tailwind.config.js | 1 + apps/web/src/app/admin-console/icons/index.ts | 1 - .../collection-access-restricted.component.ts | 10 +-- .../collections/vault.component.ts | 4 +- .../layouts/organization-layout.component.ts | 3 +- .../accept-family-sponsorship.component.ts | 5 +- .../login-via-webauthn.component.ts | 8 ++- .../create-credential-dialog.component.ts | 9 +-- .../create-passkey-failed.icon.ts | 28 -------- ...ganization-subscription-cloud.component.ts | 2 +- .../subscription-hidden.component.ts | 25 +------ .../billing/shared/sm-subscribe.component.ts | 5 +- apps/web/src/app/dirt/reports/reports.ts | 17 +++-- .../reports/shared/models/report-entry.ts | 2 +- .../report-card/report-card.component.ts | 2 +- .../src/app/layouts/password-manager-logo.ts | 5 -- .../src/app/layouts/user-layout.component.ts | 3 +- apps/web/src/app/oss-routing.module.ts | 29 ++++---- .../send/send-access/access.component.ts | 2 +- .../src/app/tools/send/send-access/routes.ts | 2 +- apps/web/src/app/tools/send/send.component.ts | 2 +- .../manually-open-extension.component.ts | 4 +- .../setup-extension.component.spec.ts | 4 +- .../setup-extension.component.ts | 6 +- .../vault/individual-vault/vault.component.ts | 5 +- apps/web/tailwind.config.js | 1 + .../device-approvals.component.ts | 2 +- .../manage/accept-provider.component.ts | 4 +- .../providers/providers-layout.component.ts | 8 +-- .../setup/setup-provider.component.ts | 4 +- .../providers/clients/no-clients.component.ts | 23 +----- .../setup/setup-business-unit.component.ts | 4 +- .../all-applications.component.ts | 4 +- .../critical-applications.component.ts | 11 +-- .../layout/navigation.component.ts | 2 +- .../shared/org-suspended.component.ts | 4 +- .../components/two-factor-icon.component.ts | 5 +- .../src/auth/icons/create-passkey.icon.ts | 26 ------- .../change-password.component.ts | 6 +- .../set-initial-password.component.ts | 5 +- .../invoices/no-invoices.component.ts | 26 +------ libs/assets/README.md | 16 +++++ libs/assets/eslint.config.mjs | 3 + libs/assets/jest.config.js | 10 +++ libs/assets/package.json | 15 ++++ libs/assets/project.json | 33 +++++++++ .../src/svg/icon-service.spec.ts} | 4 +- .../src/svg/icon-service.ts} | 0 libs/assets/src/svg/index.ts | 2 + .../src/svg/svgs}/active-send.icon.ts | 2 +- .../src/svg/svgs}/admin-console.ts | 2 +- .../svg/svgs/background-left-illustration.ts} | 4 +- .../svgs/background-right-illustration.ts} | 4 +- .../src/svg/svgs}/bitwarden-icon.ts | 2 +- .../src/svg/svgs}/bitwarden-logo.icon.ts | 2 +- .../src/svg/svgs}/browser-extension.ts | 2 +- .../src/svg/svgs}/business-unit-portal.ts | 2 +- .../src/svg/svgs}/carousel-icon.ts | 2 +- .../svg/svgs}/create-passkey-failed.icon.ts | 2 +- .../src/svg/svgs}/create-passkey.icon.ts | 2 +- .../src/svg/svgs}/deactivated-org.ts | 2 +- .../src/svg/svgs}/device-verification.icon.ts | 4 +- .../src/svg/svgs}/devices.icon.ts | 4 +- .../assets/src/svg/svgs}/devices.ts | 2 +- .../src/svg/svgs}/email.icon.ts | 3 +- .../src/svg/svgs}/empty-trash.ts | 2 +- .../src/svg/svgs}/expired-send.icon.ts | 2 +- .../svgs}/extension-bitwarden-logo.icon.ts | 2 +- libs/assets/src/svg/svgs/gear.ts | 20 ++++++ .../src/svg/svgs}/generator.ts | 2 +- libs/assets/src/svg/svgs/index.ts | 72 +++++++++++++++++++ .../src/svg/svgs}/lock.icon.ts | 2 +- .../src/svg/svgs}/login-cards.ts | 2 +- .../src/svg/svgs}/no-access.ts | 2 +- .../src/svg/svgs}/no-credentials.icon.ts | 2 +- .../src/svg/svgs}/no-folders.ts | 2 +- .../src/svg/svgs}/no-results.ts | 2 +- .../src/svg/svgs}/no-send.icon.ts | 2 +- libs/assets/src/svg/svgs/partner-trust.ts | 23 ++++++ .../icons => assets/src/svg/svgs}/party.ts | 2 +- .../src/svg/svgs}/password-manager.ts | 2 +- .../src/svg/svgs}/provider-portal.ts | 2 +- .../src/svg/svgs}/recovery.icon.ts | 2 +- .../svgs}/registration-check-email.icon.ts | 2 +- .../svgs}/registration-expired-link.icon.ts | 4 +- .../svg/svgs}/registration-lock-alt.icon.ts | 4 +- .../svg/svgs}/registration-user-add.icon.ts | 4 +- .../src/svg/svgs}/report-breach.icon.ts | 2 +- .../svgs}/report-exposed-passwords.icon.ts | 2 +- .../svgs}/report-inactive-two-factor.icon.ts | 2 +- .../svg/svgs}/report-member-access.icon.ts | 2 +- .../svg/svgs}/report-reused-passwords.icon.ts | 2 +- .../svgs}/report-unsecured-websites.icon.ts | 2 +- .../svg/svgs}/report-weak-passwords.icon.ts | 2 +- libs/assets/src/svg/svgs/restricted-view.ts | 6 ++ .../icons => assets/src/svg/svgs}/search.ts | 2 +- .../src/svg/svgs/secrets-manager-alt.ts | 4 +- .../src/svg/svgs}/secrets-manager.ts | 2 +- .../src/svg/svgs}/secure-devices.ts | 2 +- .../src/svg/svgs}/secure-user.ts | 2 +- .../src/svg/svgs}/security-handshake.ts | 2 +- .../icons => assets/src/svg/svgs}/security.ts | 2 +- .../icons => assets/src/svg/svgs}/send.ts | 2 +- .../icons => assets/src/svg/svgs}/settings.ts | 2 +- .../src/svg/svgs}/shield.ts | 2 +- .../src/svg/svgs}/sso-key.icon.ts | 4 +- .../src/svg/svgs/subscription-hidden.ts | 4 +- .../src/svg/svgs}/totp.icon.ts | 2 +- .../two-factor-auth-authenticator.icon.ts | 4 +- .../src/svg/svgs}/two-factor-auth-duo.icon.ts | 4 +- .../svg/svgs}/two-factor-auth-email.icon.ts | 4 +- .../two-factor-auth-security-key.icon.ts | 4 +- .../svgs}/two-factor-auth-webauthn.icon.ts | 4 +- .../svg/svgs}/two-factor-auth-yubico.icon.ts | 4 +- .../src/svg/svgs}/two-factor-timeout.icon.ts | 4 +- .../src/svg/svgs}/user-lock.icon.ts | 4 +- ...erification-biometrics-fingerprint.icon.ts | 4 +- .../src/svg/svgs/vault-open.ts} | 4 +- .../src/svg/svgs}/vault.icon.ts | 4 +- .../icons => assets/src/svg/svgs}/vault.ts | 2 +- .../src/svg/svgs}/wave.icon.ts | 4 +- .../src/svg/svgs}/webauthn.icon.ts | 2 +- libs/assets/tsconfig.eslint.json | 6 ++ libs/assets/tsconfig.json | 13 ++++ libs/assets/tsconfig.lib.json | 10 +++ libs/assets/tsconfig.spec.json | 10 +++ libs/auth/src/angular/icons/index.ts | 11 --- .../angular/icons/two-factor-auth/index.ts | 6 -- libs/auth/src/angular/index.ts | 3 - .../auth/src/angular/login/login.component.ts | 3 +- .../registration-link-expired.component.ts | 3 +- .../registration-start.component.ts | 5 +- .../two-factor-auth.component.ts | 15 ++-- .../two-factor-options.component.ts | 15 ++-- .../user-verification-form-input.component.ts | 3 +- .../anon-layout-wrapper.component.ts | 2 +- .../anon-layout-wrapper.stories.ts | 2 +- .../src/anon-layout/anon-layout.component.ts | 17 +++-- .../src/anon-layout/anon-layout.mdx | 9 ++- .../src/anon-layout/anon-layout.stories.ts | 3 +- .../src/anon-layout/illustrations/index.ts | 2 - libs/components/src/icon/icon.component.ts | 2 +- .../src/icon/icon.components.spec.ts | 3 +- libs/components/src/icon/icon.mdx | 9 +-- libs/components/src/icon/icon.stories.ts | 13 ++-- libs/components/src/icon/icons/index.ts | 12 ---- libs/components/src/icon/index.ts | 9 --- .../src/icon/logos/bitwarden/index.ts | 6 -- libs/components/src/icon/logos/index.ts | 1 - .../src/navigation/nav-logo.component.ts | 4 +- .../src/no-items/no-items.component.ts | 5 +- .../kitchen-sink/kitchen-sink.stories.ts | 2 +- libs/components/tailwind.config.base.js | 1 + libs/components/tailwind.config.js | 1 + .../src/empty-credential-history.component.ts | 3 +- libs/tools/send/send-ui/src/icons/index.ts | 3 - libs/tools/send/send-ui/src/index.ts | 1 - .../carousel-button.component.ts | 2 +- libs/vault/src/icons/index.ts | 11 --- libs/vault/src/index.ts | 2 - package-lock.json | 9 +++ tailwind.config.js | 1 + tsconfig.base.json | 2 + 179 files changed, 579 insertions(+), 525 deletions(-) delete mode 100644 apps/web/src/app/admin-console/icons/index.ts delete mode 100644 apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey-failed.icon.ts delete mode 100644 apps/web/src/app/layouts/password-manager-logo.ts delete mode 100644 libs/angular/src/auth/icons/create-passkey.icon.ts create mode 100644 libs/assets/README.md create mode 100644 libs/assets/eslint.config.mjs create mode 100644 libs/assets/jest.config.js create mode 100644 libs/assets/package.json create mode 100644 libs/assets/project.json rename libs/{components/src/icon/icon.spec.ts => assets/src/svg/icon-service.spec.ts} (94%) rename libs/{components/src/icon/icon.ts => assets/src/svg/icon-service.ts} (100%) create mode 100644 libs/assets/src/svg/index.ts rename libs/{tools/send/send-ui/src/icons => assets/src/svg/svgs}/active-send.icon.ts (98%) rename libs/{components/src/icon/logos/bitwarden => assets/src/svg/svgs}/admin-console.ts (99%) rename libs/{components/src/anon-layout/illustrations/left-illustration.ts => assets/src/svg/svgs/background-left-illustration.ts} (99%) rename libs/{components/src/anon-layout/illustrations/right-illustration.ts => assets/src/svg/svgs/background-right-illustration.ts} (99%) rename libs/{vault/src/icons => assets/src/svg/svgs}/bitwarden-icon.ts (97%) rename libs/{components/src/icon/icons => assets/src/svg/svgs}/bitwarden-logo.icon.ts (99%) rename libs/{vault/src/icons => assets/src/svg/svgs}/browser-extension.ts (97%) rename libs/{components/src/icon/logos/bitwarden => assets/src/svg/svgs}/business-unit-portal.ts (99%) rename libs/{vault/src/components/carousel/carousel-icons => assets/src/svg/svgs}/carousel-icon.ts (85%) rename libs/{angular/src/auth/icons => assets/src/svg/svgs}/create-passkey-failed.icon.ts (98%) rename {apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog => libs/assets/src/svg/svgs}/create-passkey.icon.ts (98%) rename libs/{vault/src/icons => assets/src/svg/svgs}/deactivated-org.ts (98%) rename libs/{auth/src/angular/icons => assets/src/svg/svgs}/device-verification.icon.ts (89%) rename libs/{auth/src/angular/icons => assets/src/svg/svgs}/devices.icon.ts (91%) rename {apps/web/src/app/admin-console/icons => libs/assets/src/svg/svgs}/devices.ts (98%) rename libs/{angular/src/auth/icons => assets/src/svg/svgs}/email.icon.ts (92%) rename libs/{vault/src/icons => assets/src/svg/svgs}/empty-trash.ts (99%) rename libs/{tools/send/send-ui/src/icons => assets/src/svg/svgs}/expired-send.icon.ts (98%) rename libs/{components/src/icon/icons => assets/src/svg/svgs}/extension-bitwarden-logo.icon.ts (99%) create mode 100644 libs/assets/src/svg/svgs/gear.ts rename libs/{components/src/icon/icons => assets/src/svg/svgs}/generator.ts (98%) create mode 100644 libs/assets/src/svg/svgs/index.ts rename libs/{components/src/icon/icons => assets/src/svg/svgs}/lock.icon.ts (98%) rename libs/{vault/src/icons => assets/src/svg/svgs}/login-cards.ts (98%) rename libs/{components/src/icon/icons => assets/src/svg/svgs}/no-access.ts (96%) rename libs/{tools/generator/components/src/icons => assets/src/svg/svgs}/no-credentials.icon.ts (99%) rename libs/{vault/src/icons => assets/src/svg/svgs}/no-folders.ts (98%) rename libs/{components/src/icon/icons => assets/src/svg/svgs}/no-results.ts (98%) rename libs/{tools/send/send-ui/src/icons => assets/src/svg/svgs}/no-send.icon.ts (97%) create mode 100644 libs/assets/src/svg/svgs/partner-trust.ts rename libs/{vault/src/icons => assets/src/svg/svgs}/party.ts (99%) rename libs/{components/src/icon/logos/bitwarden => assets/src/svg/svgs}/password-manager.ts (99%) rename libs/{components/src/icon/logos/bitwarden => assets/src/svg/svgs}/provider-portal.ts (99%) rename libs/{angular/src/auth/icons => assets/src/svg/svgs}/recovery.icon.ts (98%) rename libs/{components/src/icon/icons => assets/src/svg/svgs}/registration-check-email.icon.ts (97%) rename libs/{auth/src/angular/icons => assets/src/svg/svgs}/registration-expired-link.icon.ts (83%) rename libs/{auth/src/angular/icons => assets/src/svg/svgs}/registration-lock-alt.icon.ts (94%) rename libs/{auth/src/angular/icons => assets/src/svg/svgs}/registration-user-add.icon.ts (93%) rename {apps/web/src/app/dirt/reports/icons => libs/assets/src/svg/svgs}/report-breach.icon.ts (96%) rename {apps/web/src/app/dirt/reports/icons => libs/assets/src/svg/svgs}/report-exposed-passwords.icon.ts (97%) rename {apps/web/src/app/dirt/reports/icons => libs/assets/src/svg/svgs}/report-inactive-two-factor.icon.ts (94%) rename {apps/web/src/app/dirt/reports/icons => libs/assets/src/svg/svgs}/report-member-access.icon.ts (96%) rename {apps/web/src/app/dirt/reports/icons => libs/assets/src/svg/svgs}/report-reused-passwords.icon.ts (96%) rename {apps/web/src/app/dirt/reports/icons => libs/assets/src/svg/svgs}/report-unsecured-websites.icon.ts (94%) rename {apps/web/src/app/dirt/reports/icons => libs/assets/src/svg/svgs}/report-weak-passwords.icon.ts (95%) create mode 100644 libs/assets/src/svg/svgs/restricted-view.ts rename libs/{components/src/icon/icons => assets/src/svg/svgs}/search.ts (98%) rename apps/web/src/app/layouts/secrets-manager-logo.ts => libs/assets/src/svg/svgs/secrets-manager-alt.ts (99%) rename libs/{components/src/icon/logos/bitwarden => assets/src/svg/svgs}/secrets-manager.ts (99%) rename libs/{vault/src/icons => assets/src/svg/svgs}/secure-devices.ts (97%) rename libs/{vault/src/icons => assets/src/svg/svgs}/secure-user.ts (98%) rename libs/{vault/src/icons => assets/src/svg/svgs}/security-handshake.ts (99%) rename libs/{components/src/icon/icons => assets/src/svg/svgs}/security.ts (99%) rename libs/{components/src/icon/icons => assets/src/svg/svgs}/send.ts (97%) rename libs/{components/src/icon/icons => assets/src/svg/svgs}/settings.ts (99%) rename libs/{components/src/icon/logos/bitwarden => assets/src/svg/svgs}/shield.ts (98%) rename libs/{auth/src/angular/icons => assets/src/svg/svgs}/sso-key.icon.ts (92%) rename apps/web/src/app/billing/organizations/icons/subscription-hidden.icon.ts => libs/assets/src/svg/svgs/subscription-hidden.ts (99%) rename libs/{angular/src/auth/icons => assets/src/svg/svgs}/totp.icon.ts (98%) rename libs/{auth/src/angular/icons/two-factor-auth => assets/src/svg/svgs}/two-factor-auth-authenticator.icon.ts (96%) rename libs/{auth/src/angular/icons/two-factor-auth => assets/src/svg/svgs}/two-factor-auth-duo.icon.ts (81%) rename libs/{auth/src/angular/icons/two-factor-auth => assets/src/svg/svgs}/two-factor-auth-email.icon.ts (90%) rename libs/{auth/src/angular/icons/two-factor-auth => assets/src/svg/svgs}/two-factor-auth-security-key.icon.ts (96%) rename libs/{auth/src/angular/icons/two-factor-auth => assets/src/svg/svgs}/two-factor-auth-webauthn.icon.ts (96%) rename libs/{auth/src/angular/icons/two-factor-auth => assets/src/svg/svgs}/two-factor-auth-yubico.icon.ts (93%) rename libs/{auth/src/angular/icons => assets/src/svg/svgs}/two-factor-timeout.icon.ts (88%) rename libs/{auth/src/angular/icons => assets/src/svg/svgs}/user-lock.icon.ts (95%) rename libs/{auth/src/angular/icons => assets/src/svg/svgs}/user-verification-biometrics-fingerprint.icon.ts (92%) rename libs/{vault/src/icons/vault.ts => assets/src/svg/svgs/vault-open.ts} (98%) rename libs/{auth/src/angular/icons => assets/src/svg/svgs}/vault.icon.ts (92%) rename libs/{components/src/icon/icons => assets/src/svg/svgs}/vault.ts (99%) rename libs/{auth/src/angular/icons => assets/src/svg/svgs}/wave.icon.ts (90%) rename libs/{angular/src/auth/icons => assets/src/svg/svgs}/webauthn.icon.ts (96%) create mode 100644 libs/assets/tsconfig.eslint.json create mode 100644 libs/assets/tsconfig.json create mode 100644 libs/assets/tsconfig.lib.json create mode 100644 libs/assets/tsconfig.spec.json delete mode 100644 libs/auth/src/angular/icons/index.ts delete mode 100644 libs/auth/src/angular/icons/two-factor-auth/index.ts delete mode 100644 libs/components/src/anon-layout/illustrations/index.ts delete mode 100644 libs/components/src/icon/icons/index.ts delete mode 100644 libs/components/src/icon/logos/bitwarden/index.ts delete mode 100644 libs/components/src/icon/logos/index.ts delete mode 100644 libs/tools/send/send-ui/src/icons/index.ts delete mode 100644 libs/vault/src/icons/index.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 4b956fd577a..df71b6545fb 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -156,6 +156,7 @@ apps/desktop/desktop_native/core/src/ssh_agent @bitwarden/team-autofill-dev @bit ## UI Foundation ## .storybook @bitwarden/team-ui-foundation libs/components @bitwarden/team-ui-foundation +libs/assets @bitwarden/team-ui-foundation libs/ui @bitwarden/team-ui-foundation apps/browser/src/platform/popup/layout @bitwarden/team-ui-foundation apps/browser/src/popup/app-routing.animations.ts @bitwarden/team-ui-foundation diff --git a/apps/browser/src/autofill/popup/fido2/fido2.component.ts b/apps/browser/src/autofill/popup/fido2/fido2.component.ts index ac38fe2f894..11e00749bdf 100644 --- a/apps/browser/src/autofill/popup/fido2/fido2.component.ts +++ b/apps/browser/src/autofill/popup/fido2/fido2.component.ts @@ -18,6 +18,7 @@ import { } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { NoResults } from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; @@ -36,7 +37,6 @@ import { SecureNoteView } from "@bitwarden/common/vault/models/view/secure-note. import { ButtonModule, DialogService, - Icons, ItemModule, NoItemsModule, SearchModule, @@ -102,7 +102,7 @@ export class Fido2Component implements OnInit, OnDestroy { protected equivalentDomainsURL: string; protected hostname: string; protected loading = false; - protected noResultsIcon = Icons.NoResults; + protected noResultsIcon = NoResults; protected passkeyAction: PasskeyActionValue = PasskeyActions.Register; protected PasskeyActions = PasskeyActions; protected hasSearched = false; diff --git a/apps/browser/src/platform/popup/layout/popup-layout.stories.ts b/apps/browser/src/platform/popup/layout/popup-layout.stories.ts index 7455921b08b..a7103fdfd3c 100644 --- a/apps/browser/src/platform/popup/layout/popup-layout.stories.ts +++ b/apps/browser/src/platform/popup/layout/popup-layout.stories.ts @@ -4,6 +4,16 @@ import { Component, importProvidersFrom } from "@angular/core"; import { RouterModule } from "@angular/router"; import { Meta, StoryObj, applicationConfig, moduleMetadata } from "@storybook/angular"; +import { + GeneratorActive, + GeneratorInactive, + SendActive, + SendInactive, + SettingsActive, + SettingsInactive, + VaultActive, + VaultInactive, +} from "@bitwarden/assets/svg"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; @@ -13,7 +23,6 @@ import { BannerModule, ButtonModule, I18nMockService, - Icons, IconButtonModule, ItemModule, NoItemsModule, @@ -404,26 +413,26 @@ const navButtons = (showBerry = false) => [ { label: "vault", page: "/tabs/vault", - icon: Icons.VaultInactive, - iconActive: Icons.VaultActive, + icon: VaultInactive, + iconActive: VaultActive, }, { label: "generator", page: "/tabs/generator", - icon: Icons.GeneratorInactive, - iconActive: Icons.GeneratorActive, + icon: GeneratorInactive, + iconActive: GeneratorActive, }, { label: "send", page: "/tabs/send", - icon: Icons.SendInactive, - iconActive: Icons.SendActive, + icon: SendInactive, + iconActive: SendActive, }, { label: "settings", page: "/tabs/settings", - icon: Icons.SettingsInactive, - iconActive: Icons.SettingsActive, + icon: SettingsInactive, + iconActive: SettingsActive, showBerry: showBerry, }, ]; diff --git a/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.ts b/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.ts index 8a897e2e21b..742b12bb7ad 100644 --- a/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.ts +++ b/apps/browser/src/platform/popup/layout/popup-tab-navigation.component.ts @@ -3,8 +3,9 @@ import { Component, Input } from "@angular/core"; import { RouterModule } from "@angular/router"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { Icon } from "@bitwarden/assets/svg"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { Icon, IconModule, LinkModule } from "@bitwarden/components"; +import { IconModule, LinkModule } from "@bitwarden/components"; export type NavButton = { label: string; diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index e2f4561e86c..34a37da425e 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -17,28 +17,31 @@ import { SetInitialPasswordComponent } from "@bitwarden/angular/auth/password-ma import { canAccessFeature } from "@bitwarden/angular/platform/guard/feature-flag.guard"; import { DevicesIcon, + RegistrationLockAltIcon, + RegistrationUserAddIcon, + TwoFactorTimeoutIcon, + DeviceVerificationIcon, + UserLockIcon, + VaultIcon, + LockIcon, +} from "@bitwarden/assets/svg"; +import { LoginComponent, LoginDecryptionOptionsComponent, LoginSecondaryContentComponent, LoginViaAuthRequestComponent, PasswordHintComponent, RegistrationFinishComponent, - RegistrationLockAltIcon, RegistrationStartComponent, RegistrationStartSecondaryComponent, RegistrationStartSecondaryComponentData, - RegistrationUserAddIcon, SsoComponent, - TwoFactorTimeoutIcon, TwoFactorAuthComponent, TwoFactorAuthGuard, NewDeviceVerificationComponent, - DeviceVerificationIcon, - UserLockIcon, - VaultIcon, } from "@bitwarden/auth/angular"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { AnonLayoutWrapperData, Icons } from "@bitwarden/components"; +import { AnonLayoutWrapperData } from "@bitwarden/components"; import { LockComponent } from "@bitwarden/key-management-ui"; import { AccountSwitcherComponent } from "../auth/popup/account-switching/account-switcher.component"; @@ -497,7 +500,7 @@ const routes: Routes = [ path: "lock", canActivate: [lockGuard()], data: { - pageIcon: Icons.LockIcon, + pageIcon: LockIcon, pageTitle: { key: "yourVaultIsLockedV2", }, diff --git a/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component.ts b/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component.ts index 7a98f570fda..3b84eac2217 100644 --- a/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component.ts +++ b/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.component.ts @@ -5,10 +5,9 @@ import { Component, OnDestroy, OnInit } from "@angular/core"; import { ActivatedRoute, Data, NavigationEnd, Router, RouterModule } from "@angular/router"; import { Subject, filter, switchMap, takeUntil, tap } from "rxjs"; +import { ExtensionBitwardenLogo, Icon } from "@bitwarden/assets/svg"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { - Icon, - Icons, IconModule, Translation, AnonLayoutComponent, @@ -63,7 +62,7 @@ export class ExtensionAnonLayoutWrapperComponent implements OnInit, OnDestroy { protected hideCardWrapper: boolean = false; protected theme: string; - protected logo = Icons.ExtensionBitwardenLogo; + protected logo = ExtensionBitwardenLogo; constructor( private router: Router, diff --git a/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts b/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts index 2c3d09b79fb..4e6f2fb452d 100644 --- a/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts +++ b/apps/browser/src/popup/components/extension-anon-layout-wrapper/extension-anon-layout-wrapper.stories.ts @@ -9,6 +9,7 @@ import { } from "@storybook/angular"; import { of } from "rxjs"; +import { LockIcon, RegistrationCheckEmailIcon } from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AvatarService } from "@bitwarden/common/auth/abstractions/avatar.service"; @@ -22,12 +23,7 @@ import { import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { UserId } from "@bitwarden/common/types/guid"; -import { - AnonLayoutWrapperDataService, - ButtonModule, - Icons, - I18nMockService, -} from "@bitwarden/components"; +import { AnonLayoutWrapperDataService, ButtonModule, I18nMockService } from "@bitwarden/components"; import { AccountSwitcherService } from "../../../auth/popup/account-switching/services/account-switcher.service"; import { PopupRouterCacheService } from "../../../platform/popup/view-cache/popup-router-cache.service"; @@ -244,7 +240,7 @@ const initialData: ExtensionAnonLayoutWrapperData = { pageSubtitle: { key: "finishCreatingYourAccountBySettingAPassword", }, - pageIcon: Icons.LockIcon, + pageIcon: LockIcon, showAcctSwitcher: true, showBackButton: true, showLogo: true, @@ -258,7 +254,7 @@ const changedData: ExtensionAnonLayoutWrapperData = { pageSubtitle: { key: "checkYourEmail", }, - pageIcon: Icons.RegistrationCheckEmailIcon, + pageIcon: RegistrationCheckEmailIcon, showAcctSwitcher: false, showBackButton: false, showLogo: false, diff --git a/apps/browser/src/popup/tabs-v2.component.ts b/apps/browser/src/popup/tabs-v2.component.ts index 860b71794ff..f1e42799b35 100644 --- a/apps/browser/src/popup/tabs-v2.component.ts +++ b/apps/browser/src/popup/tabs-v2.component.ts @@ -2,9 +2,18 @@ import { Component } from "@angular/core"; import { map, Observable, startWith, switchMap } from "rxjs"; import { NudgesService } from "@bitwarden/angular/vault"; +import { + VaultInactive, + VaultActive, + GeneratorInactive, + GeneratorActive, + SendInactive, + SendActive, + SettingsInactive, + SettingsActive, +} from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { Icons } from "@bitwarden/components"; import { NavButton } from "../platform/popup/layout/popup-tab-navigation.component"; @@ -24,26 +33,26 @@ export class TabsV2Component { { label: "vault", page: "/tabs/vault", - icon: Icons.VaultInactive, - iconActive: Icons.VaultActive, + icon: VaultInactive, + iconActive: VaultActive, }, { label: "generator", page: "/tabs/generator", - icon: Icons.GeneratorInactive, - iconActive: Icons.GeneratorActive, + icon: GeneratorInactive, + iconActive: GeneratorActive, }, { label: "send", page: "/tabs/send", - icon: Icons.SendInactive, - iconActive: Icons.SendActive, + icon: SendInactive, + iconActive: SendActive, }, { label: "settings", page: "/tabs/settings", - icon: Icons.SettingsInactive, - iconActive: Icons.SettingsActive, + icon: SettingsInactive, + iconActive: SettingsActive, showBerry: hasBadges, }, ]; diff --git a/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.ts b/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.ts index dd9e95b64a1..30359e98fa0 100644 --- a/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.ts +++ b/apps/browser/src/tools/popup/send-v2/send-created/send-created.component.ts @@ -7,13 +7,13 @@ import { ActivatedRoute, Router, RouterModule } from "@angular/router"; import { firstValueFrom } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { ActiveSendIcon } from "@bitwarden/assets/svg"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { SendView } from "@bitwarden/common/tools/send/models/view/send.view"; import { SendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { ButtonModule, IconModule, ToastService } from "@bitwarden/components"; -import { ActiveSendIcon } from "@bitwarden/send-ui"; import { PopOutComponent } from "../../../../platform/popup/components/pop-out.component"; import { PopupFooterComponent } from "../../../../platform/popup/layout/popup-footer.component"; diff --git a/apps/browser/src/tools/popup/send-v2/send-v2.component.ts b/apps/browser/src/tools/popup/send-v2/send-v2.component.ts index 2fca3e41f88..5bd5386b1e0 100644 --- a/apps/browser/src/tools/popup/send-v2/send-v2.component.ts +++ b/apps/browser/src/tools/popup/send-v2/send-v2.component.ts @@ -4,15 +4,15 @@ import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { combineLatest, switchMap } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { NoResults, NoSendsIcon } from "@bitwarden/assets/svg"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { SendType } from "@bitwarden/common/tools/send/enums/send-type"; -import { ButtonModule, CalloutModule, Icons, NoItemsModule } from "@bitwarden/components"; +import { ButtonModule, CalloutModule, NoItemsModule } from "@bitwarden/components"; import { NewSendDropdownComponent, - NoSendsIcon, SendItemsService, SendListFiltersComponent, SendListFiltersService, @@ -59,7 +59,7 @@ export class SendV2Component implements OnDestroy { protected sendsLoading$ = this.sendItemsService.loading$; protected title: string = "allSends"; protected noItemIcon = NoSendsIcon; - protected noResultsIcon = Icons.NoResults; + protected noResultsIcon = NoResults; protected sendsDisabled = false; diff --git a/apps/browser/src/vault/popup/components/vault-v2/intro-carousel/intro-carousel.component.ts b/apps/browser/src/vault/popup/components/vault-v2/intro-carousel/intro-carousel.component.ts index 527f0f246af..22149f9dc86 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/intro-carousel/intro-carousel.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/intro-carousel/intro-carousel.component.ts @@ -2,9 +2,10 @@ import { Component } from "@angular/core"; import { Router } from "@angular/router"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { SecurityHandshake, LoginCards, SecureUser, SecureDevices } from "@bitwarden/assets/svg"; import { ButtonModule, DialogModule, IconModule, TypographyModule } from "@bitwarden/components"; import { I18nPipe } from "@bitwarden/ui-common"; -import { VaultCarouselModule, VaultIcons } from "@bitwarden/vault"; +import { VaultCarouselModule } from "@bitwarden/vault"; import { IntroCarouselService } from "../../../services/intro-carousel.service"; @@ -22,10 +23,10 @@ import { IntroCarouselService } from "../../../services/intro-carousel.service"; ], }) export class IntroCarouselComponent { - protected securityHandshake = VaultIcons.SecurityHandshake; - protected loginCards = VaultIcons.LoginCards; - protected secureUser = VaultIcons.SecureUser; - protected secureDevices = VaultIcons.SecureDevices; + protected securityHandshake = SecurityHandshake; + protected loginCards = LoginCards; + protected secureUser = SecureUser; + protected secureDevices = SecureDevices; constructor( private router: Router, diff --git a/apps/browser/src/vault/popup/components/vault-v2/vault-v2.component.ts b/apps/browser/src/vault/popup/components/vault-v2/vault-v2.component.ts index 0340c82369d..604cc6b73ef 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/vault-v2.component.ts +++ b/apps/browser/src/vault/popup/components/vault-v2/vault-v2.component.ts @@ -18,6 +18,7 @@ import { import { JslibModule } from "@bitwarden/angular/jslib.module"; import { NudgesService, NudgeType } from "@bitwarden/angular/vault"; import { SpotlightComponent } from "@bitwarden/angular/vault/components/spotlight/spotlight.component"; +import { DeactivatedOrg, NoResults, VaultOpen } from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; @@ -28,11 +29,10 @@ import { UnionOfValues } from "@bitwarden/common/vault/types/union-of-values"; import { ButtonModule, DialogService, - Icons, NoItemsModule, TypographyModule, } from "@bitwarden/components"; -import { DecryptionFailureDialogComponent, VaultIcons } from "@bitwarden/vault"; +import { DecryptionFailureDialogComponent } from "@bitwarden/vault"; import { CurrentAccountComponent } from "../../../../auth/popup/account-switching/current-account.component"; import { BrowserApi } from "../../../../platform/browser/browser-api"; @@ -136,9 +136,9 @@ export class VaultV2Component implements OnInit, AfterViewInit, OnDestroy { /** Visual state of the vault */ protected vaultState: VaultState | null = null; - protected vaultIcon = VaultIcons.Vault; - protected deactivatedIcon = VaultIcons.DeactivatedOrg; - protected noResultsIcon = Icons.NoResults; + protected vaultIcon = VaultOpen; + protected deactivatedIcon = DeactivatedOrg; + protected noResultsIcon = NoResults; protected VaultStateEnum = VaultState; diff --git a/apps/browser/src/vault/popup/settings/folders-v2.component.ts b/apps/browser/src/vault/popup/settings/folders-v2.component.ts index 2264415f4fa..b749f651d53 100644 --- a/apps/browser/src/vault/popup/settings/folders-v2.component.ts +++ b/apps/browser/src/vault/popup/settings/folders-v2.component.ts @@ -3,6 +3,7 @@ import { Component } from "@angular/core"; import { filter, map, Observable, switchMap } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { NoFolders } from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { UserId } from "@bitwarden/common/types/guid"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; @@ -15,7 +16,7 @@ import { ItemModule, NoItemsModule, } from "@bitwarden/components"; -import { AddEditFolderDialogComponent, VaultIcons } from "@bitwarden/vault"; +import { AddEditFolderDialogComponent } from "@bitwarden/vault"; import { PopOutComponent } from "../../../platform/popup/components/pop-out.component"; import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component"; @@ -39,7 +40,7 @@ import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.co export class FoldersV2Component { folders$: Observable; - NoFoldersIcon = VaultIcons.NoFolders; + NoFoldersIcon = NoFolders; private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id)); constructor( diff --git a/apps/browser/src/vault/popup/settings/trash.component.ts b/apps/browser/src/vault/popup/settings/trash.component.ts index d6e5f899bba..b9d6b621bba 100644 --- a/apps/browser/src/vault/popup/settings/trash.component.ts +++ b/apps/browser/src/vault/popup/settings/trash.component.ts @@ -2,8 +2,8 @@ import { CommonModule } from "@angular/common"; import { ChangeDetectionStrategy, Component } from "@angular/core"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { EmptyTrash } from "@bitwarden/assets/svg"; import { CalloutModule, NoItemsModule } from "@bitwarden/components"; -import { VaultIcons } from "@bitwarden/vault"; import { PopOutComponent } from "../../../platform/popup/components/pop-out.component"; import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component"; @@ -29,7 +29,7 @@ import { TrashListItemsContainerComponent } from "./trash-list-items-container/t export class TrashComponent { protected deletedCiphers$ = this.vaultPopupItemsService.deletedCiphers$; - protected emptyTrashIcon = VaultIcons.EmptyTrash; + protected emptyTrashIcon = EmptyTrash; constructor(private vaultPopupItemsService: VaultPopupItemsService) {} } diff --git a/apps/browser/tailwind.config.js b/apps/browser/tailwind.config.js index 02e1d86f5ac..1ad56562bb3 100644 --- a/apps/browser/tailwind.config.js +++ b/apps/browser/tailwind.config.js @@ -4,6 +4,7 @@ const config = require("../../libs/components/tailwind.config.base"); config.content = [ "./src/**/*.{html,ts}", "../../libs/components/src/**/*.{html,ts}", + "../../libs/assets/src/**/*.{html,ts}", "../../libs/auth/src/**/*.{html,ts}", "../../libs/key-management-ui/src/**/*.{html,ts}", "../../libs/vault/src/**/*.{html,ts}", diff --git a/apps/desktop/src/app/app-routing.module.ts b/apps/desktop/src/app/app-routing.module.ts index db079cd60f9..1cfe8a85386 100644 --- a/apps/desktop/src/app/app-routing.module.ts +++ b/apps/desktop/src/app/app-routing.module.ts @@ -12,29 +12,32 @@ import { unauthGuardFn, } from "@bitwarden/angular/auth/guards"; import { ChangePasswordComponent } from "@bitwarden/angular/auth/password-management/change-password"; +import { + DevicesIcon, + RegistrationLockAltIcon, + RegistrationUserAddIcon, + TwoFactorTimeoutIcon, + DeviceVerificationIcon, + UserLockIcon, + VaultIcon, + LockIcon, +} from "@bitwarden/assets/svg"; import { LoginComponent, LoginSecondaryContentComponent, LoginViaAuthRequestComponent, PasswordHintComponent, RegistrationFinishComponent, - RegistrationLockAltIcon, RegistrationStartComponent, RegistrationStartSecondaryComponent, RegistrationStartSecondaryComponentData, - RegistrationUserAddIcon, - UserLockIcon, - VaultIcon, LoginDecryptionOptionsComponent, - DevicesIcon, SsoComponent, - TwoFactorTimeoutIcon, TwoFactorAuthComponent, TwoFactorAuthGuard, NewDeviceVerificationComponent, - DeviceVerificationIcon, } from "@bitwarden/auth/angular"; -import { AnonLayoutWrapperComponent, AnonLayoutWrapperData, Icons } from "@bitwarden/components"; +import { AnonLayoutWrapperComponent, AnonLayoutWrapperData } from "@bitwarden/components"; import { LockComponent } from "@bitwarden/key-management-ui"; import { maxAccountsGuardFn } from "../auth/guards/max-accounts.guard"; @@ -260,7 +263,7 @@ const routes: Routes = [ path: "lock", canActivate: [lockGuard()], data: { - pageIcon: Icons.LockIcon, + pageIcon: LockIcon, pageTitle: { key: "yourVaultIsLockedV2", }, diff --git a/apps/desktop/tailwind.config.js b/apps/desktop/tailwind.config.js index 5b4cab027ba..bf65ae8d7cb 100644 --- a/apps/desktop/tailwind.config.js +++ b/apps/desktop/tailwind.config.js @@ -4,6 +4,7 @@ const config = require("../../libs/components/tailwind.config.base"); config.content = [ "./src/**/*.{html,ts}", "../../libs/components/src/**/*.{html,ts}", + "../../libs/assets/src/**/*.{html,ts}", "../../libs/auth/src/**/*.{html,ts}", "../../libs/key-management-ui/src/**/*.{html,ts}", "../../libs/angular/src/**/*.{html,ts}", diff --git a/apps/web/src/app/admin-console/icons/index.ts b/apps/web/src/app/admin-console/icons/index.ts deleted file mode 100644 index e0c2c124af1..00000000000 --- a/apps/web/src/app/admin-console/icons/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./devices"; diff --git a/apps/web/src/app/admin-console/organizations/collections/collection-access-restricted.component.ts b/apps/web/src/app/admin-console/organizations/collections/collection-access-restricted.component.ts index 3f26e03e203..86b83d75ca4 100644 --- a/apps/web/src/app/admin-console/organizations/collections/collection-access-restricted.component.ts +++ b/apps/web/src/app/admin-console/organizations/collections/collection-access-restricted.component.ts @@ -1,15 +1,11 @@ import { Component, EventEmitter, Input, Output } from "@angular/core"; -import { ButtonModule, NoItemsModule, svgIcon } from "@bitwarden/components"; +import { RestrictedView } from "@bitwarden/assets/svg"; +import { ButtonModule, NoItemsModule } from "@bitwarden/components"; import { SharedModule } from "../../../shared"; import { CollectionDialogTabType } from "../shared/components/collection-dialog"; -const icon = svgIcon` - - -`; - @Component({ selector: "collection-access-restricted", imports: [SharedModule, ButtonModule, NoItemsModule], @@ -38,7 +34,7 @@ const icon = svgIcon``, }) export class CollectionAccessRestrictedComponent { - protected icon = icon; + protected icon = RestrictedView; protected collectionDialogTabType = CollectionDialogTabType; @Input() canEditCollection = false; diff --git a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts index 87f309c6f66..8e4d844a871 100644 --- a/apps/web/src/app/admin-console/organizations/collections/vault.component.ts +++ b/apps/web/src/app/admin-console/organizations/collections/vault.component.ts @@ -34,6 +34,7 @@ import { Unassigned, } from "@bitwarden/admin-console/common"; import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe"; +import { Search } from "@bitwarden/assets/svg"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; @@ -66,7 +67,6 @@ import { BannerModule, DialogRef, DialogService, - Icons, NoItemsModule, ToastService, } from "@bitwarden/components"; @@ -170,7 +170,7 @@ export class VaultComponent implements OnInit, OnDestroy { activeFilter: VaultFilter = new VaultFilter(); protected showAddAccessToggle = false; - protected noItemIcon = Icons.Search; + protected noItemIcon = Search; protected performingInitialLoad = true; protected refreshing = false; protected processingEvent = false; diff --git a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts index 4b6e9a431b4..87b9d62f398 100644 --- a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts +++ b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts @@ -6,6 +6,7 @@ import { ActivatedRoute, RouterModule } from "@angular/router"; import { combineLatest, filter, map, Observable, switchMap, withLatestFrom } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { AdminConsoleLogo } from "@bitwarden/assets/svg"; import { canAccessBillingTab, canAccessGroupsTab, @@ -27,7 +28,7 @@ import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { getById } from "@bitwarden/common/platform/misc"; -import { BannerModule, IconModule, AdminConsoleLogo } from "@bitwarden/components"; +import { BannerModule, IconModule } from "@bitwarden/components"; import { OrganizationWarningsModule } from "@bitwarden/web-vault/app/billing/organizations/warnings/organization-warnings.module"; import { OrganizationWarningsService } from "@bitwarden/web-vault/app/billing/organizations/warnings/services"; import { NonIndividualSubscriber } from "@bitwarden/web-vault/app/billing/types"; diff --git a/apps/web/src/app/admin-console/organizations/sponsorships/accept-family-sponsorship.component.ts b/apps/web/src/app/admin-console/organizations/sponsorships/accept-family-sponsorship.component.ts index 2ca566a0af2..c4fe0350006 100644 --- a/apps/web/src/app/admin-console/organizations/sponsorships/accept-family-sponsorship.component.ts +++ b/apps/web/src/app/admin-console/organizations/sponsorships/accept-family-sponsorship.component.ts @@ -4,10 +4,11 @@ import { CommonModule } from "@angular/common"; import { Component, inject } from "@angular/core"; import { Params } from "@angular/router"; +import { BitwardenLogo } from "@bitwarden/assets/svg"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { OrganizationSponsorshipResponse } from "@bitwarden/common/admin-console/models/response/organization-sponsorship.response"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; -import { IconModule, Icons, ToastService } from "@bitwarden/components"; +import { IconModule, ToastService } from "@bitwarden/components"; import { I18nPipe } from "@bitwarden/ui-common"; import { BaseAcceptComponent } from "../../../common/base.accept.component"; @@ -22,7 +23,7 @@ import { BaseAcceptComponent } from "../../../common/base.accept.component"; imports: [CommonModule, I18nPipe, IconModule], }) export class AcceptFamilySponsorshipComponent extends BaseAcceptComponent { - protected logo = Icons.BitwardenLogo; + protected logo = BitwardenLogo; failedShortMessage = "inviteAcceptFailedShort"; failedMessage = "inviteAcceptFailed"; diff --git a/apps/web/src/app/auth/login/login-via-webauthn/login-via-webauthn.component.ts b/apps/web/src/app/auth/login/login-via-webauthn/login-via-webauthn.component.ts index d4a381159ab..443005473c4 100644 --- a/apps/web/src/app/auth/login/login-via-webauthn/login-via-webauthn.component.ts +++ b/apps/web/src/app/auth/login/login-via-webauthn/login-via-webauthn.component.ts @@ -1,8 +1,7 @@ import { Component } from "@angular/core"; import { BaseLoginViaWebAuthnComponent } from "@bitwarden/angular/auth/components/base-login-via-webauthn.component"; -import { CreatePasskeyFailedIcon } from "@bitwarden/angular/auth/icons/create-passkey-failed.icon"; -import { CreatePasskeyIcon } from "@bitwarden/angular/auth/icons/create-passkey.icon"; +import { CreatePasskeyIcon, CreatePasskeyFailedIcon } from "@bitwarden/assets/svg"; @Component({ selector: "app-login-via-webauthn", @@ -10,5 +9,8 @@ import { CreatePasskeyIcon } from "@bitwarden/angular/auth/icons/create-passkey. standalone: false, }) export class LoginViaWebAuthnComponent extends BaseLoginViaWebAuthnComponent { - protected readonly Icons = { CreatePasskeyIcon, CreatePasskeyFailedIcon }; + protected readonly Icons = { + CreatePasskeyIcon, + CreatePasskeyFailedIcon, + }; } diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts index 22c3b4376c5..35e5048b1af 100644 --- a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts +++ b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-credential-dialog.component.ts @@ -4,6 +4,7 @@ import { Component, OnInit } from "@angular/core"; import { FormBuilder, Validators } from "@angular/forms"; import { firstValueFrom, map, Observable } from "rxjs"; +import { CreatePasskeyFailedIcon, CreatePasskeyIcon } from "@bitwarden/assets/svg"; import { PrfKeySet } from "@bitwarden/auth/common"; import { Verification } from "@bitwarden/common/auth/types/verification"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; @@ -16,9 +17,6 @@ import { WebauthnLoginAdminService } from "../../../core"; import { CredentialCreateOptionsView } from "../../../core/views/credential-create-options.view"; import { PendingWebauthnLoginCredentialView } from "../../../core/views/pending-webauthn-login-credential.view"; -import { CreatePasskeyFailedIcon } from "./create-passkey-failed.icon"; -import { CreatePasskeyIcon } from "./create-passkey.icon"; - // FIXME: update to use a const object instead of a typescript enum // eslint-disable-next-line @bitwarden/platform/no-enums export enum CreateCredentialDialogResult { @@ -38,7 +36,10 @@ type Step = export class CreateCredentialDialogComponent implements OnInit { protected readonly NameMaxCharacters = 50; protected readonly CreateCredentialDialogResult = CreateCredentialDialogResult; - protected readonly Icons = { CreatePasskeyIcon, CreatePasskeyFailedIcon }; + protected readonly Icons = { + CreatePasskeyIcon, + CreatePasskeyFailedIcon, + }; protected currentStep: Step = "userVerification"; protected invalidSecret = false; diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey-failed.icon.ts b/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey-failed.icon.ts deleted file mode 100644 index 65902a64c9f..00000000000 --- a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey-failed.icon.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { svgIcon } from "@bitwarden/components"; - -export const CreatePasskeyFailedIcon = svgIcon` - - - - - - - - - - - -`; diff --git a/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.ts b/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.ts index 19c4ba04799..509fecb88fe 100644 --- a/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.ts +++ b/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.ts @@ -5,6 +5,7 @@ import { ActivatedRoute } from "@angular/router"; import { firstValueFrom, lastValueFrom, Subject } from "rxjs"; import { OrganizationUserApiService } from "@bitwarden/admin-console/common"; +import { SubscriptionHiddenIcon } from "@bitwarden/assets/svg"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { @@ -39,7 +40,6 @@ import { import { BillingSyncApiKeyComponent } from "./billing-sync-api-key.component"; import { ChangePlanDialogResultType, openChangePlanDialog } from "./change-plan-dialog.component"; import { DownloadLicenceDialogComponent } from "./download-license.component"; -import { SubscriptionHiddenIcon } from "./icons/subscription-hidden.icon"; import { SecretsManagerSubscriptionOptions } from "./sm-adjust-subscription.component"; @Component({ diff --git a/apps/web/src/app/billing/organizations/subscription-hidden.component.ts b/apps/web/src/app/billing/organizations/subscription-hidden.component.ts index 1455d76d67e..f68b20635ba 100644 --- a/apps/web/src/app/billing/organizations/subscription-hidden.component.ts +++ b/apps/web/src/app/billing/organizations/subscription-hidden.component.ts @@ -2,30 +2,7 @@ // @ts-strict-ignore import { Component, Input } from "@angular/core"; -import { svgIcon } from "@bitwarden/components"; - -const SubscriptionHiddenIcon = svgIcon` - - - - - - - - - - - - - - - - - - - - -`; +import { SubscriptionHiddenIcon } from "@bitwarden/assets/svg"; @Component({ selector: "app-org-subscription-hidden", diff --git a/apps/web/src/app/billing/shared/sm-subscribe.component.ts b/apps/web/src/app/billing/shared/sm-subscribe.component.ts index 1ecf3648bd2..d1e5566a235 100644 --- a/apps/web/src/app/billing/shared/sm-subscribe.component.ts +++ b/apps/web/src/app/billing/shared/sm-subscribe.component.ts @@ -5,13 +5,12 @@ import { FormBuilder, FormGroup, Validators } from "@angular/forms"; import { Subject, startWith, takeUntil } from "rxjs"; import { ControlsOf } from "@bitwarden/angular/types/controls-of"; +import { SecretsManagerAlt } from "@bitwarden/assets/svg"; import { ProductTierType } from "@bitwarden/common/billing/enums"; import { BillingCustomerDiscount } from "@bitwarden/common/billing/models/response/organization-subscription.response"; import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { SecretsManagerLogo } from "../../layouts/secrets-manager-logo"; - export interface SecretsManagerSubscription { enabled: boolean; userSeats: number; @@ -42,7 +41,7 @@ export class SecretsManagerSubscribeComponent implements OnInit, OnDestroy { @Input() selectedPlan: PlanResponse; @Input() customerDiscount: BillingCustomerDiscount; - logo = SecretsManagerLogo; + logo = SecretsManagerAlt; productTypes = ProductTierType; private destroy$ = new Subject(); diff --git a/apps/web/src/app/dirt/reports/reports.ts b/apps/web/src/app/dirt/reports/reports.ts index c47928af1e9..d7437382961 100644 --- a/apps/web/src/app/dirt/reports/reports.ts +++ b/apps/web/src/app/dirt/reports/reports.ts @@ -1,10 +1,13 @@ -import { ReportBreach } from "./icons/report-breach.icon"; -import { ReportExposedPasswords } from "./icons/report-exposed-passwords.icon"; -import { ReportInactiveTwoFactor } from "./icons/report-inactive-two-factor.icon"; -import { MemberAccess } from "./icons/report-member-access.icon"; -import { ReportReusedPasswords } from "./icons/report-reused-passwords.icon"; -import { ReportUnsecuredWebsites } from "./icons/report-unsecured-websites.icon"; -import { ReportWeakPasswords } from "./icons/report-weak-passwords.icon"; +import { + MemberAccess, + ReportBreach, + ReportExposedPasswords, + ReportInactiveTwoFactor, + ReportReusedPasswords, + ReportUnsecuredWebsites, + ReportWeakPasswords, +} from "@bitwarden/assets/svg"; + import { ReportEntry } from "./shared"; // FIXME: update to use a const object instead of a typescript enum diff --git a/apps/web/src/app/dirt/reports/shared/models/report-entry.ts b/apps/web/src/app/dirt/reports/shared/models/report-entry.ts index d4da4e36763..fd1e57991fb 100644 --- a/apps/web/src/app/dirt/reports/shared/models/report-entry.ts +++ b/apps/web/src/app/dirt/reports/shared/models/report-entry.ts @@ -1,4 +1,4 @@ -import { Icon } from "@bitwarden/components"; +import { Icon } from "@bitwarden/assets/svg"; import { ReportVariant } from "./report-variant"; diff --git a/apps/web/src/app/dirt/reports/shared/report-card/report-card.component.ts b/apps/web/src/app/dirt/reports/shared/report-card/report-card.component.ts index 92e6ddb0028..e8ffcd01068 100644 --- a/apps/web/src/app/dirt/reports/shared/report-card/report-card.component.ts +++ b/apps/web/src/app/dirt/reports/shared/report-card/report-card.component.ts @@ -2,7 +2,7 @@ // @ts-strict-ignore import { Component, Input } from "@angular/core"; -import { Icon } from "@bitwarden/components"; +import { Icon } from "@bitwarden/assets/svg"; import { ReportVariant } from "../models/report-variant"; diff --git a/apps/web/src/app/layouts/password-manager-logo.ts b/apps/web/src/app/layouts/password-manager-logo.ts deleted file mode 100644 index d93e2d5bb30..00000000000 --- a/apps/web/src/app/layouts/password-manager-logo.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { svgIcon } from "@bitwarden/components"; - -export const PasswordManagerLogo = svgIcon` - -`; diff --git a/apps/web/src/app/layouts/user-layout.component.ts b/apps/web/src/app/layouts/user-layout.component.ts index db4c181cd0f..37b35ee41be 100644 --- a/apps/web/src/app/layouts/user-layout.component.ts +++ b/apps/web/src/app/layouts/user-layout.component.ts @@ -6,10 +6,11 @@ import { RouterModule } from "@angular/router"; import { Observable, switchMap } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { PasswordManagerLogo } from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { SyncService } from "@bitwarden/common/platform/sync"; -import { IconModule, PasswordManagerLogo } from "@bitwarden/components"; +import { IconModule } from "@bitwarden/components"; import { BillingFreeFamiliesNavItemComponent } from "../billing/shared/billing-free-families-nav-item.component"; diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts index 4c1ed1a7472..9536ba19cc8 100644 --- a/apps/web/src/app/oss-routing.module.ts +++ b/apps/web/src/app/oss-routing.module.ts @@ -12,6 +12,19 @@ import { } from "@bitwarden/angular/auth/guards"; import { ChangePasswordComponent } from "@bitwarden/angular/auth/password-management/change-password"; import { SetInitialPasswordComponent } from "@bitwarden/angular/auth/password-management/set-initial-password/set-initial-password.component"; +import { + DevicesIcon, + RegistrationLockAltIcon, + RegistrationUserAddIcon, + TwoFactorTimeoutIcon, + DeviceVerificationIcon, + UserLockIcon, + VaultIcon, + RegistrationExpiredLinkIcon, + SsoKeyIcon, + LockIcon, + BrowserExtensionIcon, +} from "@bitwarden/assets/svg"; import { PasswordHintComponent, RegistrationFinishComponent, @@ -21,25 +34,15 @@ import { RegistrationLinkExpiredComponent, LoginComponent, LoginSecondaryContentComponent, - TwoFactorTimeoutIcon, - UserLockIcon, - SsoKeyIcon, LoginViaAuthRequestComponent, - DevicesIcon, - RegistrationUserAddIcon, - RegistrationLockAltIcon, - RegistrationExpiredLinkIcon, SsoComponent, - VaultIcon, LoginDecryptionOptionsComponent, TwoFactorAuthComponent, TwoFactorAuthGuard, NewDeviceVerificationComponent, - DeviceVerificationIcon, } from "@bitwarden/auth/angular"; -import { AnonLayoutWrapperComponent, AnonLayoutWrapperData, Icons } from "@bitwarden/components"; +import { AnonLayoutWrapperComponent, AnonLayoutWrapperData } from "@bitwarden/components"; import { LockComponent } from "@bitwarden/key-management-ui"; -import { VaultIcons } from "@bitwarden/vault"; import { flagEnabled, Flags } from "../utils/flags"; @@ -374,7 +377,7 @@ const routes: Routes = [ pageTitle: { key: "yourVaultIsLockedV2", }, - pageIcon: Icons.LockIcon, + pageIcon: LockIcon, showReadonlyHostname: true, } satisfies AnonLayoutWrapperData, }, @@ -533,7 +536,7 @@ const routes: Routes = [ { path: "browser-extension-prompt", data: { - pageIcon: VaultIcons.BrowserExtensionIcon, + pageIcon: BrowserExtensionIcon, } satisfies AnonLayoutWrapperData, children: [ { diff --git a/apps/web/src/app/tools/send/send-access/access.component.ts b/apps/web/src/app/tools/send/send-access/access.component.ts index bc2851f0df7..1636ac37b87 100644 --- a/apps/web/src/app/tools/send/send-access/access.component.ts +++ b/apps/web/src/app/tools/send/send-access/access.component.ts @@ -4,6 +4,7 @@ import { Component, OnInit } from "@angular/core"; import { FormBuilder } from "@angular/forms"; import { ActivatedRoute } from "@angular/router"; +import { ExpiredSendIcon } from "@bitwarden/assets/svg"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -18,7 +19,6 @@ import { SEND_KDF_ITERATIONS } from "@bitwarden/common/tools/send/send-kdf"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { AnonLayoutWrapperDataService, NoItemsModule, ToastService } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; -import { ExpiredSendIcon } from "@bitwarden/send-ui"; import { SharedModule } from "../../../shared"; diff --git a/apps/web/src/app/tools/send/send-access/routes.ts b/apps/web/src/app/tools/send/send-access/routes.ts index 4f794aecd23..e94453c9351 100644 --- a/apps/web/src/app/tools/send/send-access/routes.ts +++ b/apps/web/src/app/tools/send/send-access/routes.ts @@ -1,7 +1,7 @@ import { Routes } from "@angular/router"; +import { ActiveSendIcon } from "@bitwarden/assets/svg"; import { AnonLayoutWrapperData } from "@bitwarden/components"; -import { ActiveSendIcon } from "@bitwarden/send-ui"; import { RouteDataProperties } from "../../../core"; diff --git a/apps/web/src/app/tools/send/send.component.ts b/apps/web/src/app/tools/send/send.component.ts index b74a3b80ee3..20b93a10975 100644 --- a/apps/web/src/app/tools/send/send.component.ts +++ b/apps/web/src/app/tools/send/send.component.ts @@ -4,6 +4,7 @@ import { Component, NgZone, OnInit, OnDestroy } from "@angular/core"; import { lastValueFrom } from "rxjs"; import { SendComponent as BaseSendComponent } from "@bitwarden/angular/tools/send/send.component"; +import { NoSendsIcon } from "@bitwarden/assets/svg"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; @@ -26,7 +27,6 @@ import { } from "@bitwarden/components"; import { DefaultSendFormConfigService, - NoSendsIcon, SendFormConfig, SendAddEditDialogComponent, SendItemDialogResult, diff --git a/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.ts b/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.ts index 22041b61198..646ff76311e 100644 --- a/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.ts +++ b/apps/web/src/app/vault/components/manually-open-extension/manually-open-extension.component.ts @@ -1,8 +1,8 @@ import { Component } from "@angular/core"; +import { BitwardenIcon } from "@bitwarden/assets/svg"; import { IconModule } from "@bitwarden/components"; import { I18nPipe } from "@bitwarden/ui-common"; -import { VaultIcons } from "@bitwarden/vault"; @Component({ selector: "vault-manually-open-extension", @@ -10,5 +10,5 @@ import { VaultIcons } from "@bitwarden/vault"; imports: [I18nPipe, IconModule], }) export class ManuallyOpenExtensionComponent { - protected BitwardenIcon = VaultIcons.BitwardenIcon; + protected BitwardenIcon = BitwardenIcon; } diff --git a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.spec.ts b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.spec.ts index 8bb80e6fb44..cd4d421a7b9 100644 --- a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.spec.ts +++ b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.spec.ts @@ -3,6 +3,7 @@ import { By } from "@angular/platform-browser"; import { Router, RouterModule } from "@angular/router"; import { BehaviorSubject } from "rxjs"; +import { BrowserExtensionIcon } from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { DeviceType } from "@bitwarden/common/enums"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; @@ -12,7 +13,6 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { Utils } from "@bitwarden/common/platform/misc/utils"; import { StateProvider } from "@bitwarden/common/platform/state"; import { AnonLayoutWrapperDataService } from "@bitwarden/components"; -import { VaultIcons } from "@bitwarden/vault"; import { WebBrowserInteractionService } from "../../services/web-browser-interaction.service"; @@ -156,7 +156,7 @@ describe("SetupExtensionComponent", () => { pageTitle: { key: "somethingWentWrong", }, - pageIcon: VaultIcons.BrowserExtensionIcon, + pageIcon: BrowserExtensionIcon, hideIcon: false, hideCardWrapper: false, maxWidth: "md", diff --git a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts index 67d13ef1e4f..a36627081f2 100644 --- a/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts +++ b/apps/web/src/app/vault/components/setup-extension/setup-extension.component.ts @@ -5,6 +5,7 @@ import { Router, RouterModule } from "@angular/router"; import { firstValueFrom, pairwise, startWith } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { BrowserExtensionIcon, Party } from "@bitwarden/assets/svg"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; @@ -22,7 +23,6 @@ import { IconModule, LinkModule, } from "@bitwarden/components"; -import { VaultIcons } from "@bitwarden/vault"; import { SETUP_EXTENSION_DISMISSED } from "../../guards/setup-extension-redirect.guard"; import { WebBrowserInteractionService } from "../../services/web-browser-interaction.service"; @@ -70,7 +70,7 @@ export class SetupExtensionComponent implements OnInit, OnDestroy { private anonLayoutWrapperDataService = inject(AnonLayoutWrapperDataService); protected SetupExtensionState = SetupExtensionState; - protected PartyIcon = VaultIcons.Party; + protected PartyIcon = Party; /** The current state of the setup extension component. */ protected state: SetupExtensionState = SetupExtensionState.Loading; @@ -167,7 +167,7 @@ export class SetupExtensionComponent implements OnInit, OnDestroy { pageTitle: { key: "somethingWentWrong", }, - pageIcon: VaultIcons.BrowserExtensionIcon, + pageIcon: BrowserExtensionIcon, hideIcon: false, hideCardWrapper: false, maxWidth: "md", diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index ca8b05c2701..7593e9c59bf 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -35,6 +35,7 @@ import { Unassigned, } from "@bitwarden/admin-console/common"; import { SearchPipe } from "@bitwarden/angular/pipes/search.pipe"; +import { Search } from "@bitwarden/assets/svg"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; @@ -72,7 +73,7 @@ import { CipherViewLikeUtils, } from "@bitwarden/common/vault/utils/cipher-view-like-utils"; import { filterOutNullish } from "@bitwarden/common/vault/utils/observable-utilities"; -import { DialogRef, DialogService, Icons, ToastService } from "@bitwarden/components"; +import { DialogRef, DialogService, ToastService } from "@bitwarden/components"; import { CipherListView } from "@bitwarden/sdk-internal"; import { AddEditFolderDialogComponent, @@ -163,7 +164,7 @@ export class VaultComponent implements OnInit, OnDestr kdfIterations: number; activeFilter: VaultFilter = new VaultFilter(); - protected noItemIcon = Icons.Search; + protected noItemIcon = Search; protected performingInitialLoad = true; protected refreshing = false; protected processingEvent = false; diff --git a/apps/web/tailwind.config.js b/apps/web/tailwind.config.js index d33f94e94a9..0e1ae28abd1 100644 --- a/apps/web/tailwind.config.js +++ b/apps/web/tailwind.config.js @@ -4,6 +4,7 @@ const config = require("../../libs/components/tailwind.config.base"); config.content = [ "./src/**/*.{html,ts}", "../../libs/components/src/**/*.{html,ts}", + "../../libs/assets/src/**/*.{html,ts}", "../../libs/auth/src/**/*.{html,ts}", "../../libs/key-management-ui/src/**/*.{html,ts}", "../../libs/vault/src/**/*.{html,ts}", diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts index 3f698421e2d..f41b91261f7 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts @@ -6,6 +6,7 @@ import { BehaviorSubject, Subject, switchMap, takeUntil, tap } from "rxjs"; import { OrganizationUserApiService } from "@bitwarden/admin-console/common"; import { SafeProvider, safeProvider } from "@bitwarden/angular/platform/utils/safe-provider"; +import { Devices } from "@bitwarden/assets/svg"; import { OrganizationAuthRequestApiService } from "@bitwarden/bit-common/admin-console/auth-requests/organization-auth-request-api.service"; import { OrganizationAuthRequestService } from "@bitwarden/bit-common/admin-console/auth-requests/organization-auth-request.service"; import { PendingAuthRequestWithFingerprintView } from "@bitwarden/bit-common/admin-console/auth-requests/pending-auth-request-with-fingerprint.view"; @@ -20,7 +21,6 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { TableDataSource, NoItemsModule, ToastService } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; -import { Devices } from "@bitwarden/web-vault/app/admin-console/icons"; import { LooseComponentsModule } from "@bitwarden/web-vault/app/shared"; import { SharedModule } from "@bitwarden/web-vault/app/shared/shared.module"; diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/accept-provider.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/accept-provider.component.ts index 7696742277a..9f28ba87186 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/manage/accept-provider.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/manage/accept-provider.component.ts @@ -3,12 +3,12 @@ import { Component } from "@angular/core"; import { ActivatedRoute, Params, Router } from "@angular/router"; +import { BitwardenLogo } from "@bitwarden/assets/svg"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ProviderUserAcceptRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-user-accept.request"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { Icons } from "@bitwarden/components"; import { BaseAcceptComponent } from "@bitwarden/web-vault/app/common/base.accept.component"; @Component({ @@ -17,7 +17,7 @@ import { BaseAcceptComponent } from "@bitwarden/web-vault/app/common/base.accept standalone: false, }) export class AcceptProviderComponent extends BaseAcceptComponent { - protected logo = Icons.BitwardenLogo; + protected logo = BitwardenLogo; providerName: string; providerId: string; providerUserId: string; diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.ts index 5e2e9a14f2d..159a0105df9 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.ts @@ -7,17 +7,13 @@ import { combineLatest, map, Observable, Subject, switchMap } from "rxjs"; import { takeUntil } from "rxjs/operators"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { BusinessUnitPortalLogo, Icon, ProviderPortalLogo } from "@bitwarden/assets/svg"; import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service"; import { ProviderStatusType, ProviderType } from "@bitwarden/common/admin-console/enums"; import { Provider } from "@bitwarden/common/admin-console/models/domain/provider"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; -import { - Icon, - IconModule, - ProviderPortalLogo, - BusinessUnitPortalLogo, -} from "@bitwarden/components"; +import { IconModule } from "@bitwarden/components"; import { NonIndividualSubscriber } from "@bitwarden/web-vault/app/billing/types"; import { TaxIdWarningComponent } from "@bitwarden/web-vault/app/billing/warnings/components"; import { TaxIdWarningType } from "@bitwarden/web-vault/app/billing/warnings/types"; diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup-provider.component.ts b/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup-provider.component.ts index 47c30490af3..02ca72fa9b8 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup-provider.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/setup/setup-provider.component.ts @@ -1,7 +1,7 @@ import { Component } from "@angular/core"; import { Params } from "@angular/router"; -import { Icons } from "@bitwarden/components"; +import { BitwardenLogo } from "@bitwarden/assets/svg"; import { BaseAcceptComponent } from "@bitwarden/web-vault/app/common/base.accept.component"; @Component({ @@ -10,7 +10,7 @@ import { BaseAcceptComponent } from "@bitwarden/web-vault/app/common/base.accept standalone: false, }) export class SetupProviderComponent extends BaseAcceptComponent { - protected logo = Icons.BitwardenLogo; + protected logo = BitwardenLogo; failedShortMessage = "inviteAcceptFailedShort"; failedMessage = "inviteAcceptFailed"; diff --git a/bitwarden_license/bit-web/src/app/billing/providers/clients/no-clients.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/clients/no-clients.component.ts index 039c42de302..8ff5d070241 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/clients/no-clients.component.ts +++ b/bitwarden_license/bit-web/src/app/billing/providers/clients/no-clients.component.ts @@ -1,27 +1,8 @@ import { Component, EventEmitter, Input, Output } from "@angular/core"; -import { svgIcon } from "@bitwarden/components"; +import { GearIcon } from "@bitwarden/assets/svg"; import { SharedOrganizationModule } from "@bitwarden/web-vault/app/admin-console/organizations/shared"; -const gearIcon = svgIcon` - - - - - - - - - - - - - - - - -`; - @Component({ selector: "app-no-clients", imports: [SharedOrganizationModule], @@ -42,7 +23,7 @@ const gearIcon = svgIcon`
`, }) export class NoClientsComponent { - icon = gearIcon; + icon = GearIcon; @Input() showAddOrganizationButton = true; @Input() disableAddOrganizationButton = false; @Output() addNewOrganizationClicked = new EventEmitter(); diff --git a/bitwarden_license/bit-web/src/app/billing/providers/setup/setup-business-unit.component.ts b/bitwarden_license/bit-web/src/app/billing/providers/setup/setup-business-unit.component.ts index 0634c891a05..c964108936a 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/setup/setup-business-unit.component.ts +++ b/bitwarden_license/bit-web/src/app/billing/providers/setup/setup-business-unit.component.ts @@ -3,6 +3,7 @@ import { ActivatedRoute, Params, Router } from "@angular/router"; import { firstValueFrom } from "rxjs"; import { filter, map, switchMap } from "rxjs/operators"; +import { BitwardenLogo } from "@bitwarden/assets/svg"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { OrganizationBillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/organizations/organization-billing-api.service.abstraction"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; @@ -12,7 +13,6 @@ import { StateProvider } from "@bitwarden/common/platform/state"; import { SyncService } from "@bitwarden/common/platform/sync"; import { OrganizationId } from "@bitwarden/common/types/guid"; import { ProviderKey } from "@bitwarden/common/types/key"; -import { Icons } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; import { BillingNotificationService } from "@bitwarden/web-vault/app/billing/services/billing-notification.service"; import { BaseAcceptComponent } from "@bitwarden/web-vault/app/common/base.accept.component"; @@ -22,7 +22,7 @@ import { BaseAcceptComponent } from "@bitwarden/web-vault/app/common/base.accept standalone: false, }) export class SetupBusinessUnitComponent extends BaseAcceptComponent { - protected bitwardenLogo = Icons.BitwardenLogo; + protected bitwardenLogo = BitwardenLogo; failedMessage = "emergencyInviteAcceptFailed"; failedShortMessage = "emergencyInviteAcceptFailedShort"; diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/all-applications.component.ts b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/all-applications.component.ts index ee08ec6661e..1ce9ab9a2e6 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/all-applications.component.ts +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/all-applications.component.ts @@ -4,6 +4,7 @@ import { FormControl } from "@angular/forms"; import { ActivatedRoute } from "@angular/router"; import { combineLatest, debounceTime, firstValueFrom, map, Observable, of, switchMap } from "rxjs"; +import { Security } from "@bitwarden/assets/svg"; import { CriticalAppsService, RiskInsightsDataService, @@ -27,7 +28,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { IconButtonModule, - Icons, NoItemsModule, SearchModule, TableDataSource, @@ -63,7 +63,7 @@ export class AllApplicationsComponent implements OnInit { protected searchControl = new FormControl("", { nonNullable: true }); protected loading = true; protected organization = new Organization(); - noItemsIcon = Icons.Security; + noItemsIcon = Security; protected markingAsCritical = false; protected applicationSummary: ApplicationHealthReportSummary = { totalMemberCount: 0, diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.ts b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.ts index 4f9a9930f1c..531adc003c7 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.ts +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.ts @@ -6,6 +6,7 @@ import { FormControl } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; import { combineLatest, debounceTime, map, switchMap } from "rxjs"; +import { Security } from "@bitwarden/assets/svg"; import { CriticalAppsService, RiskInsightsDataService, @@ -20,13 +21,7 @@ import { ConfigService } from "@bitwarden/common/platform/abstractions/config/co import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { CipherId, OrganizationId } from "@bitwarden/common/types/guid"; import { SecurityTaskType } from "@bitwarden/common/vault/tasks"; -import { - Icons, - NoItemsModule, - SearchModule, - TableDataSource, - ToastService, -} from "@bitwarden/components"; +import { NoItemsModule, SearchModule, TableDataSource, ToastService } from "@bitwarden/components"; import { CardComponent } from "@bitwarden/dirt-card"; import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.module"; import { SharedModule } from "@bitwarden/web-vault/app/shared"; @@ -61,7 +56,7 @@ export class CriticalApplicationsComponent implements OnInit { protected loading = false; protected organizationId: string; protected applicationSummary = {} as ApplicationHealthReportSummary; - noItemsIcon = Icons.Security; + noItemsIcon = Security; enableRequestPasswordChange = false; async ngOnInit() { diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.ts index 24da000f213..a714bc0d543 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.ts @@ -15,6 +15,7 @@ import { takeUntil, } from "rxjs"; +import { SecretsManagerLogo } from "@bitwarden/assets/svg"; import { getOrganizationById, OrganizationService, @@ -22,7 +23,6 @@ import { import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { SecretsManagerLogo } from "@bitwarden/components"; import { OrganizationCounts } from "../models/view/counts.view"; import { ProjectService } from "../projects/project.service"; diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/org-suspended.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/shared/org-suspended.component.ts index 89baf969c34..0a7d6befde2 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/shared/org-suspended.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/org-suspended.component.ts @@ -2,13 +2,13 @@ import { Component } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { map, concatMap, firstValueFrom } from "rxjs"; +import { Icon, NoAccess } from "@bitwarden/assets/svg"; import { getOrganizationById, OrganizationService, } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { Icon, Icons } from "@bitwarden/components"; @Component({ templateUrl: "./org-suspended.component.html", @@ -21,7 +21,7 @@ export class OrgSuspendedComponent { private route: ActivatedRoute, ) {} - protected NoAccess: Icon = Icons.NoAccess; + protected NoAccess: Icon = NoAccess; protected organizationName$ = this.route.params.pipe( concatMap(async (params) => { const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$)); diff --git a/libs/angular/src/auth/components/two-factor-icon.component.ts b/libs/angular/src/auth/components/two-factor-icon.component.ts index 0e811595bea..8c650b6b04c 100644 --- a/libs/angular/src/auth/components/two-factor-icon.component.ts +++ b/libs/angular/src/auth/components/two-factor-icon.component.ts @@ -2,10 +2,7 @@ // @ts-strict-ignore import { Component, Input } from "@angular/core"; -import { EmailIcon } from "../icons/email.icon"; -import { RecoveryCodeIcon } from "../icons/recovery.icon"; -import { TOTPIcon } from "../icons/totp.icon"; -import { WebAuthnIcon } from "../icons/webauthn.icon"; +import { EmailIcon, RecoveryCodeIcon, TOTPIcon, WebAuthnIcon } from "@bitwarden/assets/svg"; @Component({ selector: "auth-two-factor-icon", diff --git a/libs/angular/src/auth/icons/create-passkey.icon.ts b/libs/angular/src/auth/icons/create-passkey.icon.ts deleted file mode 100644 index 79ba4021b58..00000000000 --- a/libs/angular/src/auth/icons/create-passkey.icon.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { svgIcon } from "@bitwarden/components"; - -export const CreatePasskeyIcon = svgIcon` - - - - - - - - - - -`; diff --git a/libs/angular/src/auth/password-management/change-password/change-password.component.ts b/libs/angular/src/auth/password-management/change-password/change-password.component.ts index 7bb9584e934..1512f348133 100644 --- a/libs/angular/src/auth/password-management/change-password/change-password.component.ts +++ b/libs/angular/src/auth/password-management/change-password/change-password.component.ts @@ -2,6 +2,7 @@ import { CommonModule } from "@angular/common"; import { Component, Input, OnInit } from "@angular/core"; import { firstValueFrom } from "rxjs"; +import { LockIcon } from "@bitwarden/assets/svg"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports import { @@ -24,7 +25,6 @@ import { AnonLayoutWrapperDataService, DialogService, ToastService, - Icons, CalloutComponent, } from "@bitwarden/components"; import { I18nPipe } from "@bitwarden/ui-common"; @@ -97,13 +97,13 @@ export class ChangePasswordComponent implements OnInit { if (this.forceSetPasswordReason === ForceSetPasswordReason.AdminForcePasswordReset) { this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ - pageIcon: Icons.LockIcon, + pageIcon: LockIcon, pageTitle: { key: "updateMasterPassword" }, pageSubtitle: { key: "accountRecoveryUpdateMasterPasswordSubtitle" }, }); } else if (this.forceSetPasswordReason === ForceSetPasswordReason.WeakMasterPassword) { this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ - pageIcon: Icons.LockIcon, + pageIcon: LockIcon, pageTitle: { key: "updateMasterPassword" }, pageSubtitle: { key: "updateMasterPasswordSubtitle" }, maxWidth: "lg", diff --git a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts index 27d4c11f692..c31495b60fb 100644 --- a/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts +++ b/libs/angular/src/auth/password-management/set-initial-password/set-initial-password.component.ts @@ -1,9 +1,9 @@ import { CommonModule } from "@angular/common"; import { Component, OnInit } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; -// import { NoAccess } from "libs/components/src/icon/icons"; import { firstValueFrom } from "rxjs"; +import { NoAccess } from "@bitwarden/assets/svg"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports import { @@ -35,7 +35,6 @@ import { CalloutComponent, DialogService, ToastService, - Icons, } from "@bitwarden/components"; import { I18nPipe } from "@bitwarden/ui-common"; @@ -113,7 +112,7 @@ export class SetInitialPasswordComponent implements OnInit { this.userType = SetInitialPasswordUserType.OFFBOARDED_TDE_ORG_USER_UNTRUSTED_DEVICE; this.anonLayoutWrapperDataService.setAnonLayoutWrapperData({ pageTitle: { key: "unableToCompleteLogin" }, - pageIcon: Icons.NoAccess, + pageIcon: NoAccess, }); } diff --git a/libs/angular/src/billing/components/invoices/no-invoices.component.ts b/libs/angular/src/billing/components/invoices/no-invoices.component.ts index 987650d1c83..5251fc0133b 100644 --- a/libs/angular/src/billing/components/invoices/no-invoices.component.ts +++ b/libs/angular/src/billing/components/invoices/no-invoices.component.ts @@ -1,28 +1,6 @@ import { Component } from "@angular/core"; -import { svgIcon } from "@bitwarden/components"; - -const partnerTrustIcon = svgIcon` - - - - - - - - - - - - - - - - - - - -`; +import { PartnerTrustIcon } from "@bitwarden/assets/svg"; @Component({ selector: "app-no-invoices", @@ -33,5 +11,5 @@ const partnerTrustIcon = svgIcon` standalone: false, }) export class NoInvoicesComponent { - icon = partnerTrustIcon; + icon = PartnerTrustIcon; } diff --git a/libs/assets/README.md b/libs/assets/README.md new file mode 100644 index 00000000000..60df3f8992a --- /dev/null +++ b/libs/assets/README.md @@ -0,0 +1,16 @@ +# Assets + +Owned by: ui-foundation + +This lib contains assets used by the Bitwarden clients. Unused assets are tree-shaken from client bundles. This means that all exports from this library must not have any [side effects](https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free). + +## Usage + +### SVGs + +SVGs intended to be used with the `bit-icon` component live in `src/svgs`. These SVGs are built with the `icon-service` for security reasons. These SVGs can be viewed in our Component Library [Icon Story](https://components.bitwarden.com/?path=/story/component-library-icon--default). + +When adding a new SVG, follow the instructions in our Component Library: [SVG Icon Docs](https://components.bitwarden.com/?path=/docs/component-library-icon--docs) + +When importing an SVG in one of the clients: +`import { ExampleSvg } from "@bitwarden/assets/svg";` diff --git a/libs/assets/eslint.config.mjs b/libs/assets/eslint.config.mjs new file mode 100644 index 00000000000..9c37d10e3ff --- /dev/null +++ b/libs/assets/eslint.config.mjs @@ -0,0 +1,3 @@ +import baseConfig from "../../eslint.config.mjs"; + +export default [...baseConfig]; diff --git a/libs/assets/jest.config.js b/libs/assets/jest.config.js new file mode 100644 index 00000000000..fae52410152 --- /dev/null +++ b/libs/assets/jest.config.js @@ -0,0 +1,10 @@ +module.exports = { + displayName: "assets", + preset: "../../jest.preset.js", + testEnvironment: "node", + transform: { + "^.+\\.[tj]s$": ["ts-jest", { tsconfig: "/tsconfig.spec.json" }], + }, + moduleFileExtensions: ["ts", "js", "html"], + coverageDirectory: "../../coverage/libs/assets", +}; diff --git a/libs/assets/package.json b/libs/assets/package.json new file mode 100644 index 00000000000..cc5935833bf --- /dev/null +++ b/libs/assets/package.json @@ -0,0 +1,15 @@ +{ + "name": "@bitwarden/assets", + "version": "0.0.1", + "description": "Assets used in Bitwarden clients", + "private": true, + "type": "commonjs", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "license": "GPL-3.0", + "author": "ui-foundation", + "scripts": { + "test": "jest" + }, + "sideEffects": false +} diff --git a/libs/assets/project.json b/libs/assets/project.json new file mode 100644 index 00000000000..97e32a24b33 --- /dev/null +++ b/libs/assets/project.json @@ -0,0 +1,33 @@ +{ + "name": "assets", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/assets/src", + "projectType": "library", + "tags": [], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/libs/assets", + "main": "libs/assets/src/index.ts", + "tsConfig": "libs/assets/tsconfig.lib.json", + "assets": ["libs/assets/*.md"] + } + }, + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/assets/**/*.ts"] + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/assets/jest.config.js" + } + } + } +} diff --git a/libs/components/src/icon/icon.spec.ts b/libs/assets/src/svg/icon-service.spec.ts similarity index 94% rename from libs/components/src/icon/icon.spec.ts rename to libs/assets/src/svg/icon-service.spec.ts index 3e7c011be93..2561c85aefa 100644 --- a/libs/components/src/icon/icon.spec.ts +++ b/libs/assets/src/svg/icon-service.spec.ts @@ -1,5 +1,5 @@ -import * as IconExports from "./icon"; -import { DynamicContentNotAllowedError, isIcon, svgIcon } from "./icon"; +import * as IconExports from "./icon-service"; +import { DynamicContentNotAllowedError, isIcon, svgIcon } from "./icon-service"; describe("Icon", () => { it("exports should not expose Icon class", () => { diff --git a/libs/components/src/icon/icon.ts b/libs/assets/src/svg/icon-service.ts similarity index 100% rename from libs/components/src/icon/icon.ts rename to libs/assets/src/svg/icon-service.ts diff --git a/libs/assets/src/svg/index.ts b/libs/assets/src/svg/index.ts new file mode 100644 index 00000000000..9f86a14f772 --- /dev/null +++ b/libs/assets/src/svg/index.ts @@ -0,0 +1,2 @@ +export * from "./svgs"; +export * from "./icon-service"; diff --git a/libs/tools/send/send-ui/src/icons/active-send.icon.ts b/libs/assets/src/svg/svgs/active-send.icon.ts similarity index 98% rename from libs/tools/send/send-ui/src/icons/active-send.icon.ts rename to libs/assets/src/svg/svgs/active-send.icon.ts index da5932bf95c..be5cb4540f7 100644 --- a/libs/tools/send/send-ui/src/icons/active-send.icon.ts +++ b/libs/assets/src/svg/svgs/active-send.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const ActiveSendIcon = svgIcon` diff --git a/libs/components/src/icon/logos/bitwarden/admin-console.ts b/libs/assets/src/svg/svgs/admin-console.ts similarity index 99% rename from libs/components/src/icon/logos/bitwarden/admin-console.ts rename to libs/assets/src/svg/svgs/admin-console.ts index 5fa96d91dfe..aa59c3f7e86 100644 --- a/libs/components/src/icon/logos/bitwarden/admin-console.ts +++ b/libs/assets/src/svg/svgs/admin-console.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../../icon"; +import { svgIcon } from "../icon-service"; const AdminConsoleLogo = svgIcon` diff --git a/libs/components/src/anon-layout/illustrations/left-illustration.ts b/libs/assets/src/svg/svgs/background-left-illustration.ts similarity index 99% rename from libs/components/src/anon-layout/illustrations/left-illustration.ts rename to libs/assets/src/svg/svgs/background-left-illustration.ts index 26fe9f6076b..50d9e76fb53 100644 --- a/libs/components/src/anon-layout/illustrations/left-illustration.ts +++ b/libs/assets/src/svg/svgs/background-left-illustration.ts @@ -1,5 +1,5 @@ -import { svgIcon } from "../../icon"; +import { svgIcon } from "../icon-service"; -export const LeftIllustration = svgIcon` +export const BackgroundLeftIllustration = svgIcon` `; diff --git a/libs/components/src/anon-layout/illustrations/right-illustration.ts b/libs/assets/src/svg/svgs/background-right-illustration.ts similarity index 99% rename from libs/components/src/anon-layout/illustrations/right-illustration.ts rename to libs/assets/src/svg/svgs/background-right-illustration.ts index ba3003ee01f..52be2213c3b 100644 --- a/libs/components/src/anon-layout/illustrations/right-illustration.ts +++ b/libs/assets/src/svg/svgs/background-right-illustration.ts @@ -1,5 +1,5 @@ -import { svgIcon } from "../../icon"; +import { svgIcon } from "../icon-service"; -export const RightIllustration = svgIcon` +export const BackgroundRightIllustration = svgIcon` `; diff --git a/libs/vault/src/icons/bitwarden-icon.ts b/libs/assets/src/svg/svgs/bitwarden-icon.ts similarity index 97% rename from libs/vault/src/icons/bitwarden-icon.ts rename to libs/assets/src/svg/svgs/bitwarden-icon.ts index 73e4304d5c7..710d20937bd 100644 --- a/libs/vault/src/icons/bitwarden-icon.ts +++ b/libs/assets/src/svg/svgs/bitwarden-icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const BitwardenIcon = svgIcon` diff --git a/libs/components/src/icon/icons/bitwarden-logo.icon.ts b/libs/assets/src/svg/svgs/bitwarden-logo.icon.ts similarity index 99% rename from libs/components/src/icon/icons/bitwarden-logo.icon.ts rename to libs/assets/src/svg/svgs/bitwarden-logo.icon.ts index 27b8ece164d..9c1c7248ec6 100644 --- a/libs/components/src/icon/icons/bitwarden-logo.icon.ts +++ b/libs/assets/src/svg/svgs/bitwarden-logo.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../icon"; +import { svgIcon } from "../icon-service"; export const BitwardenLogo = svgIcon` diff --git a/libs/vault/src/icons/browser-extension.ts b/libs/assets/src/svg/svgs/browser-extension.ts similarity index 97% rename from libs/vault/src/icons/browser-extension.ts rename to libs/assets/src/svg/svgs/browser-extension.ts index ac54322292f..4e3b54e77cd 100644 --- a/libs/vault/src/icons/browser-extension.ts +++ b/libs/assets/src/svg/svgs/browser-extension.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const BrowserExtensionIcon = svgIcon` diff --git a/libs/components/src/icon/logos/bitwarden/business-unit-portal.ts b/libs/assets/src/svg/svgs/business-unit-portal.ts similarity index 99% rename from libs/components/src/icon/logos/bitwarden/business-unit-portal.ts rename to libs/assets/src/svg/svgs/business-unit-portal.ts index 6206256f88b..66b30ba06be 100644 --- a/libs/components/src/icon/logos/bitwarden/business-unit-portal.ts +++ b/libs/assets/src/svg/svgs/business-unit-portal.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../../icon"; +import { svgIcon } from "../icon-service"; const BusinessUnitPortalLogo = svgIcon` diff --git a/libs/vault/src/components/carousel/carousel-icons/carousel-icon.ts b/libs/assets/src/svg/svgs/carousel-icon.ts similarity index 85% rename from libs/vault/src/components/carousel/carousel-icons/carousel-icon.ts rename to libs/assets/src/svg/svgs/carousel-icon.ts index 64052e6fa6c..802f6ff1435 100644 --- a/libs/vault/src/components/carousel/carousel-icons/carousel-icon.ts +++ b/libs/assets/src/svg/svgs/carousel-icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const CarouselIcon = svgIcon` diff --git a/libs/angular/src/auth/icons/create-passkey-failed.icon.ts b/libs/assets/src/svg/svgs/create-passkey-failed.icon.ts similarity index 98% rename from libs/angular/src/auth/icons/create-passkey-failed.icon.ts rename to libs/assets/src/svg/svgs/create-passkey-failed.icon.ts index 65902a64c9f..37e679b9b5e 100644 --- a/libs/angular/src/auth/icons/create-passkey-failed.icon.ts +++ b/libs/assets/src/svg/svgs/create-passkey-failed.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const CreatePasskeyFailedIcon = svgIcon` diff --git a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey.icon.ts b/libs/assets/src/svg/svgs/create-passkey.icon.ts similarity index 98% rename from apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey.icon.ts rename to libs/assets/src/svg/svgs/create-passkey.icon.ts index 79ba4021b58..efe180e1e2f 100644 --- a/apps/web/src/app/auth/settings/webauthn-login-settings/create-credential-dialog/create-passkey.icon.ts +++ b/libs/assets/src/svg/svgs/create-passkey.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const CreatePasskeyIcon = svgIcon` diff --git a/libs/vault/src/icons/deactivated-org.ts b/libs/assets/src/svg/svgs/deactivated-org.ts similarity index 98% rename from libs/vault/src/icons/deactivated-org.ts rename to libs/assets/src/svg/svgs/deactivated-org.ts index 5f7c910aec8..92a1064e31e 100644 --- a/libs/vault/src/icons/deactivated-org.ts +++ b/libs/assets/src/svg/svgs/deactivated-org.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const DeactivatedOrg = svgIcon` diff --git a/libs/auth/src/angular/icons/device-verification.icon.ts b/libs/assets/src/svg/svgs/device-verification.icon.ts similarity index 89% rename from libs/auth/src/angular/icons/device-verification.icon.ts rename to libs/assets/src/svg/svgs/device-verification.icon.ts index 6c5313a8705..c8fccbf7eca 100644 --- a/libs/auth/src/angular/icons/device-verification.icon.ts +++ b/libs/assets/src/svg/svgs/device-verification.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const DeviceVerificationIcon = svgIcon` diff --git a/libs/auth/src/angular/icons/devices.icon.ts b/libs/assets/src/svg/svgs/devices.icon.ts similarity index 91% rename from libs/auth/src/angular/icons/devices.icon.ts rename to libs/assets/src/svg/svgs/devices.icon.ts index dd268f0e6e2..471b44017b1 100644 --- a/libs/auth/src/angular/icons/devices.icon.ts +++ b/libs/assets/src/svg/svgs/devices.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const DevicesIcon = svgIcon` diff --git a/apps/web/src/app/admin-console/icons/devices.ts b/libs/assets/src/svg/svgs/devices.ts similarity index 98% rename from apps/web/src/app/admin-console/icons/devices.ts rename to libs/assets/src/svg/svgs/devices.ts index 9faddb0b2ee..517256ec591 100644 --- a/apps/web/src/app/admin-console/icons/devices.ts +++ b/libs/assets/src/svg/svgs/devices.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const Devices = svgIcon` diff --git a/libs/angular/src/auth/icons/email.icon.ts b/libs/assets/src/svg/svgs/email.icon.ts similarity index 92% rename from libs/angular/src/auth/icons/email.icon.ts rename to libs/assets/src/svg/svgs/email.icon.ts index 7b5163898fd..c6341707880 100644 --- a/libs/angular/src/auth/icons/email.icon.ts +++ b/libs/assets/src/svg/svgs/email.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const EmailIcon = svgIcon` - diff --git a/libs/vault/src/icons/empty-trash.ts b/libs/assets/src/svg/svgs/empty-trash.ts similarity index 99% rename from libs/vault/src/icons/empty-trash.ts rename to libs/assets/src/svg/svgs/empty-trash.ts index df74602e6d1..61df8933d44 100644 --- a/libs/vault/src/icons/empty-trash.ts +++ b/libs/assets/src/svg/svgs/empty-trash.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const EmptyTrash = svgIcon` diff --git a/libs/tools/send/send-ui/src/icons/expired-send.icon.ts b/libs/assets/src/svg/svgs/expired-send.icon.ts similarity index 98% rename from libs/tools/send/send-ui/src/icons/expired-send.icon.ts rename to libs/assets/src/svg/svgs/expired-send.icon.ts index c699a544e7c..19283525b4c 100644 --- a/libs/tools/send/send-ui/src/icons/expired-send.icon.ts +++ b/libs/assets/src/svg/svgs/expired-send.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const ExpiredSendIcon = svgIcon` diff --git a/libs/components/src/icon/icons/extension-bitwarden-logo.icon.ts b/libs/assets/src/svg/svgs/extension-bitwarden-logo.icon.ts similarity index 99% rename from libs/components/src/icon/icons/extension-bitwarden-logo.icon.ts rename to libs/assets/src/svg/svgs/extension-bitwarden-logo.icon.ts index a8a07d5d1ef..42a74e006bc 100644 --- a/libs/components/src/icon/icons/extension-bitwarden-logo.icon.ts +++ b/libs/assets/src/svg/svgs/extension-bitwarden-logo.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../icon"; +import { svgIcon } from "../icon-service"; export const ExtensionBitwardenLogo = svgIcon` + + + + + + + + + + + + + + + +`; diff --git a/libs/components/src/icon/icons/generator.ts b/libs/assets/src/svg/svgs/generator.ts similarity index 98% rename from libs/components/src/icon/icons/generator.ts rename to libs/assets/src/svg/svgs/generator.ts index 6d1e25abc27..52368ddc204 100644 --- a/libs/components/src/icon/icons/generator.ts +++ b/libs/assets/src/svg/svgs/generator.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../icon"; +import { svgIcon } from "../icon-service"; export const GeneratorInactive = svgIcon` diff --git a/libs/assets/src/svg/svgs/index.ts b/libs/assets/src/svg/svgs/index.ts new file mode 100644 index 00000000000..a5a4c215a29 --- /dev/null +++ b/libs/assets/src/svg/svgs/index.ts @@ -0,0 +1,72 @@ +export * from "./active-send.icon"; +export { default as AdminConsoleLogo } from "./admin-console"; +export * from "./background-left-illustration"; +export * from "./background-right-illustration"; +export * from "./bitwarden-icon"; +export * from "./bitwarden-logo.icon"; +export * from "./browser-extension"; +export { default as BusinessUnitPortalLogo } from "./business-unit-portal"; +export * from "./carousel-icon"; +export * from "./create-passkey-failed.icon"; +export * from "./create-passkey.icon"; +export * from "./deactivated-org"; +export * from "./device-verification.icon"; +export * from "./devices.icon"; +export * from "./devices"; +export * from "./email.icon"; +export * from "./empty-trash"; +export * from "./expired-send.icon"; +export * from "./extension-bitwarden-logo.icon"; +export * from "./gear"; +export * from "./generator"; +export * from "./lock.icon"; +export * from "./login-cards"; +export * from "./no-access"; +export * from "./no-credentials.icon"; +export * from "./no-folders"; +export * from "./no-results"; +export * from "./no-send.icon"; +export * from "./partner-trust"; +export * from "./party"; +export { default as PasswordManagerLogo } from "./password-manager"; +export { default as ProviderPortalLogo } from "./provider-portal"; +export * from "./recovery.icon"; +export * from "./registration-check-email.icon"; +export * from "./registration-expired-link.icon"; +export * from "./registration-lock-alt.icon"; +export * from "./registration-user-add.icon"; +export * from "./report-breach.icon"; +export * from "./report-exposed-passwords.icon"; +export * from "./report-inactive-two-factor.icon"; +export * from "./report-member-access.icon"; +export * from "./report-reused-passwords.icon"; +export * from "./report-unsecured-websites.icon"; +export * from "./report-weak-passwords.icon"; +export * from "./restricted-view"; +export * from "./search"; +export * from "./secrets-manager-alt"; +export { default as SecretsManagerLogo } from "./secrets-manager"; +export * from "./secure-devices"; +export * from "./secure-user"; +export * from "./security-handshake"; +export * from "./security"; +export * from "./send"; +export * from "./settings"; +export * from "./shield"; +export * from "./sso-key.icon"; +export * from "./subscription-hidden"; +export * from "./totp.icon"; +export * from "./two-factor-auth-authenticator.icon"; +export * from "./two-factor-auth-duo.icon"; +export * from "./two-factor-auth-email.icon"; +export * from "./two-factor-auth-security-key.icon"; +export * from "./two-factor-auth-webauthn.icon"; +export * from "./two-factor-auth-yubico.icon"; +export * from "./two-factor-timeout.icon"; +export * from "./user-lock.icon"; +export * from "./user-verification-biometrics-fingerprint.icon"; +export * from "./vault-open"; +export * from "./vault.icon"; +export * from "./vault"; +export * from "./wave.icon"; +export * from "./webauthn.icon"; diff --git a/libs/components/src/icon/icons/lock.icon.ts b/libs/assets/src/svg/svgs/lock.icon.ts similarity index 98% rename from libs/components/src/icon/icons/lock.icon.ts rename to libs/assets/src/svg/svgs/lock.icon.ts index d7a7e4abb1b..5d5d23bcdd1 100644 --- a/libs/components/src/icon/icons/lock.icon.ts +++ b/libs/assets/src/svg/svgs/lock.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../icon"; +import { svgIcon } from "../icon-service"; export const LockIcon = svgIcon` diff --git a/libs/vault/src/icons/login-cards.ts b/libs/assets/src/svg/svgs/login-cards.ts similarity index 98% rename from libs/vault/src/icons/login-cards.ts rename to libs/assets/src/svg/svgs/login-cards.ts index 6e066a0d924..0eea164a512 100644 --- a/libs/vault/src/icons/login-cards.ts +++ b/libs/assets/src/svg/svgs/login-cards.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const LoginCards = svgIcon` diff --git a/libs/components/src/icon/icons/no-access.ts b/libs/assets/src/svg/svgs/no-access.ts similarity index 96% rename from libs/components/src/icon/icons/no-access.ts rename to libs/assets/src/svg/svgs/no-access.ts index 1011b3089cf..6c9dfae939e 100644 --- a/libs/components/src/icon/icons/no-access.ts +++ b/libs/assets/src/svg/svgs/no-access.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../icon"; +import { svgIcon } from "../icon-service"; export const NoAccess = svgIcon` diff --git a/libs/tools/generator/components/src/icons/no-credentials.icon.ts b/libs/assets/src/svg/svgs/no-credentials.icon.ts similarity index 99% rename from libs/tools/generator/components/src/icons/no-credentials.icon.ts rename to libs/assets/src/svg/svgs/no-credentials.icon.ts index 7bb289600b8..a825de2f95b 100644 --- a/libs/tools/generator/components/src/icons/no-credentials.icon.ts +++ b/libs/assets/src/svg/svgs/no-credentials.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const NoCredentialsIcon = svgIcon` diff --git a/libs/vault/src/icons/no-folders.ts b/libs/assets/src/svg/svgs/no-folders.ts similarity index 98% rename from libs/vault/src/icons/no-folders.ts rename to libs/assets/src/svg/svgs/no-folders.ts index 666bfc86c4c..ea06a9827e9 100644 --- a/libs/vault/src/icons/no-folders.ts +++ b/libs/assets/src/svg/svgs/no-folders.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const NoFolders = svgIcon` diff --git a/libs/components/src/icon/icons/no-results.ts b/libs/assets/src/svg/svgs/no-results.ts similarity index 98% rename from libs/components/src/icon/icons/no-results.ts rename to libs/assets/src/svg/svgs/no-results.ts index 7ed886a06e9..ce45fce7f3c 100644 --- a/libs/components/src/icon/icons/no-results.ts +++ b/libs/assets/src/svg/svgs/no-results.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../icon"; +import { svgIcon } from "../icon-service"; export const NoResults = svgIcon` diff --git a/libs/tools/send/send-ui/src/icons/no-send.icon.ts b/libs/assets/src/svg/svgs/no-send.icon.ts similarity index 97% rename from libs/tools/send/send-ui/src/icons/no-send.icon.ts rename to libs/assets/src/svg/svgs/no-send.icon.ts index 555d8024601..85106930961 100644 --- a/libs/tools/send/send-ui/src/icons/no-send.icon.ts +++ b/libs/assets/src/svg/svgs/no-send.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const NoSendsIcon = svgIcon` diff --git a/libs/assets/src/svg/svgs/partner-trust.ts b/libs/assets/src/svg/svgs/partner-trust.ts new file mode 100644 index 00000000000..22249874118 --- /dev/null +++ b/libs/assets/src/svg/svgs/partner-trust.ts @@ -0,0 +1,23 @@ +import { svgIcon } from "../icon-service"; + +export const PartnerTrustIcon = svgIcon` + + + + + + + + + + + + + + + + + + + +`; diff --git a/libs/vault/src/icons/party.ts b/libs/assets/src/svg/svgs/party.ts similarity index 99% rename from libs/vault/src/icons/party.ts rename to libs/assets/src/svg/svgs/party.ts index 2e506c5d705..6fb587a7c14 100644 --- a/libs/vault/src/icons/party.ts +++ b/libs/assets/src/svg/svgs/party.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const Party = svgIcon` diff --git a/libs/components/src/icon/logos/bitwarden/password-manager.ts b/libs/assets/src/svg/svgs/password-manager.ts similarity index 99% rename from libs/components/src/icon/logos/bitwarden/password-manager.ts rename to libs/assets/src/svg/svgs/password-manager.ts index 7586e28bfae..42b3df1a0ed 100644 --- a/libs/components/src/icon/logos/bitwarden/password-manager.ts +++ b/libs/assets/src/svg/svgs/password-manager.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../../icon"; +import { svgIcon } from "../icon-service"; const PasswordManagerLogo = svgIcon` diff --git a/libs/components/src/icon/logos/bitwarden/provider-portal.ts b/libs/assets/src/svg/svgs/provider-portal.ts similarity index 99% rename from libs/components/src/icon/logos/bitwarden/provider-portal.ts rename to libs/assets/src/svg/svgs/provider-portal.ts index b9c4d76b0e3..9626cc30c57 100644 --- a/libs/components/src/icon/logos/bitwarden/provider-portal.ts +++ b/libs/assets/src/svg/svgs/provider-portal.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../../icon"; +import { svgIcon } from "../icon-service"; const ProviderPortalLogo = svgIcon` diff --git a/libs/angular/src/auth/icons/recovery.icon.ts b/libs/assets/src/svg/svgs/recovery.icon.ts similarity index 98% rename from libs/angular/src/auth/icons/recovery.icon.ts rename to libs/assets/src/svg/svgs/recovery.icon.ts index e23b46bebe1..95de89cad03 100644 --- a/libs/angular/src/auth/icons/recovery.icon.ts +++ b/libs/assets/src/svg/svgs/recovery.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const RecoveryCodeIcon = svgIcon` diff --git a/libs/auth/src/angular/icons/registration-expired-link.icon.ts b/libs/assets/src/svg/svgs/registration-expired-link.icon.ts similarity index 83% rename from libs/auth/src/angular/icons/registration-expired-link.icon.ts rename to libs/assets/src/svg/svgs/registration-expired-link.icon.ts index 099cf16d1d8..fbeda6c25ad 100644 --- a/libs/auth/src/angular/icons/registration-expired-link.icon.ts +++ b/libs/assets/src/svg/svgs/registration-expired-link.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const RegistrationExpiredLinkIcon = svgIcon` diff --git a/libs/auth/src/angular/icons/registration-lock-alt.icon.ts b/libs/assets/src/svg/svgs/registration-lock-alt.icon.ts similarity index 94% rename from libs/auth/src/angular/icons/registration-lock-alt.icon.ts rename to libs/assets/src/svg/svgs/registration-lock-alt.icon.ts index d312e909413..2e81989c304 100644 --- a/libs/auth/src/angular/icons/registration-lock-alt.icon.ts +++ b/libs/assets/src/svg/svgs/registration-lock-alt.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const RegistrationLockAltIcon = svgIcon` diff --git a/libs/auth/src/angular/icons/registration-user-add.icon.ts b/libs/assets/src/svg/svgs/registration-user-add.icon.ts similarity index 93% rename from libs/auth/src/angular/icons/registration-user-add.icon.ts rename to libs/assets/src/svg/svgs/registration-user-add.icon.ts index 4f68453639d..2aa5bcc81b5 100644 --- a/libs/auth/src/angular/icons/registration-user-add.icon.ts +++ b/libs/assets/src/svg/svgs/registration-user-add.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const RegistrationUserAddIcon = svgIcon` diff --git a/apps/web/src/app/dirt/reports/icons/report-breach.icon.ts b/libs/assets/src/svg/svgs/report-breach.icon.ts similarity index 96% rename from apps/web/src/app/dirt/reports/icons/report-breach.icon.ts rename to libs/assets/src/svg/svgs/report-breach.icon.ts index 749779a87bc..6e7fde74cbc 100644 --- a/apps/web/src/app/dirt/reports/icons/report-breach.icon.ts +++ b/libs/assets/src/svg/svgs/report-breach.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const ReportBreach = svgIcon` diff --git a/apps/web/src/app/dirt/reports/icons/report-exposed-passwords.icon.ts b/libs/assets/src/svg/svgs/report-exposed-passwords.icon.ts similarity index 97% rename from apps/web/src/app/dirt/reports/icons/report-exposed-passwords.icon.ts rename to libs/assets/src/svg/svgs/report-exposed-passwords.icon.ts index df532fe1582..0a019885805 100644 --- a/apps/web/src/app/dirt/reports/icons/report-exposed-passwords.icon.ts +++ b/libs/assets/src/svg/svgs/report-exposed-passwords.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const ReportExposedPasswords = svgIcon` diff --git a/apps/web/src/app/dirt/reports/icons/report-inactive-two-factor.icon.ts b/libs/assets/src/svg/svgs/report-inactive-two-factor.icon.ts similarity index 94% rename from apps/web/src/app/dirt/reports/icons/report-inactive-two-factor.icon.ts rename to libs/assets/src/svg/svgs/report-inactive-two-factor.icon.ts index 65ca4469648..d7ad3c9084c 100644 --- a/apps/web/src/app/dirt/reports/icons/report-inactive-two-factor.icon.ts +++ b/libs/assets/src/svg/svgs/report-inactive-two-factor.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const ReportInactiveTwoFactor = svgIcon` diff --git a/apps/web/src/app/dirt/reports/icons/report-member-access.icon.ts b/libs/assets/src/svg/svgs/report-member-access.icon.ts similarity index 96% rename from apps/web/src/app/dirt/reports/icons/report-member-access.icon.ts rename to libs/assets/src/svg/svgs/report-member-access.icon.ts index 825968cd0c0..c47fed9cd2a 100644 --- a/apps/web/src/app/dirt/reports/icons/report-member-access.icon.ts +++ b/libs/assets/src/svg/svgs/report-member-access.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const MemberAccess = svgIcon` diff --git a/apps/web/src/app/dirt/reports/icons/report-reused-passwords.icon.ts b/libs/assets/src/svg/svgs/report-reused-passwords.icon.ts similarity index 96% rename from apps/web/src/app/dirt/reports/icons/report-reused-passwords.icon.ts rename to libs/assets/src/svg/svgs/report-reused-passwords.icon.ts index d28790ba051..30aaeee80fa 100644 --- a/apps/web/src/app/dirt/reports/icons/report-reused-passwords.icon.ts +++ b/libs/assets/src/svg/svgs/report-reused-passwords.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const ReportReusedPasswords = svgIcon` diff --git a/apps/web/src/app/dirt/reports/icons/report-unsecured-websites.icon.ts b/libs/assets/src/svg/svgs/report-unsecured-websites.icon.ts similarity index 94% rename from apps/web/src/app/dirt/reports/icons/report-unsecured-websites.icon.ts rename to libs/assets/src/svg/svgs/report-unsecured-websites.icon.ts index 083ddb40db7..d55c06987ca 100644 --- a/apps/web/src/app/dirt/reports/icons/report-unsecured-websites.icon.ts +++ b/libs/assets/src/svg/svgs/report-unsecured-websites.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const ReportUnsecuredWebsites = svgIcon` diff --git a/apps/web/src/app/dirt/reports/icons/report-weak-passwords.icon.ts b/libs/assets/src/svg/svgs/report-weak-passwords.icon.ts similarity index 95% rename from apps/web/src/app/dirt/reports/icons/report-weak-passwords.icon.ts rename to libs/assets/src/svg/svgs/report-weak-passwords.icon.ts index 8a0ef324c73..9709255169b 100644 --- a/apps/web/src/app/dirt/reports/icons/report-weak-passwords.icon.ts +++ b/libs/assets/src/svg/svgs/report-weak-passwords.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const ReportWeakPasswords = svgIcon` diff --git a/libs/assets/src/svg/svgs/restricted-view.ts b/libs/assets/src/svg/svgs/restricted-view.ts new file mode 100644 index 00000000000..afe6c752870 --- /dev/null +++ b/libs/assets/src/svg/svgs/restricted-view.ts @@ -0,0 +1,6 @@ +import { svgIcon } from "../icon-service"; + +export const RestrictedView = svgIcon` + + +`; diff --git a/libs/components/src/icon/icons/search.ts b/libs/assets/src/svg/svgs/search.ts similarity index 98% rename from libs/components/src/icon/icons/search.ts rename to libs/assets/src/svg/svgs/search.ts index 914fa0e9813..40f323acf3e 100644 --- a/libs/components/src/icon/icons/search.ts +++ b/libs/assets/src/svg/svgs/search.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../icon"; +import { svgIcon } from "../icon-service"; export const Search = svgIcon` diff --git a/apps/web/src/app/layouts/secrets-manager-logo.ts b/libs/assets/src/svg/svgs/secrets-manager-alt.ts similarity index 99% rename from apps/web/src/app/layouts/secrets-manager-logo.ts rename to libs/assets/src/svg/svgs/secrets-manager-alt.ts index 70f0f46540e..293bd99cbf3 100644 --- a/apps/web/src/app/layouts/secrets-manager-logo.ts +++ b/libs/assets/src/svg/svgs/secrets-manager-alt.ts @@ -1,5 +1,5 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; -export const SecretsManagerLogo = svgIcon` +export const SecretsManagerAlt = svgIcon` `; diff --git a/libs/components/src/icon/logos/bitwarden/secrets-manager.ts b/libs/assets/src/svg/svgs/secrets-manager.ts similarity index 99% rename from libs/components/src/icon/logos/bitwarden/secrets-manager.ts rename to libs/assets/src/svg/svgs/secrets-manager.ts index 45f3418b1e8..b2657f8fb67 100644 --- a/libs/components/src/icon/logos/bitwarden/secrets-manager.ts +++ b/libs/assets/src/svg/svgs/secrets-manager.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../../icon"; +import { svgIcon } from "../icon-service"; const SecretsManagerLogo = svgIcon` diff --git a/libs/vault/src/icons/secure-devices.ts b/libs/assets/src/svg/svgs/secure-devices.ts similarity index 97% rename from libs/vault/src/icons/secure-devices.ts rename to libs/assets/src/svg/svgs/secure-devices.ts index 4e123afad40..ed216f1bc87 100644 --- a/libs/vault/src/icons/secure-devices.ts +++ b/libs/assets/src/svg/svgs/secure-devices.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const SecureDevices = svgIcon` diff --git a/libs/vault/src/icons/secure-user.ts b/libs/assets/src/svg/svgs/secure-user.ts similarity index 98% rename from libs/vault/src/icons/secure-user.ts rename to libs/assets/src/svg/svgs/secure-user.ts index 39d9957030c..8684549a815 100644 --- a/libs/vault/src/icons/secure-user.ts +++ b/libs/assets/src/svg/svgs/secure-user.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const SecureUser = svgIcon` diff --git a/libs/vault/src/icons/security-handshake.ts b/libs/assets/src/svg/svgs/security-handshake.ts similarity index 99% rename from libs/vault/src/icons/security-handshake.ts rename to libs/assets/src/svg/svgs/security-handshake.ts index d68f8a948d3..f6309bc4c54 100644 --- a/libs/vault/src/icons/security-handshake.ts +++ b/libs/assets/src/svg/svgs/security-handshake.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const SecurityHandshake = svgIcon` diff --git a/libs/components/src/icon/icons/security.ts b/libs/assets/src/svg/svgs/security.ts similarity index 99% rename from libs/components/src/icon/icons/security.ts rename to libs/assets/src/svg/svgs/security.ts index 5732b8066c6..0edf0aec14f 100644 --- a/libs/components/src/icon/icons/security.ts +++ b/libs/assets/src/svg/svgs/security.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../icon"; +import { svgIcon } from "../icon-service"; export const Security = svgIcon` diff --git a/libs/components/src/icon/icons/send.ts b/libs/assets/src/svg/svgs/send.ts similarity index 97% rename from libs/components/src/icon/icons/send.ts rename to libs/assets/src/svg/svgs/send.ts index 19026fc74cc..f09f59a5388 100644 --- a/libs/components/src/icon/icons/send.ts +++ b/libs/assets/src/svg/svgs/send.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../icon"; +import { svgIcon } from "../icon-service"; export const SendInactive = svgIcon` diff --git a/libs/components/src/icon/icons/settings.ts b/libs/assets/src/svg/svgs/settings.ts similarity index 99% rename from libs/components/src/icon/icons/settings.ts rename to libs/assets/src/svg/svgs/settings.ts index 361999bc244..3b54bbbd88c 100644 --- a/libs/components/src/icon/icons/settings.ts +++ b/libs/assets/src/svg/svgs/settings.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../icon"; +import { svgIcon } from "../icon-service"; export const SettingsInactive = svgIcon` diff --git a/libs/components/src/icon/logos/bitwarden/shield.ts b/libs/assets/src/svg/svgs/shield.ts similarity index 98% rename from libs/components/src/icon/logos/bitwarden/shield.ts rename to libs/assets/src/svg/svgs/shield.ts index d736a44ba3e..57a92e66e82 100644 --- a/libs/components/src/icon/logos/bitwarden/shield.ts +++ b/libs/assets/src/svg/svgs/shield.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../../icon"; +import { svgIcon } from "../icon-service"; /** * Shield logo with extra space in the viewbox. diff --git a/libs/auth/src/angular/icons/sso-key.icon.ts b/libs/assets/src/svg/svgs/sso-key.icon.ts similarity index 92% rename from libs/auth/src/angular/icons/sso-key.icon.ts rename to libs/assets/src/svg/svgs/sso-key.icon.ts index e00c3555906..533c033feac 100644 --- a/libs/auth/src/angular/icons/sso-key.icon.ts +++ b/libs/assets/src/svg/svgs/sso-key.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const SsoKeyIcon = svgIcon` diff --git a/apps/web/src/app/billing/organizations/icons/subscription-hidden.icon.ts b/libs/assets/src/svg/svgs/subscription-hidden.ts similarity index 99% rename from apps/web/src/app/billing/organizations/icons/subscription-hidden.icon.ts rename to libs/assets/src/svg/svgs/subscription-hidden.ts index 82490e82a1d..38840580f86 100644 --- a/apps/web/src/app/billing/organizations/icons/subscription-hidden.icon.ts +++ b/libs/assets/src/svg/svgs/subscription-hidden.ts @@ -1,6 +1,6 @@ -import { Icon, svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; -export const SubscriptionHiddenIcon: Icon = svgIcon` +export const SubscriptionHiddenIcon = svgIcon` diff --git a/libs/angular/src/auth/icons/totp.icon.ts b/libs/assets/src/svg/svgs/totp.icon.ts similarity index 98% rename from libs/angular/src/auth/icons/totp.icon.ts rename to libs/assets/src/svg/svgs/totp.icon.ts index 1754e77b308..00e96c93b6f 100644 --- a/libs/angular/src/auth/icons/totp.icon.ts +++ b/libs/assets/src/svg/svgs/totp.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const TOTPIcon = svgIcon` diff --git a/libs/auth/src/angular/icons/two-factor-auth/two-factor-auth-duo.icon.ts b/libs/assets/src/svg/svgs/two-factor-auth-duo.icon.ts similarity index 81% rename from libs/auth/src/angular/icons/two-factor-auth/two-factor-auth-duo.icon.ts rename to libs/assets/src/svg/svgs/two-factor-auth-duo.icon.ts index a64027c5fba..d56e3b325d1 100644 --- a/libs/auth/src/angular/icons/two-factor-auth/two-factor-auth-duo.icon.ts +++ b/libs/assets/src/svg/svgs/two-factor-auth-duo.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const TwoFactorAuthDuoIcon = svgIcon` diff --git a/libs/auth/src/angular/icons/two-factor-auth/two-factor-auth-email.icon.ts b/libs/assets/src/svg/svgs/two-factor-auth-email.icon.ts similarity index 90% rename from libs/auth/src/angular/icons/two-factor-auth/two-factor-auth-email.icon.ts rename to libs/assets/src/svg/svgs/two-factor-auth-email.icon.ts index 380bc16a738..71ffc099e58 100644 --- a/libs/auth/src/angular/icons/two-factor-auth/two-factor-auth-email.icon.ts +++ b/libs/assets/src/svg/svgs/two-factor-auth-email.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const TwoFactorAuthEmailIcon = svgIcon` diff --git a/libs/auth/src/angular/icons/two-factor-auth/two-factor-auth-security-key.icon.ts b/libs/assets/src/svg/svgs/two-factor-auth-security-key.icon.ts similarity index 96% rename from libs/auth/src/angular/icons/two-factor-auth/two-factor-auth-security-key.icon.ts rename to libs/assets/src/svg/svgs/two-factor-auth-security-key.icon.ts index 573dc890428..644f98a0cbd 100644 --- a/libs/auth/src/angular/icons/two-factor-auth/two-factor-auth-security-key.icon.ts +++ b/libs/assets/src/svg/svgs/two-factor-auth-security-key.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const TwoFactorAuthSecurityKeyIcon = svgIcon` diff --git a/libs/auth/src/angular/icons/two-factor-auth/two-factor-auth-webauthn.icon.ts b/libs/assets/src/svg/svgs/two-factor-auth-webauthn.icon.ts similarity index 96% rename from libs/auth/src/angular/icons/two-factor-auth/two-factor-auth-webauthn.icon.ts rename to libs/assets/src/svg/svgs/two-factor-auth-webauthn.icon.ts index ff73bf2e255..f5e7519e024 100644 --- a/libs/auth/src/angular/icons/two-factor-auth/two-factor-auth-webauthn.icon.ts +++ b/libs/assets/src/svg/svgs/two-factor-auth-webauthn.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const TwoFactorAuthWebAuthnIcon = svgIcon` diff --git a/libs/auth/src/angular/icons/two-factor-auth/two-factor-auth-yubico.icon.ts b/libs/assets/src/svg/svgs/two-factor-auth-yubico.icon.ts similarity index 93% rename from libs/auth/src/angular/icons/two-factor-auth/two-factor-auth-yubico.icon.ts rename to libs/assets/src/svg/svgs/two-factor-auth-yubico.icon.ts index 8f6dca837ad..231b3c3f5b1 100644 --- a/libs/auth/src/angular/icons/two-factor-auth/two-factor-auth-yubico.icon.ts +++ b/libs/assets/src/svg/svgs/two-factor-auth-yubico.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const TwoFactorAuthYubicoIcon = svgIcon` diff --git a/libs/auth/src/angular/icons/two-factor-timeout.icon.ts b/libs/assets/src/svg/svgs/two-factor-timeout.icon.ts similarity index 88% rename from libs/auth/src/angular/icons/two-factor-timeout.icon.ts rename to libs/assets/src/svg/svgs/two-factor-timeout.icon.ts index 3681670c124..7a5e04c07a3 100644 --- a/libs/auth/src/angular/icons/two-factor-timeout.icon.ts +++ b/libs/assets/src/svg/svgs/two-factor-timeout.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const TwoFactorTimeoutIcon = svgIcon` diff --git a/libs/auth/src/angular/icons/user-lock.icon.ts b/libs/assets/src/svg/svgs/user-lock.icon.ts similarity index 95% rename from libs/auth/src/angular/icons/user-lock.icon.ts rename to libs/assets/src/svg/svgs/user-lock.icon.ts index bc4fdd9e268..ad56d612268 100644 --- a/libs/auth/src/angular/icons/user-lock.icon.ts +++ b/libs/assets/src/svg/svgs/user-lock.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const UserLockIcon = svgIcon` diff --git a/libs/auth/src/angular/icons/user-verification-biometrics-fingerprint.icon.ts b/libs/assets/src/svg/svgs/user-verification-biometrics-fingerprint.icon.ts similarity index 92% rename from libs/auth/src/angular/icons/user-verification-biometrics-fingerprint.icon.ts rename to libs/assets/src/svg/svgs/user-verification-biometrics-fingerprint.icon.ts index e329d889574..b3ace19a93d 100644 --- a/libs/auth/src/angular/icons/user-verification-biometrics-fingerprint.icon.ts +++ b/libs/assets/src/svg/svgs/user-verification-biometrics-fingerprint.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const UserVerificationBiometricsIcon = svgIcon` diff --git a/libs/vault/src/icons/vault.ts b/libs/assets/src/svg/svgs/vault-open.ts similarity index 98% rename from libs/vault/src/icons/vault.ts rename to libs/assets/src/svg/svgs/vault-open.ts index 577080b0f37..e644e316c05 100644 --- a/libs/vault/src/icons/vault.ts +++ b/libs/assets/src/svg/svgs/vault-open.ts @@ -1,6 +1,6 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; -export const Vault = svgIcon` +export const VaultOpen = svgIcon` diff --git a/libs/auth/src/angular/icons/vault.icon.ts b/libs/assets/src/svg/svgs/vault.icon.ts similarity index 92% rename from libs/auth/src/angular/icons/vault.icon.ts rename to libs/assets/src/svg/svgs/vault.icon.ts index a341bcd99f5..21fcac24e7e 100644 --- a/libs/auth/src/angular/icons/vault.icon.ts +++ b/libs/assets/src/svg/svgs/vault.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const VaultIcon = svgIcon` diff --git a/libs/components/src/icon/icons/vault.ts b/libs/assets/src/svg/svgs/vault.ts similarity index 99% rename from libs/components/src/icon/icons/vault.ts rename to libs/assets/src/svg/svgs/vault.ts index eda2e3d6b60..1c699f2ba8e 100644 --- a/libs/components/src/icon/icons/vault.ts +++ b/libs/assets/src/svg/svgs/vault.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "../icon"; +import { svgIcon } from "../icon-service"; export const VaultInactive = svgIcon` diff --git a/libs/auth/src/angular/icons/wave.icon.ts b/libs/assets/src/svg/svgs/wave.icon.ts similarity index 90% rename from libs/auth/src/angular/icons/wave.icon.ts rename to libs/assets/src/svg/svgs/wave.icon.ts index 5629c43fc8d..b7e16213d0f 100644 --- a/libs/auth/src/angular/icons/wave.icon.ts +++ b/libs/assets/src/svg/svgs/wave.icon.ts @@ -1,6 +1,4 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const WaveIcon = svgIcon` diff --git a/libs/angular/src/auth/icons/webauthn.icon.ts b/libs/assets/src/svg/svgs/webauthn.icon.ts similarity index 96% rename from libs/angular/src/auth/icons/webauthn.icon.ts rename to libs/assets/src/svg/svgs/webauthn.icon.ts index a72692233d8..c679438106c 100644 --- a/libs/angular/src/auth/icons/webauthn.icon.ts +++ b/libs/assets/src/svg/svgs/webauthn.icon.ts @@ -1,4 +1,4 @@ -import { svgIcon } from "@bitwarden/components"; +import { svgIcon } from "../icon-service"; export const WebAuthnIcon = svgIcon` (); readonly subtitle = input(); diff --git a/libs/components/src/anon-layout/anon-layout.mdx b/libs/components/src/anon-layout/anon-layout.mdx index 9d40d617b0d..3c6faeccfb0 100644 --- a/libs/components/src/anon-layout/anon-layout.mdx +++ b/libs/components/src/anon-layout/anon-layout.mdx @@ -65,7 +65,8 @@ example) to construct the page via routable composition: ```typescript // File: oss-routing.module.ts -import { AnonLayoutWrapperComponent, AnonLayoutWrapperData, LockIcon } from "@bitwarden/auth/angular"; +import { AnonLayoutWrapperComponent, AnonLayoutWrapperData } from "@bitwarden/auth/angular"; +import { LockIcon } from "@bitwarden/assets/svg"; { path: "", @@ -116,7 +117,8 @@ in the `AnonLayoutWrapperData` interface: All of these properties are optional. ```typescript -import { AnonLayoutWrapperComponent, AnonLayoutWrapperData, LockIcon } from "@bitwarden/auth/angular"; +import { AnonLayoutWrapperComponent, AnonLayoutWrapperData } from "@bitwarden/auth/angular"; +import { LockIcon } from "@bitwarden/assets/svg"; { // ... @@ -137,7 +139,8 @@ on your client) as a component with `outlet: "environment-selector"`. ```javascript // File: oss-routing.module.ts -import { AnonLayoutWrapperComponent, AnonLayoutWrapperData, LockIcon } from "@bitwarden/auth/angular"; +import { AnonLayoutWrapperComponent, AnonLayoutWrapperData } from "@bitwarden/auth/angular"; + import { EnvironmentSelectorComponent } from "./components/environment-selector/environment-selector.component"; { diff --git a/libs/components/src/anon-layout/anon-layout.stories.ts b/libs/components/src/anon-layout/anon-layout.stories.ts index 339f76ec06b..15cce39d8b7 100644 --- a/libs/components/src/anon-layout/anon-layout.stories.ts +++ b/libs/components/src/anon-layout/anon-layout.stories.ts @@ -2,14 +2,13 @@ import { ActivatedRoute, RouterModule } from "@angular/router"; import { Meta, StoryObj, moduleMetadata } from "@storybook/angular"; import { BehaviorSubject, of } from "rxjs"; +import { Icon, LockIcon } from "@bitwarden/assets/svg"; import { ClientType } from "@bitwarden/common/enums"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { ButtonModule } from "../button"; -import { Icon } from "../icon"; -import { LockIcon } from "../icon/icons"; import { I18nMockService } from "../utils/i18n-mock.service"; import { AnonLayoutComponent } from "./anon-layout.component"; diff --git a/libs/components/src/anon-layout/illustrations/index.ts b/libs/components/src/anon-layout/illustrations/index.ts deleted file mode 100644 index a107eb7cd15..00000000000 --- a/libs/components/src/anon-layout/illustrations/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./left-illustration"; -export * from "./right-illustration"; diff --git a/libs/components/src/icon/icon.component.ts b/libs/components/src/icon/icon.component.ts index ec25ad30d56..49f284b947c 100644 --- a/libs/components/src/icon/icon.component.ts +++ b/libs/components/src/icon/icon.component.ts @@ -1,7 +1,7 @@ import { Component, effect, input } from "@angular/core"; import { DomSanitizer, SafeHtml } from "@angular/platform-browser"; -import { Icon, isIcon } from "./icon"; +import { Icon, isIcon } from "@bitwarden/assets/svg"; @Component({ selector: "bit-icon", diff --git a/libs/components/src/icon/icon.components.spec.ts b/libs/components/src/icon/icon.components.spec.ts index 76e86971587..3ae37ff5423 100644 --- a/libs/components/src/icon/icon.components.spec.ts +++ b/libs/components/src/icon/icon.components.spec.ts @@ -1,6 +1,7 @@ import { ComponentFixture, TestBed } from "@angular/core/testing"; -import { Icon, svgIcon } from "./icon"; +import { Icon, svgIcon } from "@bitwarden/assets/svg"; + import { BitIconComponent } from "./icon.component"; describe("IconComponent", () => { diff --git a/libs/components/src/icon/icon.mdx b/libs/components/src/icon/icon.mdx index e4186b5e4a9..9d48a2f3c45 100644 --- a/libs/components/src/icon/icon.mdx +++ b/libs/components/src/icon/icon.mdx @@ -23,9 +23,10 @@ import { IconModule } from "@bitwarden/components"; [SVG Formatter Beautifier](https://codebeautify.org/svg-formatter-beautifier) to make applying classes easier. -2. **Rename the file** as a `.icon.ts` TypeScript file. +2. **Rename the file** as a `.icon.ts` TypeScript file and place it in the `libs/assets/svg` + lib. -3. **Import** `svgIcon` from `@bitwarden/components`. +3. **Import** `svgIcon` from `./icon-service`. 4. **Define and export** a `const` to represent your `svgIcon`. @@ -74,7 +75,7 @@ import { IconModule } from "@bitwarden/components"; [viewBox](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox) attribute in order to allow the SVG to scale to fit its container. - **Note:** Scaling is required for any SVG used as an - [AnonLayout](?path=/docs/auth-anon-layout--docs) `pageIcon`. + [AnonLayout](?path=/docs/component-library-anon-layout--docs) `pageIcon`. 7. **Import your SVG const** anywhere you want to use the SVG. - **Angular Component Example:** @@ -82,8 +83,8 @@ import { IconModule } from "@bitwarden/components"; ```typescript import { Component } from "@angular/core"; - import { ExampleIcon } from "your/path/here"; import { IconModule } from '@bitwarden/components'; + import { ExampleIcon, Example2Icon } from "@bitwarden/assets/svg"; @Component({ selector: "app-example", diff --git a/libs/components/src/icon/icon.stories.ts b/libs/components/src/icon/icon.stories.ts index 7892bdd3ec1..e71a7597913 100644 --- a/libs/components/src/icon/icon.stories.ts +++ b/libs/components/src/icon/icon.stories.ts @@ -1,7 +1,8 @@ import { Meta, StoryObj } from "@storybook/angular"; +import * as SvgIcons from "@bitwarden/assets/svg"; + import { BitIconComponent } from "./icon.component"; -import * as GenericIcons from "./icons"; export default { title: "Component Library/Icon", @@ -16,14 +17,18 @@ export default { type Story = StoryObj; +// Filtering out the few non-icons in the libs/assets/svg import +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const { DynamicContentNotAllowedError, isIcon, svgIcon, ...Icons } = SvgIcons; + export const Default: Story = { args: { - icon: GenericIcons.NoAccess, + icon: Icons.NoAccess, }, argTypes: { icon: { - options: Object.keys(GenericIcons), - mapping: GenericIcons, + options: Object.keys(Icons), + mapping: Icons, control: { type: "select" }, }, ariaLabel: { diff --git a/libs/components/src/icon/icons/index.ts b/libs/components/src/icon/icons/index.ts deleted file mode 100644 index 69fac7d644e..00000000000 --- a/libs/components/src/icon/icons/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -export * from "./bitwarden-logo.icon"; -export * from "./extension-bitwarden-logo.icon"; -export * from "./lock.icon"; -export * from "./generator"; -export * from "./no-access"; -export * from "./no-results"; -export * from "./registration-check-email.icon"; -export * from "./search"; -export * from "./security"; -export * from "./send"; -export * from "./settings"; -export * from "./vault"; diff --git a/libs/components/src/icon/index.ts b/libs/components/src/icon/index.ts index 01819a3678e..1ee66e59837 100644 --- a/libs/components/src/icon/index.ts +++ b/libs/components/src/icon/index.ts @@ -1,10 +1 @@ export * from "./icon.module"; -export * from "./icon"; -export * as Icons from "./icons"; -export { - AdminConsoleLogo, - BusinessUnitPortalLogo, - PasswordManagerLogo, - ProviderPortalLogo, - SecretsManagerLogo, -} from "./logos"; diff --git a/libs/components/src/icon/logos/bitwarden/index.ts b/libs/components/src/icon/logos/bitwarden/index.ts deleted file mode 100644 index d74c6fe453a..00000000000 --- a/libs/components/src/icon/logos/bitwarden/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { default as AdminConsoleLogo } from "./admin-console"; -export { default as BusinessUnitPortalLogo } from "./business-unit-portal"; -export * from "./shield"; -export { default as PasswordManagerLogo } from "./password-manager"; -export { default as ProviderPortalLogo } from "./provider-portal"; -export { default as SecretsManagerLogo } from "./secrets-manager"; diff --git a/libs/components/src/icon/logos/index.ts b/libs/components/src/icon/logos/index.ts deleted file mode 100644 index 07a8a739289..00000000000 --- a/libs/components/src/icon/logos/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./bitwarden"; diff --git a/libs/components/src/navigation/nav-logo.component.ts b/libs/components/src/navigation/nav-logo.component.ts index 52d67446f2f..96258740d74 100644 --- a/libs/components/src/navigation/nav-logo.component.ts +++ b/libs/components/src/navigation/nav-logo.component.ts @@ -2,9 +2,9 @@ import { CommonModule } from "@angular/common"; import { Component, input } from "@angular/core"; import { RouterLinkActive, RouterLink } from "@angular/router"; -import { Icon } from "../icon"; +import { BitwardenShield, Icon } from "@bitwarden/assets/svg"; + import { BitIconComponent } from "../icon/icon.component"; -import { BitwardenShield } from "../icon/logos"; import { SideNavService } from "./side-nav.service"; diff --git a/libs/components/src/no-items/no-items.component.ts b/libs/components/src/no-items/no-items.component.ts index 7c00999f59f..3d7394a16ae 100644 --- a/libs/components/src/no-items/no-items.component.ts +++ b/libs/components/src/no-items/no-items.component.ts @@ -1,6 +1,7 @@ import { Component, input } from "@angular/core"; -import { Icons } from ".."; +import { Search } from "@bitwarden/assets/svg"; + import { BitIconComponent } from "../icon/icon.component"; /** @@ -12,5 +13,5 @@ import { BitIconComponent } from "../icon/icon.component"; imports: [BitIconComponent], }) export class NoItemsComponent { - readonly icon = input(Icons.Search); + readonly icon = input(Search); } diff --git a/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts b/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts index cb8a72e1b3f..2cacab5af75 100644 --- a/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts +++ b/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts @@ -11,9 +11,9 @@ import { getAllByLabelText, } from "@storybook/test"; +import { PasswordManagerLogo } from "@bitwarden/assets/svg"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { PasswordManagerLogo } from "../../icon"; import { LayoutComponent } from "../../layout"; import { I18nMockService } from "../../utils/i18n-mock.service"; import { positionFixedWrapperDecorator } from "../storybook-decorators"; diff --git a/libs/components/tailwind.config.base.js b/libs/components/tailwind.config.base.js index fe33e592609..95b239537ff 100644 --- a/libs/components/tailwind.config.base.js +++ b/libs/components/tailwind.config.base.js @@ -10,6 +10,7 @@ module.exports = { prefix: "tw-", content: [ "./src/**/*.{html,ts}", + "../../libs/assets/src/**/*.{html,ts}", "../../libs/components/src/**/*.{html,ts}", "../../libs/key-management-ui/src/**/*.{html,ts}", "../../libs/auth/src/**/*.{html,ts}", diff --git a/libs/components/tailwind.config.js b/libs/components/tailwind.config.js index d256214a4ff..d8cef6596dc 100644 --- a/libs/components/tailwind.config.js +++ b/libs/components/tailwind.config.js @@ -3,6 +3,7 @@ const config = require("./tailwind.config.base"); config.content = [ "libs/components/src/**/*.{html,ts,mdx}", + "libs/assets/src/**/*.{html,ts,mdx}", "libs/auth/src/**/*.{html,ts,mdx}", "libs/vault/src/**/*.{html,ts,mdx}", "apps/web/src/**/*.{html,ts,mdx}", diff --git a/libs/tools/generator/components/src/empty-credential-history.component.ts b/libs/tools/generator/components/src/empty-credential-history.component.ts index 29c9fc277fc..6ae55d33d2c 100644 --- a/libs/tools/generator/components/src/empty-credential-history.component.ts +++ b/libs/tools/generator/components/src/empty-credential-history.component.ts @@ -1,10 +1,9 @@ import { Component } from "@angular/core"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { NoCredentialsIcon } from "@bitwarden/assets/svg"; import { IconModule, TypographyModule } from "@bitwarden/components"; -import { NoCredentialsIcon } from "./icons/no-credentials.icon"; - @Component({ selector: "bit-empty-credential-history", templateUrl: "empty-credential-history.component.html", diff --git a/libs/tools/send/send-ui/src/icons/index.ts b/libs/tools/send/send-ui/src/icons/index.ts deleted file mode 100644 index 57636daadcf..00000000000 --- a/libs/tools/send/send-ui/src/icons/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { ExpiredSendIcon } from "./expired-send.icon"; -export { NoSendsIcon } from "./no-send.icon"; -export { ActiveSendIcon } from "./active-send.icon"; diff --git a/libs/tools/send/send-ui/src/index.ts b/libs/tools/send/send-ui/src/index.ts index db4416a13f0..2803e91c418 100644 --- a/libs/tools/send/send-ui/src/index.ts +++ b/libs/tools/send/send-ui/src/index.ts @@ -1,4 +1,3 @@ -export * from "./icons"; export * from "./send-form"; export { NewSendDropdownComponent } from "./new-send-dropdown/new-send-dropdown.component"; export * from "./add-edit/send-add-edit-dialog.component"; diff --git a/libs/vault/src/components/carousel/carousel-button/carousel-button.component.ts b/libs/vault/src/components/carousel/carousel-button/carousel-button.component.ts index 7b5f7d3b164..ae2ce12cba8 100644 --- a/libs/vault/src/components/carousel/carousel-button/carousel-button.component.ts +++ b/libs/vault/src/components/carousel/carousel-button/carousel-button.component.ts @@ -2,9 +2,9 @@ import { FocusableOption } from "@angular/cdk/a11y"; import { CommonModule } from "@angular/common"; import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from "@angular/core"; +import { CarouselIcon } from "@bitwarden/assets/svg"; import { IconModule } from "@bitwarden/components"; -import { CarouselIcon } from "../carousel-icons/carousel-icon"; import { VaultCarouselSlideComponent } from "../carousel-slide/carousel-slide.component"; @Component({ diff --git a/libs/vault/src/icons/index.ts b/libs/vault/src/icons/index.ts deleted file mode 100644 index 904399da4b3..00000000000 --- a/libs/vault/src/icons/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -export * from "./deactivated-org"; -export * from "./no-folders"; -export * from "./vault"; -export * from "./empty-trash"; -export * from "./browser-extension"; -export * from "./bitwarden-icon"; -export * from "./security-handshake"; -export * from "./login-cards"; -export * from "./secure-user"; -export * from "./secure-devices"; -export * from "./party"; diff --git a/libs/vault/src/index.ts b/libs/vault/src/index.ts index 9d037d8fe5e..f3925ac3379 100644 --- a/libs/vault/src/index.ts +++ b/libs/vault/src/index.ts @@ -21,8 +21,6 @@ export * from "./components/add-edit-folder-dialog/add-edit-folder-dialog.compon export * from "./components/carousel"; export * from "./components/new-cipher-menu/new-cipher-menu.component"; -export * as VaultIcons from "./icons"; - export { DefaultSshImportPromptService } from "./services/default-ssh-import-prompt.service"; export { SshImportPromptService } from "./services/ssh-import-prompt.service"; diff --git a/package-lock.json b/package-lock.json index d2d497d10b0..c0958eab200 100644 --- a/package-lock.json +++ b/package-lock.json @@ -303,6 +303,11 @@ "version": "0.0.0", "license": "GPL-3.0" }, + "libs/assets": { + "name": "@bitwarden/assets", + "version": "0.0.1", + "license": "GPL-3.0" + }, "libs/auth": { "name": "@bitwarden/auth", "version": "0.0.0", @@ -4563,6 +4568,10 @@ "resolved": "libs/angular", "link": true }, + "node_modules/@bitwarden/assets": { + "resolved": "libs/assets", + "link": true + }, "node_modules/@bitwarden/auth": { "resolved": "libs/auth", "link": true diff --git a/tailwind.config.js b/tailwind.config.js index 637c28a54ea..dff04c897c3 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -6,6 +6,7 @@ config.content = [ "./libs/admin-console/src/**/*.{html,ts,mdx}", "./libs/auth/src/**/*.{html,ts,mdx}", "./libs/billing/src/**/*.{html,ts,mdx}", + "./libs/assets/src/**/*.{html,ts}", "./libs/platform/src/**/*.{html,ts,mdx}", "./libs/tools/send/send-ui/src/*.{html,ts,mdx}", "./libs/vault/src/**/*.{html,ts,mdx}", diff --git a/tsconfig.base.json b/tsconfig.base.json index c1256383915..8053bfe6c63 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -20,6 +20,8 @@ "paths": { "@bitwarden/admin-console/common": ["./libs/admin-console/src/common"], "@bitwarden/angular/*": ["./libs/angular/src/*"], + "@bitwarden/assets": ["libs/assets/src/index.ts"], + "@bitwarden/assets/svg": ["libs/assets/src/svg/index.ts"], "@bitwarden/auth/angular": ["./libs/auth/src/angular"], "@bitwarden/auth/common": ["./libs/auth/src/common"], "@bitwarden/billing": ["./libs/billing/src"], From a6e7efddeb5a6263053118b5f211e7d2b0c13a91 Mon Sep 17 00:00:00 2001 From: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> Date: Thu, 21 Aug 2025 15:49:19 -0500 Subject: [PATCH 014/167] [PM-23627] Require publicKey for keyService getFingerprint (#15933) * require public key on keyService getFingerprint * Update consumers and add error handling & logging --- .../account-security.component.spec.ts | 2 - .../settings/account-security.component.ts | 16 ++++-- apps/cli/src/commands/get.command.ts | 3 + apps/desktop/src/app/app.component.ts | 18 ++++-- .../settings/account/profile.component.html | 13 +++-- .../settings/account/profile.component.ts | 24 ++++++-- .../src/abstractions/key.service.ts | 10 ++-- libs/key-management/src/key.service.spec.ts | 57 +++++++++++++++++++ libs/key-management/src/key.service.ts | 12 +--- 9 files changed, 119 insertions(+), 36 deletions(-) diff --git a/apps/browser/src/auth/popup/settings/account-security.component.spec.ts b/apps/browser/src/auth/popup/settings/account-security.component.spec.ts index 014f2a7638b..63666440a76 100644 --- a/apps/browser/src/auth/popup/settings/account-security.component.spec.ts +++ b/apps/browser/src/auth/popup/settings/account-security.component.spec.ts @@ -24,7 +24,6 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { MessageSender } from "@bitwarden/common/platform/messaging"; import { Utils } from "@bitwarden/common/platform/misc/utils"; @@ -79,7 +78,6 @@ describe("AccountSecurityComponent", () => { { provide: PlatformUtilsService, useValue: platformUtilsService }, { provide: PolicyService, useValue: policyService }, { provide: PopupRouterCacheService, useValue: mock() }, - { provide: StateService, useValue: mock() }, { provide: ToastService, useValue: mock() }, { provide: UserVerificationService, useValue: mock() }, { provide: VaultTimeoutService, useValue: mock() }, diff --git a/apps/browser/src/auth/popup/settings/account-security.component.ts b/apps/browser/src/auth/popup/settings/account-security.component.ts index b41cfe14c4f..72a389ecf71 100644 --- a/apps/browser/src/auth/popup/settings/account-security.component.ts +++ b/apps/browser/src/auth/popup/settings/account-security.component.ts @@ -44,9 +44,9 @@ import { import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { DialogRef, @@ -149,7 +149,6 @@ export class AccountSecurityComponent implements OnInit, OnDestroy { public messagingService: MessagingService, private environmentService: EnvironmentService, private keyService: KeyService, - private stateService: StateService, private userVerificationService: UserVerificationService, private dialogService: DialogService, private changeDetectorRef: ChangeDetectorRef, @@ -159,6 +158,7 @@ export class AccountSecurityComponent implements OnInit, OnDestroy { private vaultNudgesService: NudgesService, private validationService: ValidationService, private configService: ConfigService, + private logService: LogService, ) {} async ngOnInit() { @@ -683,10 +683,16 @@ export class AccountSecurityComponent implements OnInit, OnDestroy { } async openAcctFingerprintDialog() { - const activeUserId = await firstValueFrom( - this.accountService.activeAccount$.pipe(map((a) => a?.id)), - ); + const activeUserId = await firstValueFrom(getUserId(this.accountService.activeAccount$)); const publicKey = await firstValueFrom(this.keyService.userPublicKey$(activeUserId)); + if (publicKey == null) { + this.logService.error( + "[AccountSecurityComponent] No public key available for the user: " + + activeUserId + + " fingerprint can't be displayed.", + ); + return; + } const fingerprint = await this.keyService.getFingerprint(activeUserId, publicKey); const dialogRef = FingerprintDialogComponent.open(this.dialogService, { diff --git a/apps/cli/src/commands/get.command.ts b/apps/cli/src/commands/get.command.ts index 58181cff6ce..a994ad3117c 100644 --- a/apps/cli/src/commands/get.command.ts +++ b/apps/cli/src/commands/get.command.ts @@ -606,6 +606,9 @@ export class GetCommand extends DownloadCommand { if (id === "me") { const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)); const publicKey = await firstValueFrom(this.keyService.userPublicKey$(activeUserId)); + if (publicKey == null) { + return Response.error("No public key available for the active user."); + } fingerprint = await this.keyService.getFingerprint(activeUserId, publicKey); } else if (Utils.isGuid(id)) { try { diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts index 197290cf690..c4e60e4ff93 100644 --- a/apps/desktop/src/app/app.component.ts +++ b/apps/desktop/src/app/app.component.ts @@ -299,12 +299,22 @@ export class AppComponent implements OnInit, OnDestroy { break; case "showFingerprintPhrase": { const activeUserId = await firstValueFrom( - this.accountService.activeAccount$.pipe(map((a) => a?.id)), + getUserId(this.accountService.activeAccount$), ); const publicKey = await firstValueFrom(this.keyService.userPublicKey$(activeUserId)); - const fingerprint = await this.keyService.getFingerprint(activeUserId, publicKey); - const dialogRef = FingerprintDialogComponent.open(this.dialogService, { fingerprint }); - await firstValueFrom(dialogRef.closed); + if (publicKey == null) { + this.logService.error( + "[AppComponent] No public key available for the user: " + + activeUserId + + " fingerprint can't be displayed.", + ); + } else { + const fingerprint = await this.keyService.getFingerprint(activeUserId, publicKey); + const dialogRef = FingerprintDialogComponent.open(this.dialogService, { + fingerprint, + }); + await firstValueFrom(dialogRef.closed); + } break; } case "deleteAccount": diff --git a/apps/web/src/app/auth/settings/account/profile.component.html b/apps/web/src/app/auth/settings/account/profile.component.html index 74e9cf08f89..a49e6c31d2e 100644 --- a/apps/web/src/app/auth/settings/account/profile.component.html +++ b/apps/web/src/app/auth/settings/account/profile.component.html @@ -46,11 +46,14 @@
- - + @if (fingerprintMaterial && userPublicKey) { + + + }
diff --git a/apps/web/src/app/auth/settings/account/profile.component.ts b/apps/web/src/app/auth/settings/account/profile.component.ts index a0572b846db..54f9ac58291 100644 --- a/apps/web/src/app/auth/settings/account/profile.component.ts +++ b/apps/web/src/app/auth/settings/account/profile.component.ts @@ -12,7 +12,10 @@ import { UpdateProfileRequest } from "@bitwarden/common/auth/models/request/upda import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { ProfileResponse } from "@bitwarden/common/models/response/profile.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { UserPublicKey } from "@bitwarden/common/types/key"; import { DialogService, ToastService } from "@bitwarden/components"; +import { KeyService } from "@bitwarden/key-management"; import { DynamicAvatarComponent } from "../../../components/dynamic-avatar.component"; import { SharedModule } from "../../../shared"; @@ -29,6 +32,7 @@ export class ProfileComponent implements OnInit, OnDestroy { loading = true; profile: ProfileResponse; fingerprintMaterial: string; + userPublicKey: UserPublicKey; managingOrganization$: Observable; private destroy$ = new Subject(); @@ -44,16 +48,24 @@ export class ProfileComponent implements OnInit, OnDestroy { private dialogService: DialogService, private toastService: ToastService, private organizationService: OrganizationService, + private keyService: KeyService, + private logService: LogService, ) {} async ngOnInit() { this.profile = await this.apiService.getProfile(); - this.loading = false; - this.fingerprintMaterial = await firstValueFrom( - this.accountService.activeAccount$.pipe(map((a) => a?.id)), - ); - const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$)); + this.fingerprintMaterial = userId; + const publicKey = await firstValueFrom(this.keyService.userPublicKey$(userId)); + if (publicKey == null) { + this.logService.error( + "[ProfileComponent] No public key available for the user: " + + userId + + " fingerprint can't be displayed.", + ); + } else { + this.userPublicKey = publicKey; + } this.managingOrganization$ = this.organizationService .organizations$(userId) @@ -70,6 +82,8 @@ export class ProfileComponent implements OnInit, OnDestroy { .subscribe((name) => { this.profile.name = name; }); + + this.loading = false; } openChangeAvatar = async () => { diff --git a/libs/key-management/src/abstractions/key.service.ts b/libs/key-management/src/abstractions/key.service.ts index 4f14f5523b9..1685938de3d 100644 --- a/libs/key-management/src/abstractions/key.service.ts +++ b/libs/key-management/src/abstractions/key.service.ts @@ -318,14 +318,14 @@ export abstract class KeyService { ): Observable<{ privateKey: UserPrivateKey; publicKey: UserPublicKey } | null>; /** - * Generates a fingerprint phrase for the user based on their public key + * Generates a fingerprint phrase for the public key provided. * - * @throws Error when publicKey is null and there is no active user, or the active user does not have a public key + * @throws Error when publicKey is null or undefined. * @param fingerprintMaterial Fingerprint material - * @param publicKey The user's public key - * @returns The user's fingerprint phrase + * @param publicKey The public key to generate the fingerprint phrase for. + * @returns The fingerprint phrase */ - abstract getFingerprint(fingerprintMaterial: string, publicKey?: Uint8Array): Promise; + abstract getFingerprint(fingerprintMaterial: string, publicKey: Uint8Array): Promise; /** * Generates a new keypair * @param key A key to encrypt the private key with. If not provided, diff --git a/libs/key-management/src/key.service.spec.ts b/libs/key-management/src/key.service.spec.ts index 4d872e2cd5c..6e1ee5d6506 100644 --- a/libs/key-management/src/key.service.spec.ts +++ b/libs/key-management/src/key.service.spec.ts @@ -1227,6 +1227,63 @@ describe("keyService", () => { }); }); + describe("getFingerprint", () => { + const mockFingerprintMaterial = "test@example.com"; + const mockPublicKey = new Uint8Array(256); + const mockKeyFingerprint = Utils.fromB64ToArray("nfG2jTrJilBEsSrg7ffe9exE9PlClem4P2bxlQ6rNbs="); + const mockUserFingerprint = Utils.fromB64ToArray( + "V5AQSk83YXd6kZqCncC6d9J72R7UZ60Xl1eIoDoWgTc=", + ); + const expectedFingerprint = ["predefine", "hunting", "pastime", "enrich", "unhearing"]; + + beforeEach(() => { + cryptoFunctionService.hash.mockResolvedValue(mockKeyFingerprint); + cryptoFunctionService.hkdfExpand.mockResolvedValue(mockUserFingerprint); + }); + + test.each([null as unknown as Uint8Array, undefined as unknown as Uint8Array])( + "throws when publicKey is %s", + async (publicKey) => { + await expect(keyService.getFingerprint(mockFingerprintMaterial, publicKey)).rejects.toThrow( + "Public key is required to generate a fingerprint.", + ); + expect(cryptoFunctionService.hash).not.toHaveBeenCalled(); + expect(cryptoFunctionService.hkdfExpand).not.toHaveBeenCalled(); + }, + ); + + it("generates fingerprint successfully", async () => { + const result = await keyService.getFingerprint(mockFingerprintMaterial, mockPublicKey); + + expect(result).toEqual(expectedFingerprint); + expect(cryptoFunctionService.hash).toHaveBeenCalledWith(mockPublicKey, "sha256"); + expect(cryptoFunctionService.hkdfExpand).toHaveBeenCalledWith( + mockKeyFingerprint, + mockFingerprintMaterial, + 32, + "sha256", + ); + }); + + it("throws when entropy of hash function is too small", async () => { + const keyFingerprint = new Uint8Array(3); + cryptoFunctionService.hash.mockResolvedValue(keyFingerprint); + cryptoFunctionService.hkdfExpand.mockResolvedValue(new Uint8Array(3)); + + await expect( + keyService.getFingerprint(mockFingerprintMaterial, mockPublicKey), + ).rejects.toThrow("Output entropy of hash function is too small"); + + expect(cryptoFunctionService.hash).toHaveBeenCalledWith(mockPublicKey, "sha256"); + expect(cryptoFunctionService.hkdfExpand).toHaveBeenCalledWith( + keyFingerprint, + mockFingerprintMaterial, + 32, + "sha256", + ); + }); + }); + describe("makeKeyPair", () => { test.each([null as unknown as SymmetricCryptoKey, undefined as unknown as SymmetricCryptoKey])( "throws when the provided key is %s", diff --git a/libs/key-management/src/key.service.ts b/libs/key-management/src/key.service.ts index 92bee383a0b..ed0b844a2a4 100644 --- a/libs/key-management/src/key.service.ts +++ b/libs/key-management/src/key.service.ts @@ -473,19 +473,11 @@ export class DefaultKeyService implements KeyServiceAbstraction { .update(() => encPrivateKey); } - // TODO: Make public key required - async getFingerprint(fingerprintMaterial: string, publicKey?: Uint8Array): Promise { + async getFingerprint(fingerprintMaterial: string, publicKey: Uint8Array): Promise { if (publicKey == null) { - const activeUserId = await firstValueFrom(this.stateProvider.activeUserId$); - if (activeUserId == null) { - throw new Error("No active user found."); - } - publicKey = (await firstValueFrom(this.userPublicKey$(activeUserId))) as Uint8Array; + throw new Error("Public key is required to generate a fingerprint."); } - if (publicKey === null) { - throw new Error("No public key available."); - } const keyFingerprint = await this.cryptoFunctionService.hash(publicKey, "sha256"); const userFingerprint = await this.cryptoFunctionService.hkdfExpand( keyFingerprint, From 7aca0cdbd7345a0e10bbd24cb86daf0f4c75938b Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Thu, 21 Aug 2025 17:28:03 -0400 Subject: [PATCH 015/167] Fix `AppComponent.ngOnInit` throwing an error (#16115) --- apps/browser/src/popup/app.component.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/browser/src/popup/app.component.ts b/apps/browser/src/popup/app.component.ts index fa1e6c237c9..bd7b41b6e5f 100644 --- a/apps/browser/src/popup/app.component.ts +++ b/apps/browser/src/popup/app.component.ts @@ -321,6 +321,9 @@ export class AppComponent implements OnInit, OnDestroy { } private async clearComponentStates() { + if (this.activeUserId == null) { + return; + } if (!(await firstValueFrom(this.tokenService.hasAccessToken$(this.activeUserId)))) { return; } From 12df7def61cc5b90af972edb5638e94b5cd53744 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Fri, 22 Aug 2025 14:21:52 +0200 Subject: [PATCH 016/167] [PM-19479] Client-Managed SDK state definition (#14839) * [PM-19479] Client-Managed SDK state definition * Remove test code * Update based on latest sdk * Add DB config * Remove uuid conversion step * Move mapper into separate file * Revert to client managed state * Move mapper to Cipher * Typo --------- Co-authored-by: Andreas Coroiu --- .../browser/src/background/main.background.ts | 1 + .../service-container/service-container.ts | 1 + .../src/services/jslib-services.module.ts | 1 + .../services/sdk/client-managed-state.ts | 64 +++++++++++++++++++ .../services/sdk/default-sdk.service.ts | 10 +++ .../vault/models/domain/cipher-sdk-mapper.ts | 22 +++++++ 6 files changed, 99 insertions(+) create mode 100644 libs/common/src/platform/services/sdk/client-managed-state.ts create mode 100644 libs/common/src/vault/models/domain/cipher-sdk-mapper.ts diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index a5fb9397125..cd045c9874e 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -779,6 +779,7 @@ export default class MainBackground { this.accountService, this.kdfConfigService, this.keyService, + this.stateProvider, ); this.passwordStrengthService = new PasswordStrengthService(); diff --git a/apps/cli/src/service-container/service-container.ts b/apps/cli/src/service-container/service-container.ts index e82ceb5a6e9..0268eed06ae 100644 --- a/apps/cli/src/service-container/service-container.ts +++ b/apps/cli/src/service-container/service-container.ts @@ -599,6 +599,7 @@ export class ServiceContainer { this.accountService, this.kdfConfigService, this.keyService, + this.stateProvider, customUserAgent, ); diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 50d1c477c96..ab7c12ceffa 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -1467,6 +1467,7 @@ const safeProviders: SafeProvider[] = [ AccountServiceAbstraction, KdfConfigService, KeyService, + StateProvider, ], }), safeProvider({ diff --git a/libs/common/src/platform/services/sdk/client-managed-state.ts b/libs/common/src/platform/services/sdk/client-managed-state.ts new file mode 100644 index 00000000000..1e3273d0801 --- /dev/null +++ b/libs/common/src/platform/services/sdk/client-managed-state.ts @@ -0,0 +1,64 @@ +import { firstValueFrom, map } from "rxjs"; + +import { UserId } from "@bitwarden/common/types/guid"; +import { CipherRecordMapper } from "@bitwarden/common/vault/models/domain/cipher-sdk-mapper"; +import { StateClient, Repository } from "@bitwarden/sdk-internal"; + +import { StateProvider, UserKeyDefinition } from "../../state"; + +export async function initializeState( + userId: UserId, + stateClient: StateClient, + stateProvider: StateProvider, +): Promise { + await stateClient.register_cipher_repository( + new RepositoryRecord(userId, stateProvider, new CipherRecordMapper()), + ); +} + +export interface SdkRecordMapper { + userKeyDefinition(): UserKeyDefinition>; + toSdk(value: ClientType): SdkType; + fromSdk(value: SdkType): ClientType; +} + +class RepositoryRecord implements Repository { + constructor( + private userId: UserId, + private stateProvider: StateProvider, + private mapper: SdkRecordMapper, + ) {} + + async get(id: string): Promise { + const prov = this.stateProvider.getUser(this.userId, this.mapper.userKeyDefinition()); + const data = await firstValueFrom(prov.state$.pipe(map((data) => data ?? {}))); + const element = data[id]; + if (!element) { + return null; + } + return this.mapper.toSdk(element); + } + + async list(): Promise { + const prov = this.stateProvider.getUser(this.userId, this.mapper.userKeyDefinition()); + const elements = await firstValueFrom(prov.state$.pipe(map((data) => data ?? {}))); + return Object.values(elements).map((element) => this.mapper.toSdk(element)); + } + + async set(id: string, value: SdkType): Promise { + const prov = this.stateProvider.getUser(this.userId, this.mapper.userKeyDefinition()); + const elements = await firstValueFrom(prov.state$.pipe(map((data) => data ?? {}))); + elements[id] = this.mapper.fromSdk(value); + await prov.update(() => elements); + } + + async remove(id: string): Promise { + const prov = this.stateProvider.getUser(this.userId, this.mapper.userKeyDefinition()); + const elements = await firstValueFrom(prov.state$.pipe(map((data) => data ?? {}))); + if (!elements[id]) { + return; + } + delete elements[id]; + await prov.update(() => elements); + } +} diff --git a/libs/common/src/platform/services/sdk/default-sdk.service.ts b/libs/common/src/platform/services/sdk/default-sdk.service.ts index d8780b0f1f4..4359f03a17f 100644 --- a/libs/common/src/platform/services/sdk/default-sdk.service.ts +++ b/libs/common/src/platform/services/sdk/default-sdk.service.ts @@ -38,6 +38,9 @@ import { SdkLoadService } from "../../abstractions/sdk/sdk-load.service"; import { SdkService, UserNotLoggedInError } from "../../abstractions/sdk/sdk.service"; import { compareValues } from "../../misc/compare-values"; import { Rc } from "../../misc/reference-counting/rc"; +import { StateProvider } from "../../state"; + +import { initializeState } from "./client-managed-state"; // A symbol that represents an overriden client that is explicitly set to undefined, // blocking the creation of an internal client for that user. @@ -81,6 +84,7 @@ export class DefaultSdkService implements SdkService { private accountService: AccountService, private kdfConfigService: KdfConfigService, private keyService: KeyService, + private stateProvider?: StateProvider, private userAgent: string | null = null, ) {} @@ -241,6 +245,12 @@ export class DefaultSdkService implements SdkService { .map(([k, v]) => [k, v.key as UnsignedSharedKey]), ), }); + + // This is optional to avoid having to mock it on the tests + if (this.stateProvider) { + // Initialize the SDK managed database and the client managed repositories. + await initializeState(userId, client.platform().state(), this.stateProvider); + } } private toSettings(env: Environment): ClientSettings { diff --git a/libs/common/src/vault/models/domain/cipher-sdk-mapper.ts b/libs/common/src/vault/models/domain/cipher-sdk-mapper.ts new file mode 100644 index 00000000000..644a9ff7645 --- /dev/null +++ b/libs/common/src/vault/models/domain/cipher-sdk-mapper.ts @@ -0,0 +1,22 @@ +import { SdkRecordMapper } from "@bitwarden/common/platform/services/sdk/client-managed-state"; +import { UserKeyDefinition } from "@bitwarden/common/platform/state"; +import { Cipher as SdkCipher } from "@bitwarden/sdk-internal"; + +import { ENCRYPTED_CIPHERS } from "../../services/key-state/ciphers.state"; +import { CipherData } from "../data/cipher.data"; + +import { Cipher } from "./cipher"; + +export class CipherRecordMapper implements SdkRecordMapper { + userKeyDefinition(): UserKeyDefinition> { + return ENCRYPTED_CIPHERS; + } + + toSdk(value: CipherData): SdkCipher { + return new Cipher(value).toSdkCipher(); + } + + fromSdk(value: SdkCipher): CipherData { + throw new Error("Cipher.fromSdk is not implemented yet"); + } +} From 92c9aa7b3e37a7dcdcf48fca927a868abc7e44a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa?= Date: Fri, 22 Aug 2025 15:19:18 +0200 Subject: [PATCH 017/167] Use FakeStateProvider in SdkService tests (#16126) --- .../services/sdk/default-sdk.service.spec.ts | 22 +++++++++++++++---- .../services/sdk/default-sdk.service.ts | 9 +++----- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts b/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts index 17d98159c41..30b43bfe00a 100644 --- a/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts +++ b/libs/common/src/platform/services/sdk/default-sdk.service.spec.ts @@ -6,8 +6,13 @@ import { BehaviorSubject, firstValueFrom, of } from "rxjs"; import { KdfConfigService, KeyService, PBKDF2KdfConfig } from "@bitwarden/key-management"; import { BitwardenClient } from "@bitwarden/sdk-internal"; -import { ObservableTracker } from "../../../../spec"; -import { AccountInfo, AccountService } from "../../../auth/abstractions/account.service"; +import { + FakeAccountService, + FakeStateProvider, + mockAccountServiceWith, + ObservableTracker, +} from "../../../../spec"; +import { AccountInfo } from "../../../auth/abstractions/account.service"; import { EncryptedString } from "../../../key-management/crypto/models/enc-string"; import { UserId } from "../../../types/guid"; import { UserKey } from "../../../types/key"; @@ -17,6 +22,7 @@ import { SdkClientFactory } from "../../abstractions/sdk/sdk-client-factory"; import { SdkLoadService } from "../../abstractions/sdk/sdk-load.service"; import { UserNotLoggedInError } from "../../abstractions/sdk/sdk.service"; import { Rc } from "../../misc/reference-counting/rc"; +import { Utils } from "../../misc/utils"; import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key"; import { DefaultSdkService } from "./default-sdk.service"; @@ -33,10 +39,11 @@ describe("DefaultSdkService", () => { let sdkClientFactory!: MockProxy; let environmentService!: MockProxy; let platformUtilsService!: MockProxy; - let accountService!: MockProxy; let kdfConfigService!: MockProxy; let keyService!: MockProxy; let service!: DefaultSdkService; + let accountService!: FakeAccountService; + let fakeStateProvider!: FakeStateProvider; beforeEach(async () => { await new TestSdkLoadService().loadAndInit(); @@ -44,9 +51,11 @@ describe("DefaultSdkService", () => { sdkClientFactory = mock(); environmentService = mock(); platformUtilsService = mock(); - accountService = mock(); kdfConfigService = mock(); keyService = mock(); + const mockUserId = Utils.newGuid() as UserId; + accountService = mockAccountServiceWith(mockUserId); + fakeStateProvider = new FakeStateProvider(accountService); // Can't use `of(mock())` for some reason environmentService.environment$ = new BehaviorSubject(mock()); @@ -58,6 +67,7 @@ describe("DefaultSdkService", () => { accountService, kdfConfigService, keyService, + fakeStateProvider, ); }); @@ -219,5 +229,9 @@ describe("DefaultSdkService", () => { function createMockClient(): MockProxy { const client = mock(); client.crypto.mockReturnValue(mock()); + client.platform.mockReturnValue({ + state: jest.fn().mockReturnValue(mock()), + free: mock(), + }); return client; } diff --git a/libs/common/src/platform/services/sdk/default-sdk.service.ts b/libs/common/src/platform/services/sdk/default-sdk.service.ts index 4359f03a17f..629d7dafed5 100644 --- a/libs/common/src/platform/services/sdk/default-sdk.service.ts +++ b/libs/common/src/platform/services/sdk/default-sdk.service.ts @@ -84,7 +84,7 @@ export class DefaultSdkService implements SdkService { private accountService: AccountService, private kdfConfigService: KdfConfigService, private keyService: KeyService, - private stateProvider?: StateProvider, + private stateProvider: StateProvider, private userAgent: string | null = null, ) {} @@ -246,11 +246,8 @@ export class DefaultSdkService implements SdkService { ), }); - // This is optional to avoid having to mock it on the tests - if (this.stateProvider) { - // Initialize the SDK managed database and the client managed repositories. - await initializeState(userId, client.platform().state(), this.stateProvider); - } + // Initialize the SDK managed database and the client managed repositories. + await initializeState(userId, client.platform().state(), this.stateProvider); } private toSettings(env: Environment): ClientSettings { From eb84faaf9907e67e3ff23f6968ffcbcba542952b Mon Sep 17 00:00:00 2001 From: Bryan Cunningham Date: Fri, 22 Aug 2025 10:01:23 -0400 Subject: [PATCH 018/167] [CL-825] Provide dimensions to checkbox to fix ios rendering bug (#16109) * absolutely position checkbox to fix ios rendering bug * remove absolute positioning. Dimensions fix it --- libs/components/src/checkbox/checkbox.component.ts | 3 +++ libs/components/src/form-control/form-control.component.html | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/components/src/checkbox/checkbox.component.ts b/libs/components/src/checkbox/checkbox.component.ts index f93861c877a..b5d53c41fd6 100644 --- a/libs/components/src/checkbox/checkbox.component.ts +++ b/libs/components/src/checkbox/checkbox.component.ts @@ -21,6 +21,9 @@ export class CheckboxComponent implements BitFormControlAbstraction { "tw-align-sub", "tw-flex-none", // Flexbox fix for bit-form-control "!tw-p-1", + // Give checkbox explicit height and width to fix iOS rendering bug + "tw-h-[calc(1.12rem_+_theme(spacing.2))]", + "tw-w-[calc(1.12rem_+_theme(spacing.2))]", "after:tw-inset-1", // negative margin to negate the positioning added by the padding "!-tw-mt-1", diff --git a/libs/components/src/form-control/form-control.component.html b/libs/components/src/form-control/form-control.component.html index 3dc3f90c9b0..4fbb8e6342e 100644 --- a/libs/components/src/form-control/form-control.component.html +++ b/libs/components/src/form-control/form-control.component.html @@ -1,5 +1,5 @@
-
-
- -
-
diff --git a/apps/desktop/src/app/accounts/settings.component.spec.ts b/apps/desktop/src/app/accounts/settings.component.spec.ts index 10825df7093..4219a9952c6 100644 --- a/apps/desktop/src/app/accounts/settings.component.spec.ts +++ b/apps/desktop/src/app/accounts/settings.component.spec.ts @@ -157,7 +157,6 @@ describe("SettingsComponent", () => { ); vaultTimeoutSettingsService.isBiometricLockSet.mockResolvedValue(false); biometricStateService.promptAutomatically$ = of(false); - biometricStateService.requirePasswordOnStart$ = of(false); autofillSettingsServiceAbstraction.clearClipboardDelay$ = of(null); desktopSettingsService.minimizeOnCopy$ = of(false); desktopSettingsService.trayEnabled$ = of(false); @@ -378,48 +377,14 @@ describe("SettingsComponent", () => { }); describe("when updating to false", () => { - let updateRequirePasswordOnStartSpy: jest.SpyInstance; - - beforeEach(() => { - updateRequirePasswordOnStartSpy = jest - .spyOn(component, "updateRequirePasswordOnStart") - .mockImplementation(() => Promise.resolve()); - }); - - it("updates requires password on start when the user doesn't have a MP and has requirePasswordOnStart on", async () => { + it("sets the pin form control to false and clears vault timeout", async () => { await component.ngOnInit(); - component.form.controls.requirePasswordOnStart.setValue(true, { emitEvent: false }); - component.userHasMasterPassword = false; await component.updatePinHandler(false); expect(component.form.controls.pin.value).toBe(false); - expect(component.form.controls.requirePasswordOnStart.value).toBe(false); - expect(updateRequirePasswordOnStartSpy).toHaveBeenCalled(); expect(vaultTimeoutSettingsService.clear).toHaveBeenCalled(); expect(messagingService.send).toHaveBeenCalledWith("redrawMenu"); }); - - test.each([ - [true, true], - [false, true], - [false, false], - ])( - `doesn't updates requires password on start when the user's requirePasswordOnStart is %s and userHasMasterPassword is %s`, - async (requirePasswordOnStart, userHasMasterPassword) => { - await component.ngOnInit(); - component.form.controls.requirePasswordOnStart.setValue(requirePasswordOnStart, { - emitEvent: false, - }); - component.userHasMasterPassword = userHasMasterPassword; - await component.updatePinHandler(false); - - expect(component.form.controls.pin.value).toBe(false); - expect(component.form.controls.requirePasswordOnStart.value).toBe(requirePasswordOnStart); - expect(updateRequirePasswordOnStartSpy).not.toHaveBeenCalled(); - expect(vaultTimeoutSettingsService.clear).toHaveBeenCalled(); - expect(messagingService.send).toHaveBeenCalledWith("redrawMenu"); - }, - ); }); }); @@ -512,11 +477,8 @@ describe("SettingsComponent", () => { await component.updateBiometricHandler(true); expect(biometricStateService.setBiometricUnlockEnabled).toHaveBeenCalledWith(true); - expect(component.form.controls.requirePasswordOnStart.value).toBe(true); expect(component.form.controls.autoPromptBiometrics.value).toBe(false); expect(biometricStateService.setPromptAutomatically).toHaveBeenCalledWith(false); - expect(biometricStateService.setRequirePasswordOnStart).toHaveBeenCalledWith(true); - expect(biometricStateService.setDismissedRequirePasswordOnStartCallout).toHaveBeenCalled(); expect(keyService.refreshAdditionalKeys).toHaveBeenCalledWith(mockUserId); expect(component.form.controls.biometric.value).toBe(true); expect(messagingService.send).toHaveBeenCalledWith("redrawMenu"); @@ -533,11 +495,8 @@ describe("SettingsComponent", () => { await component.updateBiometricHandler(true); expect(biometricStateService.setBiometricUnlockEnabled).toHaveBeenCalledWith(true); - expect(component.form.controls.requirePasswordOnStart.value).toBe(true); expect(component.form.controls.autoPromptBiometrics.value).toBe(false); expect(biometricStateService.setPromptAutomatically).toHaveBeenCalledWith(false); - expect(biometricStateService.setRequirePasswordOnStart).toHaveBeenCalledWith(true); - expect(biometricStateService.setDismissedRequirePasswordOnStartCallout).toHaveBeenCalled(); expect(keyService.refreshAdditionalKeys).toHaveBeenCalledWith(mockUserId); expect(component.form.controls.biometric.value).toBe(true); expect(messagingService.send).toHaveBeenCalledWith("redrawMenu"); diff --git a/apps/desktop/src/app/accounts/settings.component.ts b/apps/desktop/src/app/accounts/settings.component.ts index 066b33e4b08..fd17873a4b1 100644 --- a/apps/desktop/src/app/accounts/settings.component.ts +++ b/apps/desktop/src/app/accounts/settings.component.ts @@ -135,7 +135,6 @@ export class SettingsComponent implements OnInit, OnDestroy { pin: [null as boolean | null], biometric: false, autoPromptBiometrics: false, - requirePasswordOnStart: false, // Account Preferences clearClipboard: [null], minimizeOnCopyToClipboard: false, @@ -350,9 +349,6 @@ export class SettingsComponent implements OnInit, OnDestroy { pin: this.userHasPinSet, biometric: await this.vaultTimeoutSettingsService.isBiometricLockSet(), autoPromptBiometrics: await firstValueFrom(this.biometricStateService.promptAutomatically$), - requirePasswordOnStart: await firstValueFrom( - this.biometricStateService.requirePasswordOnStart$, - ), clearClipboard: await firstValueFrom(this.autofillSettingsService.clearClipboardDelay$), minimizeOnCopyToClipboard: await firstValueFrom(this.desktopSettingsService.minimizeOnCopy$), enableFavicons: await firstValueFrom(this.domainSettingsService.showFavicons$), @@ -557,16 +553,7 @@ export class SettingsComponent implements OnInit, OnDestroy { this.userHasPinSet = await firstValueFrom(dialogRef.closed); this.form.controls.pin.setValue(this.userHasPinSet, { emitEvent: false }); - } - - if (!value) { - // If user turned off PIN without having a MP and has biometric + require MP/PIN on restart enabled - if (this.form.value.requirePasswordOnStart && !this.userHasMasterPassword) { - // then must turn that off to prevent user from getting into bad state - this.form.controls.requirePasswordOnStart.setValue(false); - await this.updateRequirePasswordOnStart(); - } - + } else { const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)); await this.vaultTimeoutSettingsService.clear(userId); } @@ -617,18 +604,12 @@ export class SettingsComponent implements OnInit, OnDestroy { await this.biometricStateService.setBiometricUnlockEnabled(true); if (this.isWindows) { // Recommended settings for Windows Hello - this.form.controls.requirePasswordOnStart.setValue(true); this.form.controls.autoPromptBiometrics.setValue(false); await this.biometricStateService.setPromptAutomatically(false); - await this.biometricStateService.setRequirePasswordOnStart(true); - await this.biometricStateService.setDismissedRequirePasswordOnStartCallout(); } else if (this.isLinux) { // Similar to Windows - this.form.controls.requirePasswordOnStart.setValue(true); this.form.controls.autoPromptBiometrics.setValue(false); await this.biometricStateService.setPromptAutomatically(false); - await this.biometricStateService.setRequirePasswordOnStart(true); - await this.biometricStateService.setDismissedRequirePasswordOnStartCallout(); } await this.keyService.refreshAdditionalKeys(activeUserId); @@ -644,30 +625,12 @@ export class SettingsComponent implements OnInit, OnDestroy { async updateAutoPromptBiometrics() { if (this.form.value.autoPromptBiometrics) { - // require password on start must be disabled if auto prompt biometrics is enabled - this.form.controls.requirePasswordOnStart.setValue(false); - await this.updateRequirePasswordOnStart(); await this.biometricStateService.setPromptAutomatically(true); } else { await this.biometricStateService.setPromptAutomatically(false); } } - async updateRequirePasswordOnStart() { - if (this.form.value.requirePasswordOnStart) { - // auto prompt biometrics must be disabled if require password on start is enabled - this.form.controls.autoPromptBiometrics.setValue(false); - await this.updateAutoPromptBiometrics(); - - await this.biometricStateService.setRequirePasswordOnStart(true); - } else { - await this.biometricStateService.setRequirePasswordOnStart(false); - } - await this.biometricStateService.setDismissedRequirePasswordOnStartCallout(); - const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)); - await this.keyService.refreshAdditionalKeys(userId); - } - async saveFavicons() { await this.domainSettingsService.setShowFavicons(this.form.value.enableFavicons); this.messagingService.send("refreshCiphers"); diff --git a/apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.ts b/apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.ts index 26a8e949f38..0ef3033b4c5 100644 --- a/apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.ts +++ b/apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.ts @@ -198,11 +198,6 @@ export default class OsBiometricsServiceLinux implements OsBiometricService { userId: UserId, key: SymmetricCryptoKey, ): Promise { - const requireClientKeyHalf = await this.biometricStateService.getRequirePasswordOnStart(userId); - if (!requireClientKeyHalf) { - return null; - } - if (this.clientKeyHalves.has(userId)) { return this.clientKeyHalves.get(userId) || null; } @@ -227,12 +222,10 @@ export default class OsBiometricsServiceLinux implements OsBiometricService { } async getBiometricsFirstUnlockStatusForUser(userId: UserId): Promise { - const requireClientKeyHalf = await this.biometricStateService.getRequirePasswordOnStart(userId); - const clientKeyHalfB64 = this.clientKeyHalves.get(userId); - const clientKeyHalfSatisfied = !requireClientKeyHalf || !!clientKeyHalfB64; - if (!clientKeyHalfSatisfied) { + if (this.clientKeyHalves.has(userId)) { + return BiometricsStatus.Available; + } else { return BiometricsStatus.UnlockNeeded; } - return BiometricsStatus.Available; } } diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index 300cf779cc3..eaa5f7f0f1e 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -1846,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/libs/key-management/src/biometrics/biometric-state.service.spec.ts b/libs/key-management/src/biometrics/biometric-state.service.spec.ts index 8569df16319..32043514ff7 100644 --- a/libs/key-management/src/biometrics/biometric-state.service.spec.ts +++ b/libs/key-management/src/biometrics/biometric-state.service.spec.ts @@ -6,7 +6,6 @@ import { trackEmissions, FakeStateProvider, FakeGlobalState, - FakeSingleUserState, FakeAccountService, mockAccountServiceWith, } from "@bitwarden/common/spec"; @@ -15,12 +14,10 @@ import { UserId } from "@bitwarden/common/types/guid"; import { BiometricStateService, DefaultBiometricStateService } from "./biometric-state.service"; import { BIOMETRIC_UNLOCK_ENABLED, - DISMISSED_REQUIRE_PASSWORD_ON_START_CALLOUT, ENCRYPTED_CLIENT_KEY_HALF, FINGERPRINT_VALIDATED, PROMPT_AUTOMATICALLY, PROMPT_CANCELLED, - REQUIRE_PASSWORD_ON_START, } from "./biometric.state"; describe("BiometricStateService", () => { @@ -42,22 +39,6 @@ describe("BiometricStateService", () => { jest.resetAllMocks(); }); - describe("requirePasswordOnStart$", () => { - it("emits when the require password on start state changes", async () => { - const state = stateProvider.activeUser.getFake(REQUIRE_PASSWORD_ON_START); - state.nextState(true); - - expect(await firstValueFrom(sut.requirePasswordOnStart$)).toBe(true); - }); - - it("emits false when the require password on start state is undefined", async () => { - const state = stateProvider.activeUser.getFake(REQUIRE_PASSWORD_ON_START); - state.nextState(undefined as unknown as boolean); - - expect(await firstValueFrom(sut.requirePasswordOnStart$)).toBe(false); - }); - }); - describe("encryptedClientKeyHalf$", () => { it("emits when the encryptedClientKeyHalf state changes", async () => { const state = stateProvider.activeUser.getFake(ENCRYPTED_CLIENT_KEY_HALF); @@ -95,61 +76,6 @@ describe("BiometricStateService", () => { }); }); - describe("setRequirePasswordOnStart", () => { - it("updates the requirePasswordOnStart$", async () => { - await sut.setRequirePasswordOnStart(true); - - expect(await firstValueFrom(sut.requirePasswordOnStart$)).toBe(true); - }); - - it("removes the encryptedClientKeyHalf when the set value is false", async () => { - await sut.setEncryptedClientKeyHalf(encClientKeyHalf, userId); - await sut.setRequirePasswordOnStart(false); - - const keyHalfState = stateProvider.getUser( - userId, - ENCRYPTED_CLIENT_KEY_HALF, - ) as FakeSingleUserState; - expect(await firstValueFrom(keyHalfState.state$)).toBe(null); - expect(keyHalfState.nextMock).toHaveBeenCalledWith(null); - }); - - it("does not remove the encryptedClientKeyHalf when the value is true", async () => { - await sut.setEncryptedClientKeyHalf(encClientKeyHalf); - await sut.setRequirePasswordOnStart(true); - - expect(await firstValueFrom(sut.encryptedClientKeyHalf$)).toEqual(encClientKeyHalf); - }); - }); - - describe("getRequirePasswordOnStart", () => { - it("returns the requirePasswordOnStart state value", async () => { - stateProvider.singleUser.mockFor(userId, REQUIRE_PASSWORD_ON_START, true); - - expect(await sut.getRequirePasswordOnStart(userId)).toBe(true); - }); - }); - - describe("require password on start callout", () => { - it("is false when not set", async () => { - expect(await firstValueFrom(sut.dismissedRequirePasswordOnStartCallout$)).toBe(false); - }); - - it("is true when set", async () => { - await sut.setDismissedRequirePasswordOnStartCallout(); - - expect(await firstValueFrom(sut.dismissedRequirePasswordOnStartCallout$)).toBe(true); - }); - - it("updates disk state when called", async () => { - await sut.setDismissedRequirePasswordOnStartCallout(); - - expect( - stateProvider.activeUser.getFake(DISMISSED_REQUIRE_PASSWORD_ON_START_CALLOUT).nextMock, - ).toHaveBeenCalledWith([userId, true]); - }); - }); - describe("setPromptCancelled", () => { let existingState: Record; diff --git a/libs/key-management/src/biometrics/biometric-state.service.ts b/libs/key-management/src/biometrics/biometric-state.service.ts index d27617315ee..1488f12b50b 100644 --- a/libs/key-management/src/biometrics/biometric-state.service.ts +++ b/libs/key-management/src/biometrics/biometric-state.service.ts @@ -10,8 +10,6 @@ import { UserId } from "@bitwarden/common/types/guid"; import { BIOMETRIC_UNLOCK_ENABLED, ENCRYPTED_CLIENT_KEY_HALF, - REQUIRE_PASSWORD_ON_START, - DISMISSED_REQUIRE_PASSWORD_ON_START_CALLOUT, PROMPT_AUTOMATICALLY, PROMPT_CANCELLED, FINGERPRINT_VALIDATED, @@ -30,18 +28,6 @@ export abstract class BiometricStateService { * Tracks the currently active user */ abstract encryptedClientKeyHalf$: Observable; - /** - * whether or not a password is required on first unlock after opening the application - * - * tracks the currently active user - */ - abstract requirePasswordOnStart$: Observable; - /** - * Indicates the user has been warned about the security implications of using biometrics and, depending on the OS, - * - * tracks the currently active user. - */ - abstract dismissedRequirePasswordOnStartCallout$: Observable; /** * Whether the user has cancelled the biometric prompt. * @@ -59,14 +45,6 @@ export abstract class BiometricStateService { */ abstract fingerprintValidated$: Observable; - /** - * Updates the require password on start state for the currently active user. - * - * If false, the encrypted client key half will be removed. - * @param value whether or not a password is required on first unlock after opening the application - */ - abstract setRequirePasswordOnStart(value: boolean): Promise; - /** * Updates the biometric unlock enabled state for the currently active user. * @param enabled whether or not to store a biometric key to unlock the vault @@ -83,15 +61,6 @@ export abstract class BiometricStateService { abstract getEncryptedClientKeyHalf(userId: UserId): Promise; - abstract getRequirePasswordOnStart(userId: UserId): Promise; - - abstract removeEncryptedClientKeyHalf(userId: UserId): Promise; - - /** - * Updates the active user's state to reflect that they've been warned about requiring password on start. - */ - abstract setDismissedRequirePasswordOnStartCallout(): Promise; - /** * Updates the active user's state to reflect that they've cancelled the biometric prompt. */ @@ -129,17 +98,13 @@ export abstract class BiometricStateService { export class DefaultBiometricStateService implements BiometricStateService { private biometricUnlockEnabledState: ActiveUserState; - private requirePasswordOnStartState: ActiveUserState; private encryptedClientKeyHalfState: ActiveUserState; - private dismissedRequirePasswordOnStartCalloutState: ActiveUserState; private promptCancelledState: GlobalState>; private promptAutomaticallyState: ActiveUserState; private fingerprintValidatedState: GlobalState; private lastProcessReloadState: GlobalState; biometricUnlockEnabled$: Observable; encryptedClientKeyHalf$: Observable; - requirePasswordOnStart$: Observable; - dismissedRequirePasswordOnStartCallout$: Observable; promptCancelled$: Observable; promptAutomatically$: Observable; fingerprintValidated$: Observable; @@ -149,22 +114,11 @@ export class DefaultBiometricStateService implements BiometricStateService { this.biometricUnlockEnabledState = this.stateProvider.getActive(BIOMETRIC_UNLOCK_ENABLED); this.biometricUnlockEnabled$ = this.biometricUnlockEnabledState.state$.pipe(map(Boolean)); - this.requirePasswordOnStartState = this.stateProvider.getActive(REQUIRE_PASSWORD_ON_START); - this.requirePasswordOnStart$ = this.requirePasswordOnStartState.state$.pipe( - map((value) => !!value), - ); - this.encryptedClientKeyHalfState = this.stateProvider.getActive(ENCRYPTED_CLIENT_KEY_HALF); this.encryptedClientKeyHalf$ = this.encryptedClientKeyHalfState.state$.pipe( map(encryptedClientKeyHalfToEncString), ); - this.dismissedRequirePasswordOnStartCalloutState = this.stateProvider.getActive( - DISMISSED_REQUIRE_PASSWORD_ON_START_CALLOUT, - ); - this.dismissedRequirePasswordOnStartCallout$ = - this.dismissedRequirePasswordOnStartCalloutState.state$.pipe(map(Boolean)); - this.promptCancelledState = this.stateProvider.getGlobal(PROMPT_CANCELLED); this.promptCancelled$ = combineLatest([ this.stateProvider.activeUserId$, @@ -194,22 +148,6 @@ export class DefaultBiometricStateService implements BiometricStateService { ); } - async setRequirePasswordOnStart(value: boolean): Promise { - let currentActiveId: UserId | undefined = undefined; - await this.requirePasswordOnStartState.update( - (_, [userId]) => { - currentActiveId = userId; - return value; - }, - { - combineLatestWith: this.requirePasswordOnStartState.combinedState$, - }, - ); - if (!value && currentActiveId) { - await this.removeEncryptedClientKeyHalf(currentActiveId); - } - } - async setEncryptedClientKeyHalf(encryptedKeyHalf: EncString, userId?: UserId): Promise { const value = encryptedKeyHalf?.encryptedString ?? null; if (userId) { @@ -219,16 +157,6 @@ export class DefaultBiometricStateService implements BiometricStateService { } } - async removeEncryptedClientKeyHalf(userId: UserId): Promise { - await this.stateProvider.getUser(userId, ENCRYPTED_CLIENT_KEY_HALF).update(() => null); - } - - async getRequirePasswordOnStart(userId: UserId): Promise { - return !!(await firstValueFrom( - this.stateProvider.getUser(userId, REQUIRE_PASSWORD_ON_START).state$, - )); - } - async getEncryptedClientKeyHalf(userId: UserId): Promise { return await firstValueFrom( this.stateProvider @@ -244,10 +172,6 @@ export class DefaultBiometricStateService implements BiometricStateService { // Persist dismissed require password on start callout through logout } - async setDismissedRequirePasswordOnStartCallout(): Promise { - await this.dismissedRequirePasswordOnStartCalloutState.update(() => true); - } - async resetUserPromptCancelled(userId: UserId): Promise { await this.stateProvider.getGlobal(PROMPT_CANCELLED).update( (data, activeUserId) => { diff --git a/libs/key-management/src/biometrics/biometric.state.spec.ts b/libs/key-management/src/biometrics/biometric.state.spec.ts index b961808cea7..8235ff4fabe 100644 --- a/libs/key-management/src/biometrics/biometric.state.spec.ts +++ b/libs/key-management/src/biometrics/biometric.state.spec.ts @@ -2,20 +2,16 @@ import { KeyDefinition, UserKeyDefinition } from "@bitwarden/common/platform/sta import { BIOMETRIC_UNLOCK_ENABLED, - DISMISSED_REQUIRE_PASSWORD_ON_START_CALLOUT, ENCRYPTED_CLIENT_KEY_HALF, FINGERPRINT_VALIDATED, PROMPT_AUTOMATICALLY, PROMPT_CANCELLED, - REQUIRE_PASSWORD_ON_START, } from "./biometric.state"; describe.each([ [ENCRYPTED_CLIENT_KEY_HALF, "encryptedClientKeyHalf"], - [DISMISSED_REQUIRE_PASSWORD_ON_START_CALLOUT, true], [PROMPT_CANCELLED, { userId1: true, userId2: false }], [PROMPT_AUTOMATICALLY, true], - [REQUIRE_PASSWORD_ON_START, true], [BIOMETRIC_UNLOCK_ENABLED, true], [FINGERPRINT_VALIDATED, true], ])( diff --git a/libs/key-management/src/biometrics/biometric.state.ts b/libs/key-management/src/biometrics/biometric.state.ts index 31570a71837..1ce469e7837 100644 --- a/libs/key-management/src/biometrics/biometric.state.ts +++ b/libs/key-management/src/biometrics/biometric.state.ts @@ -18,20 +18,6 @@ export const BIOMETRIC_UNLOCK_ENABLED = new UserKeyDefinition( }, ); -/** - * Boolean indicating the user has elected to require a password to use their biometric key upon starting the application. - * - * A true setting controls whether {@link ENCRYPTED_CLIENT_KEY_HALF} is set. - */ -export const REQUIRE_PASSWORD_ON_START = new UserKeyDefinition( - BIOMETRIC_SETTINGS_DISK, - "requirePasswordOnStart", - { - deserializer: (value: any) => value, - clearOn: [], - }, -); - /** * If the user has elected to require a password on first unlock of an application instance, this key will store the * encrypted client key half used to unlock the vault. @@ -48,19 +34,6 @@ export const ENCRYPTED_CLIENT_KEY_HALF = new UserKeyDefinition( }, ); -/** - * Indicates the user has been warned about the security implications of using biometrics and, depending on the OS, - * recommended to require a password on first unlock of an application instance. - */ -export const DISMISSED_REQUIRE_PASSWORD_ON_START_CALLOUT = new UserKeyDefinition( - BIOMETRIC_SETTINGS_DISK, - "dismissedBiometricRequirePasswordOnStartCallout", - { - deserializer: (obj) => obj, - clearOn: [], - }, -); - /** * Stores whether the user has elected to cancel the biometric prompt. This is stored on disk due to process-reload * wiping memory state. We don't want to prompt the user again if they've elected to cancel. From 1674709a58b296a5aaf342f7370b6f99c90fd879 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 12:47:31 +0200 Subject: [PATCH 030/167] Autosync the updated translations (#16118) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/desktop/src/locales/af/messages.json | 18 +- apps/desktop/src/locales/ar/messages.json | 18 +- apps/desktop/src/locales/az/messages.json | 18 +- apps/desktop/src/locales/be/messages.json | 18 +- apps/desktop/src/locales/bg/messages.json | 18 +- apps/desktop/src/locales/bn/messages.json | 18 +- apps/desktop/src/locales/bs/messages.json | 18 +- apps/desktop/src/locales/ca/messages.json | 18 +- apps/desktop/src/locales/cs/messages.json | 18 +- apps/desktop/src/locales/cy/messages.json | 18 +- apps/desktop/src/locales/da/messages.json | 18 +- apps/desktop/src/locales/de/messages.json | 18 +- apps/desktop/src/locales/el/messages.json | 18 +- apps/desktop/src/locales/en_GB/messages.json | 18 +- apps/desktop/src/locales/en_IN/messages.json | 18 +- apps/desktop/src/locales/eo/messages.json | 18 +- apps/desktop/src/locales/es/messages.json | 18 +- apps/desktop/src/locales/et/messages.json | 18 +- apps/desktop/src/locales/eu/messages.json | 18 +- apps/desktop/src/locales/fa/messages.json | 18 +- apps/desktop/src/locales/fi/messages.json | 18 +- apps/desktop/src/locales/fil/messages.json | 18 +- apps/desktop/src/locales/fr/messages.json | 18 +- apps/desktop/src/locales/gl/messages.json | 18 +- apps/desktop/src/locales/he/messages.json | 18 +- apps/desktop/src/locales/hi/messages.json | 18 +- apps/desktop/src/locales/hr/messages.json | 18 +- apps/desktop/src/locales/hu/messages.json | 18 +- apps/desktop/src/locales/id/messages.json | 20 +- apps/desktop/src/locales/it/messages.json | 18 +- apps/desktop/src/locales/ja/messages.json | 18 +- apps/desktop/src/locales/ka/messages.json | 18 +- apps/desktop/src/locales/km/messages.json | 18 +- apps/desktop/src/locales/kn/messages.json | 18 +- apps/desktop/src/locales/ko/messages.json | 18 +- apps/desktop/src/locales/lt/messages.json | 18 +- apps/desktop/src/locales/lv/messages.json | 18 +- apps/desktop/src/locales/me/messages.json | 18 +- apps/desktop/src/locales/ml/messages.json | 18 +- apps/desktop/src/locales/mr/messages.json | 18 +- apps/desktop/src/locales/my/messages.json | 18 +- apps/desktop/src/locales/nb/messages.json | 18 +- apps/desktop/src/locales/ne/messages.json | 18 +- apps/desktop/src/locales/nl/messages.json | 18 +- apps/desktop/src/locales/nn/messages.json | 18 +- apps/desktop/src/locales/or/messages.json | 18 +- apps/desktop/src/locales/pl/messages.json | 750 +++++++++---------- apps/desktop/src/locales/pt_BR/messages.json | 18 +- apps/desktop/src/locales/pt_PT/messages.json | 58 +- apps/desktop/src/locales/ro/messages.json | 18 +- apps/desktop/src/locales/ru/messages.json | 18 +- apps/desktop/src/locales/si/messages.json | 18 +- apps/desktop/src/locales/sk/messages.json | 18 +- apps/desktop/src/locales/sl/messages.json | 18 +- apps/desktop/src/locales/sr/messages.json | 18 +- apps/desktop/src/locales/sv/messages.json | 18 +- apps/desktop/src/locales/te/messages.json | 18 +- apps/desktop/src/locales/th/messages.json | 18 +- apps/desktop/src/locales/tr/messages.json | 18 +- apps/desktop/src/locales/uk/messages.json | 18 +- apps/desktop/src/locales/vi/messages.json | 18 +- apps/desktop/src/locales/zh_CN/messages.json | 18 +- apps/desktop/src/locales/zh_TW/messages.json | 18 +- 63 files changed, 954 insertions(+), 954 deletions(-) diff --git a/apps/desktop/src/locales/af/messages.json b/apps/desktop/src/locales/af/messages.json index 3a483445ae2..aac699b6003 100644 --- a/apps/desktop/src/locales/af/messages.json +++ b/apps/desktop/src/locales/af/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Kies dié opsie as jy die inhoud van die ingevoerde lêer na $DESTINATION$ wil skuif", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Lêer bevat ontoegewysde items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/ar/messages.json b/apps/desktop/src/locales/ar/messages.json index ebaef5f120c..2692c061373 100644 --- a/apps/desktop/src/locales/ar/messages.json +++ b/apps/desktop/src/locales/ar/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "اختر مجموعة" }, - "importTargetHint": { - "message": "حدد هذا الخيار إذا كنت تريد نقل محتويات الملف المستورد إلى $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "الملف يحتوي على عناصر غير معينة." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/az/messages.json b/apps/desktop/src/locales/az/messages.json index d8dd0c73339..9995bc3cbb3 100644 --- a/apps/desktop/src/locales/az/messages.json +++ b/apps/desktop/src/locales/az/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Bir kolleksiya seçin" }, - "importTargetHint": { - "message": "Daxilə köçürülən fayl məzmununun $DESTINATION$ yerinə daşınmasını istəyirsinizsə bu variantı seçin", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Faylda təyin edilməmiş elementlər var." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden, giriş yerlərini doğrulamır, qısayolu istifadə etməzdən əvvəl doğru pəncərədə və xanada olduğunuza əmin olun." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/be/messages.json b/apps/desktop/src/locales/be/messages.json index 8052446fadd..fbe6b098d8b 100644 --- a/apps/desktop/src/locales/be/messages.json +++ b/apps/desktop/src/locales/be/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/bg/messages.json b/apps/desktop/src/locales/bg/messages.json index c4c1e64caea..99434e6c992 100644 --- a/apps/desktop/src/locales/bg/messages.json +++ b/apps/desktop/src/locales/bg/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Изберете колекция" }, - "importTargetHint": { - "message": "Изберете тази опция, ако искате съдържанието на внесения файл да бъде преместено в $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Изберете тази опция, ако искате съдържанието на внесения файл да бъде преместено в колекция" + }, + "importTargetHintFolder": { + "message": "Изберете тази опция, ако искате съдържанието на внесения файл да бъде преместено в папка" }, "importUnassignedItemsError": { "message": "Файлът съдържа невъзложени елементи." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Битуорден не проверява местата за въвеждане, така че се уверете, че сте в правилния прозорец, преди да ползвате клавишната комбинация." + }, + "moreBreadcrumbs": { + "message": "Още елементи в пътечката", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/bn/messages.json b/apps/desktop/src/locales/bn/messages.json index 229b565c533..36db3a37cce 100644 --- a/apps/desktop/src/locales/bn/messages.json +++ b/apps/desktop/src/locales/bn/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/bs/messages.json b/apps/desktop/src/locales/bs/messages.json index d75193c4d2c..c745a150698 100644 --- a/apps/desktop/src/locales/bs/messages.json +++ b/apps/desktop/src/locales/bs/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/ca/messages.json b/apps/desktop/src/locales/ca/messages.json index ec9c824a6b9..0c03f554d33 100644 --- a/apps/desktop/src/locales/ca/messages.json +++ b/apps/desktop/src/locales/ca/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Selecciona una col·lecció" }, - "importTargetHint": { - "message": "Seleccioneu aquesta opció si voleu que el contingut del fitxer importat es traslladi a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "El fitxer conté elements no assignats." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/cs/messages.json b/apps/desktop/src/locales/cs/messages.json index 54346110f5d..31952bc3812 100644 --- a/apps/desktop/src/locales/cs/messages.json +++ b/apps/desktop/src/locales/cs/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Zvolte sbírku" }, - "importTargetHint": { - "message": "Pokud chcete obsah importovaného souboru přesunout do složky $DESTINATION$, vyberte tuto volbu", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Pokud chcete obsah importovaného souboru přesunout do sbírky, vyberte tuto volbu" + }, + "importTargetHintFolder": { + "message": "Pokud chcete obsah importovaného souboru přesunout do složky, vyberte tuto volbu" }, "importUnassignedItemsError": { "message": "Soubor obsahuje nepřiřazené položky." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden neověřuje umístění vstupu. Před použitím zkratky se ujistěte, že jste ve správném okně a poli." + }, + "moreBreadcrumbs": { + "message": "Více...", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/cy/messages.json b/apps/desktop/src/locales/cy/messages.json index a6400c36e53..aa4c7c519a8 100644 --- a/apps/desktop/src/locales/cy/messages.json +++ b/apps/desktop/src/locales/cy/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/da/messages.json b/apps/desktop/src/locales/da/messages.json index 81df0a0aeb2..43f1287ee3c 100644 --- a/apps/desktop/src/locales/da/messages.json +++ b/apps/desktop/src/locales/da/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Vælg en samling" }, - "importTargetHint": { - "message": "Vælg denne indstilling, hvis importeret filindhold skal flyttet til en $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Fil indeholder ikke-tildelte emner." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/de/messages.json b/apps/desktop/src/locales/de/messages.json index ec727bc69d8..94dd43c3499 100644 --- a/apps/desktop/src/locales/de/messages.json +++ b/apps/desktop/src/locales/de/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Sammlung auswählen" }, - "importTargetHint": { - "message": "Wähle diese Option, wenn der importierte Dateiinhalt in eine(n) $DESTINATION$ verschoben werden soll", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Die Datei enthält nicht zugewiesene Einträge." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden überprüft die Eingabestellen nicht. Vergewissere dich, dass du dich im richtigen Fenster und Feld befindest, bevor du die Tastenkombination verwendest." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/el/messages.json b/apps/desktop/src/locales/el/messages.json index 049bfa7780b..6c93205d6eb 100644 --- a/apps/desktop/src/locales/el/messages.json +++ b/apps/desktop/src/locales/el/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Επιλέξτε μια συλλογή" }, - "importTargetHint": { - "message": "Επιλέξτε αυτή την επιλογή εάν θέλετε τα περιεχόμενα του εισαγόμενου αρχείου να μετακινηθούν σε $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Το αρχείο περιέχει μη αναθετημένα αντικείμενα." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/en_GB/messages.json b/apps/desktop/src/locales/en_GB/messages.json index 3d4f0120eba..f82c493a646 100644 --- a/apps/desktop/src/locales/en_GB/messages.json +++ b/apps/desktop/src/locales/en_GB/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/en_IN/messages.json b/apps/desktop/src/locales/en_IN/messages.json index 4576e5212d3..85e486e5cef 100644 --- a/apps/desktop/src/locales/en_IN/messages.json +++ b/apps/desktop/src/locales/en_IN/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/eo/messages.json b/apps/desktop/src/locales/eo/messages.json index 0306fd420bc..17ac511b174 100644 --- a/apps/desktop/src/locales/eo/messages.json +++ b/apps/desktop/src/locales/eo/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Elekti kolekton" }, - "importTargetHint": { - "message": "Elektu tiun ĉi elekteblon se vi volus la enhavojn de la enporta dosiero movi al $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/es/messages.json b/apps/desktop/src/locales/es/messages.json index 912d92665cd..2282fca50d1 100644 --- a/apps/desktop/src/locales/es/messages.json +++ b/apps/desktop/src/locales/es/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Escoge una colección" }, - "importTargetHint": { - "message": "Selecciona esta opción si quieres que el contenido del archivo importado se mueva a un $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "El archivo contiene elementos no asignados." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden no valida las ubicaciones de entrada, asegúrate de que estás en la ventana y en el capo correctos antes de usar el atajo." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/et/messages.json b/apps/desktop/src/locales/et/messages.json index 267714a3f53..374f9afb265 100644 --- a/apps/desktop/src/locales/et/messages.json +++ b/apps/desktop/src/locales/et/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Vali kogumik" }, - "importTargetHint": { - "message": "Tee siin valik, kui soovid, et imporditud faili sisu liigutatakse asukohta $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Fail sisaldab määramata kirjeid." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/eu/messages.json b/apps/desktop/src/locales/eu/messages.json index 01a522a3c8e..54bffefada1 100644 --- a/apps/desktop/src/locales/eu/messages.json +++ b/apps/desktop/src/locales/eu/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/fa/messages.json b/apps/desktop/src/locales/fa/messages.json index f48383d6aed..50480b329c8 100644 --- a/apps/desktop/src/locales/fa/messages.json +++ b/apps/desktop/src/locales/fa/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "یک مجموعه انتخاب کنید" }, - "importTargetHint": { - "message": "اگر می‌خواهید محتوای پرونده درون ریزی شده به $DESTINATION$ منتقل شود، این گزینه را انتخاب کنید", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "پرونده حاوی موارد اختصاص نیافته است." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/fi/messages.json b/apps/desktop/src/locales/fi/messages.json index fbe43e03514..8eeebcd48fb 100644 --- a/apps/desktop/src/locales/fi/messages.json +++ b/apps/desktop/src/locales/fi/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Valitse kokoelma" }, - "importTargetHint": { - "message": "Valitse tämä, jos haluat tuoda tiedoston sisällön kohteeseen \"$DESTINATION$\".", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Tiedosto sisältää määrittämättömiä kohteita." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/fil/messages.json b/apps/desktop/src/locales/fil/messages.json index f3f771d4004..cca4ebfc0f4 100644 --- a/apps/desktop/src/locales/fil/messages.json +++ b/apps/desktop/src/locales/fil/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/fr/messages.json b/apps/desktop/src/locales/fr/messages.json index f0f2eec9c7a..fd402e2c447 100644 --- a/apps/desktop/src/locales/fr/messages.json +++ b/apps/desktop/src/locales/fr/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Sélectionnez une collection" }, - "importTargetHint": { - "message": "Sélectionnez cette option si vous voulez que le contenu du fichier importé soit déplacé vers un(e) $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Le fichier contient des éléments non assignés." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden ne valide pas les emplacements d'entrée, assurez-vous d'être dans la bonne fenêtre et le bon champ avant d'utiliser le raccourci." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/gl/messages.json b/apps/desktop/src/locales/gl/messages.json index 2e0d5b09f5c..028bc34f77e 100644 --- a/apps/desktop/src/locales/gl/messages.json +++ b/apps/desktop/src/locales/gl/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/he/messages.json b/apps/desktop/src/locales/he/messages.json index 116556afcb2..e9cc7541921 100644 --- a/apps/desktop/src/locales/he/messages.json +++ b/apps/desktop/src/locales/he/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "בחר אוסף" }, - "importTargetHint": { - "message": "בחר באפשרות זו אם ברצונך להעביר את תוכן הקובץ המיובא אל $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "קובץ מכיל פריטים לא מוקצים." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden לא מאמת את מקומות הקלט, נא לוודא שזה החלון והשדה הנכונים בטרם שימוש בקיצור הדרך." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/hi/messages.json b/apps/desktop/src/locales/hi/messages.json index 234d1ca9283..3c9bbd4d497 100644 --- a/apps/desktop/src/locales/hi/messages.json +++ b/apps/desktop/src/locales/hi/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/hr/messages.json b/apps/desktop/src/locales/hr/messages.json index 5266c7cb137..31f01655fde 100644 --- a/apps/desktop/src/locales/hr/messages.json +++ b/apps/desktop/src/locales/hr/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Odaberi zbirku" }, - "importTargetHint": { - "message": "Odaberi ovu opciju ako sadržaj uvezene datoteke želiš spremiti u $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Datoteka sadrži nedodijeljene stavke." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden ne provjerava lokacije unosa, prije korištenja prečaca provjeri da si u pravom prozoru i polju." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/hu/messages.json b/apps/desktop/src/locales/hu/messages.json index 2f0d15b3fe0..cee3549bc50 100644 --- a/apps/desktop/src/locales/hu/messages.json +++ b/apps/desktop/src/locales/hu/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Gyűjtemény kiválasztása" }, - "importTargetHint": { - "message": "Válasszuk ezt a lehetőséget, ha azt akarjuk, hogy az importált fájl tartalma $DESTINATION$ helyre kerüljön", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Válasszuk ezt az opciót, ha azt akarjuk, hogy az importált fájl tartalma egy gyűjteménybe kerüljön." + }, + "importTargetHintFolder": { + "message": "Válasszuk ezt az opciót, ha azt akarjuk, hogy az importált fájl tartalma egy mappába kerüljön." }, "importUnassignedItemsError": { "message": "A fájl hozzá nem rendelt elemeket tartalmaz." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "A Bitwarden nem érvényesíti a beviteli helyeket, győződjünk meg róla, hogy a megfelelő ablakban és mezőben vagyunk, mielőtt a parancsikont használnánk." + }, + "moreBreadcrumbs": { + "message": "További morzsamenük", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/id/messages.json b/apps/desktop/src/locales/id/messages.json index 01a10a65ef4..fa11c2e5f88 100644 --- a/apps/desktop/src/locales/id/messages.json +++ b/apps/desktop/src/locales/id/messages.json @@ -2664,7 +2664,7 @@ "message": "Terkunci" }, "yourVaultIsLockedV2": { - "message": "Your vault is locked" + "message": "Brankas Anda terkunci" }, "unlocked": { "message": "Tidak terkunci" @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/it/messages.json b/apps/desktop/src/locales/it/messages.json index 42eafea9717..3f70f226665 100644 --- a/apps/desktop/src/locales/it/messages.json +++ b/apps/desktop/src/locales/it/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Seleziona una raccolta" }, - "importTargetHint": { - "message": "Seleziona questa opzione se vuoi che i contenuti del file di importazione siano spostati in una $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Il file contiene elementi non assegnati." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden non convalida i campi di input: assicurati di essere nella finestra e nel campo di testo corretti prima di usare la scorciatoia." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/ja/messages.json b/apps/desktop/src/locales/ja/messages.json index 0ac3473f17f..7fe98d746fc 100644 --- a/apps/desktop/src/locales/ja/messages.json +++ b/apps/desktop/src/locales/ja/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "コレクションを選択" }, - "importTargetHint": { - "message": "インポートしたファイルコンテンツを $DESTINATION$ に移動したい場合は、このオプションを選択してください。", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "割り当てられていないアイテムがファイルに含まれています。" @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/ka/messages.json b/apps/desktop/src/locales/ka/messages.json index 5b21fe1ae07..5ab87271c2e 100644 --- a/apps/desktop/src/locales/ka/messages.json +++ b/apps/desktop/src/locales/ka/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "აირჩიეთ კოლექცია" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/km/messages.json b/apps/desktop/src/locales/km/messages.json index 2e0d5b09f5c..028bc34f77e 100644 --- a/apps/desktop/src/locales/km/messages.json +++ b/apps/desktop/src/locales/km/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/kn/messages.json b/apps/desktop/src/locales/kn/messages.json index ac1cc7b451d..9f8c871285b 100644 --- a/apps/desktop/src/locales/kn/messages.json +++ b/apps/desktop/src/locales/kn/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/ko/messages.json b/apps/desktop/src/locales/ko/messages.json index 4d1f6709e4a..12f853079cb 100644 --- a/apps/desktop/src/locales/ko/messages.json +++ b/apps/desktop/src/locales/ko/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "가져온 파일의 내용을 $DESTINATION$로 이동하려면 이 옵션을 선택하세요.", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/lt/messages.json b/apps/desktop/src/locales/lt/messages.json index 01e92251420..7e2a4e286cc 100644 --- a/apps/desktop/src/locales/lt/messages.json +++ b/apps/desktop/src/locales/lt/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Pasirinkti rinkinį" }, - "importTargetHint": { - "message": "Pasirinkite šį pasirinkimą jei norite jog importuoto failo turinys būtų perkeltas į $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Faile yra nepriskirtų elementų." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/lv/messages.json b/apps/desktop/src/locales/lv/messages.json index 63f03bf5dfd..1f1a7a54834 100644 --- a/apps/desktop/src/locales/lv/messages.json +++ b/apps/desktop/src/locales/lv/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Atlasīt krājumu" }, - "importTargetHint": { - "message": "Šī iespēja jāatlasa, ja ir vēlēšanās ievietotās datnes saturu pārvietot uz $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Datne satur nepiešķirtus vienumus." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden nepārbauda ievades atrašanās vietas, jāpārliecinās, ka atrodies pareizajā logā un laukā, pirms saīsnes izmantošanas." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/me/messages.json b/apps/desktop/src/locales/me/messages.json index fe818806bbf..139066cf9af 100644 --- a/apps/desktop/src/locales/me/messages.json +++ b/apps/desktop/src/locales/me/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/ml/messages.json b/apps/desktop/src/locales/ml/messages.json index ccee87678fb..78dbed9fa6e 100644 --- a/apps/desktop/src/locales/ml/messages.json +++ b/apps/desktop/src/locales/ml/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/mr/messages.json b/apps/desktop/src/locales/mr/messages.json index 2e0d5b09f5c..028bc34f77e 100644 --- a/apps/desktop/src/locales/mr/messages.json +++ b/apps/desktop/src/locales/mr/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/my/messages.json b/apps/desktop/src/locales/my/messages.json index 2c0b5311b29..6432e4f15a1 100644 --- a/apps/desktop/src/locales/my/messages.json +++ b/apps/desktop/src/locales/my/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/nb/messages.json b/apps/desktop/src/locales/nb/messages.json index bcf58d8f243..d778ba216e4 100644 --- a/apps/desktop/src/locales/nb/messages.json +++ b/apps/desktop/src/locales/nb/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Velg en samling" }, - "importTargetHint": { - "message": "Velg dette alternativet hvis du vil flytte den importerte filens innhold til en $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Filen inneholder utildelte elementer." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/ne/messages.json b/apps/desktop/src/locales/ne/messages.json index e08ed353978..6bd3afecd29 100644 --- a/apps/desktop/src/locales/ne/messages.json +++ b/apps/desktop/src/locales/ne/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/nl/messages.json b/apps/desktop/src/locales/nl/messages.json index 1d4d930a67e..93acc51408d 100644 --- a/apps/desktop/src/locales/nl/messages.json +++ b/apps/desktop/src/locales/nl/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Collectie selecteren" }, - "importTargetHint": { - "message": "Kies deze optie als je de geïmporteerde bestandsinhoud wilt verplaatsen naar een $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Kies deze optie als je de geïmporteerde bestandsinhoud naar een collectie wilt verplaatsen" + }, + "importTargetHintFolder": { + "message": "Kies deze optie als je de geïmporteerde bestandsinhoud naar een map wilt verplaatsen" }, "importUnassignedItemsError": { "message": "Bestand bevat niet-toegewezen items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden valideert de invoerlocaties niet, zorg ervoor dat je je in het juiste venster en veld bevindt voordat je de snelkoppeling gebruikt." + }, + "moreBreadcrumbs": { + "message": "Meer broodkruimels", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/nn/messages.json b/apps/desktop/src/locales/nn/messages.json index 5a45d379f9d..3764f9a6c0c 100644 --- a/apps/desktop/src/locales/nn/messages.json +++ b/apps/desktop/src/locales/nn/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/or/messages.json b/apps/desktop/src/locales/or/messages.json index 172e0079201..e8a7531235f 100644 --- a/apps/desktop/src/locales/or/messages.json +++ b/apps/desktop/src/locales/or/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/pl/messages.json b/apps/desktop/src/locales/pl/messages.json index 55093da1245..af707665b86 100644 --- a/apps/desktop/src/locales/pl/messages.json +++ b/apps/desktop/src/locales/pl/messages.json @@ -24,7 +24,7 @@ "message": "Tożsamość" }, "typeNote": { - "message": "Note" + "message": "Notatka" }, "typeSecureNote": { "message": "Notatka" @@ -42,7 +42,7 @@ "message": "Szukaj w sejfie" }, "resetSearch": { - "message": "Reset search" + "message": "Zresetuj wyszukiwanie" }, "addItem": { "message": "Dodaj element" @@ -57,7 +57,7 @@ "message": "Przenieś do organizacji" }, "movedItemToOrg": { - "message": "Element $ITEMNAME$ został przeniesiony do organizacji $ORGNAME$", + "message": "Przeniesiono $ITEMNAME$ do $ORGNAME$", "placeholders": { "itemname": { "content": "$1", @@ -73,13 +73,13 @@ "message": "Witaj ponownie" }, "moveToOrgDesc": { - "message": "Wybierz organizację, do której chcesz przenieść ten element. Ta czynność spowoduje utratę własności elementu i przenosi te uprawnienia do organizacji." + "message": "Wybierz organizację, do której chcesz przenieść element. Przeniesienie spowoduje zmianę własności elementu na organizację." }, "attachments": { "message": "Załączniki" }, "viewItem": { - "message": "Zobacz element" + "message": "Pokaż element" }, "name": { "message": "Nazwa" @@ -138,10 +138,10 @@ "message": "Minimalizuj podczas kopiowania do schowka" }, "minimizeOnCopyToClipboardDesc": { - "message": "Minimalizuj podczas kopiowania danych elementu do schowka." + "message": "Minimalizuj aplikację podczas kopiowania danych elementu do schowka." }, "toggleVisibility": { - "message": "Pokaż / Ukryj" + "message": "Pokaż / ukryj" }, "toggleCollapse": { "message": "Zwiń/rozwiń", @@ -163,7 +163,7 @@ "message": "Kod zabezpieczający" }, "identityName": { - "message": "Nazwa profilu" + "message": "Nowa tożsamość" }, "company": { "message": "Firma" @@ -181,7 +181,7 @@ "message": "Adres e-mail" }, "phone": { - "message": "Telefon" + "message": "Numer telefonu" }, "address": { "message": "Adres" @@ -193,28 +193,28 @@ "message": "Klucz publiczny" }, "sshFingerprint": { - "message": "Odcisk palca" + "message": "Odcisk klucza" }, "sshKeyAlgorithm": { - "message": "Typ klucza" + "message": "Rodzaj klucza" }, "sshKeyAlgorithmED25519": { "message": "ED25519" }, "sshKeyAlgorithmRSA2048": { - "message": "RSA 2048-bitowy" + "message": "RSA 2048-bit" }, "sshKeyAlgorithmRSA3072": { - "message": "RSA 3072-bitowy" + "message": "RSA 3072-bit" }, "sshKeyAlgorithmRSA4096": { - "message": "RSA 4096-bitowy" + "message": "RSA 4096-bit" }, "sshKeyGenerated": { "message": "Nowy klucz SSH został wygenerowany" }, "sshKeyWrongPassword": { - "message": "Wprowadzone hasło jest nieprawidłowe." + "message": "Hasło jest nieprawidłowe." }, "importSshKey": { "message": "Importuj" @@ -223,10 +223,10 @@ "message": "Potwierdź hasło" }, "enterSshKeyPasswordDesc": { - "message": "Wprowadź hasło do klucza SSH." + "message": "Wpisz hasło klucza SSH." }, "enterSshKeyPassword": { - "message": "Wprowadź hasło" + "message": "Wpisz hasło" }, "sshAgentUnlockRequired": { "message": "Odblokuj swój sejf, aby zatwierdzić żądanie klucza SSH." @@ -262,10 +262,10 @@ "message": "Zapamiętaj aż sejf będzie zablokowany" }, "premiumRequired": { - "message": "Konto Premium jest wymagane" + "message": "Konto premium jest wymagane" }, "premiumRequiredDesc": { - "message": "Konto Premium jest wymagane, aby skorzystać z tej funkcji." + "message": "Konto premium jest wymagane, aby skorzystać z tej funkcji." }, "errorOccurred": { "message": "Wystąpił błąd." @@ -277,14 +277,14 @@ "message": "Błąd odszyfrowywania" }, "couldNotDecryptVaultItemsBelow": { - "message": "Bitwarden nie mógł odszyfrować elementów sejfu wymienionych poniżej." + "message": "Bitwarden nie mógł odszyfrować poniższych elementów sejfu." }, "contactCSToAvoidDataLossPart1": { "message": "Skontaktuj się z działem obsługi klienta,", "description": "This is part of a larger sentence. The full sentence will read 'Contact customer success to avoid additional data loss.'" }, "contactCSToAvoidDataLossPart2": { - "message": "aby uniknąć dalszej utraty danych.", + "message": "aby uniknąć dodatkowej utraty danych.", "description": "This is part of a larger sentence. The full sentence will read 'Contact customer success to avoid additional data loss.'" }, "january": { @@ -334,7 +334,7 @@ "message": "Pan" }, "mrs": { - "message": "Mrs" + "message": "Pani (Mrs)" }, "ms": { "message": "Pani" @@ -403,7 +403,7 @@ "message": "Usuń" }, "favorite": { - "message": "Ulubione" + "message": "Dodaj do ulubionych" }, "edit": { "message": "Edytuj" @@ -431,7 +431,7 @@ } }, "websiteAdded": { - "message": "Strona dodana" + "message": "Strona internetowa została dodana" }, "addWebsite": { "message": "Dodaj stronę internetową" @@ -449,10 +449,10 @@ "message": "Edytuj pole" }, "permanentlyDeleteAttachmentConfirmation": { - "message": "Czy na pewno chcesz trwale usunąć ten załącznik?" + "message": "Czy na pewno chcesz usunąć trwale załącznik?" }, "fieldType": { - "message": "Typ pola" + "message": "Rodzaj pola" }, "fieldLabel": { "message": "Etykieta pola" @@ -464,16 +464,16 @@ "message": "Użyj pól tekstowych dla danych takich jak pytania bezpieczeństwa" }, "hiddenHelpText": { - "message": "Użyj ukrytych pól dla danych poufnych, takich jak hasło" + "message": "Użyj ukrytych pól dla danych poufnych takich jak hasło" }, "checkBoxHelpText": { - "message": "Użyj pól wyboru, jeśli chcesz automatycznie wypełnić pole wyboru formularza, np. zapamiętaj e-mail" + "message": "Użyj pól wyboru, gdy chcesz uzupełnić pole wyboru formularza, np. zapamiętaj adres e-mail" }, "linkedHelpText": { "message": "Użyj powiązanego pola, gdy masz problemy z autouzupełnianiem na konkretnej stronie internetowej." }, "linkedLabelHelpText": { - "message": "Wprowadź atrybut z HTML'a: id, name, aria-label lub placeholder." + "message": "Wpisz identyfikator, nazwę, etykietę lub tekst zastępczy pola HTML." }, "folder": { "message": "Folder" @@ -491,7 +491,7 @@ "message": "Tekst" }, "cfTypeHidden": { - "message": "Pole maskowane" + "message": "Ukryty tekst" }, "cfTypeBoolean": { "message": "Wartość logiczna" @@ -529,7 +529,7 @@ "message": "Usuń załącznik" }, "deleteItemConfirmation": { - "message": "Czy na pewno chcesz to usunąć?" + "message": "Czy na pewno chcesz usunąć?" }, "deletedItem": { "message": "Element został przeniesiony do kosza" @@ -566,7 +566,7 @@ "message": "Skopiuj klucz prywatny SSH" }, "copyPassphrase": { - "message": "Skopiuj hasło wyrazowe", + "message": "Kopiuj hasło wyrazowe", "description": "Copy passphrase to clipboard" }, "copyUri": { @@ -576,7 +576,7 @@ "message": "Kopiuj kod weryfikacyjny (TOTP)" }, "copyFieldCipherName": { - "message": "Copy $FIELD$, $CIPHERNAME$", + "message": "Kopiuj $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { @@ -615,7 +615,7 @@ "description": "Card header for password generator include block" }, "uppercaseDescription": { - "message": "Uwzględnij wielkie litery", + "message": "Wielkie litery", "description": "Tooltip for the password generator uppercase character checkbox" }, "uppercaseLabel": { @@ -623,7 +623,7 @@ "description": "Label for the password generator uppercase character checkbox" }, "lowercaseDescription": { - "message": "Uwzględnij małe litery", + "message": "Małe litery", "description": "Full description for the password generator lowercase character checkbox" }, "lowercaseLabel": { @@ -631,7 +631,7 @@ "description": "Label for the password generator lowercase character checkbox" }, "numbersDescription": { - "message": "Uwzględnij cyfry", + "message": "Cyfry", "description": "Full description for the password generator numbers checkbox" }, "numbersLabel": { @@ -639,7 +639,7 @@ "description": "Label for the password generator numbers checkbox" }, "specialCharactersDescription": { - "message": "Uwzględnij znaki specjalne", + "message": "Znaki specjalne", "description": "Full description for the password generator special characters checkbox" }, "numWords": { @@ -674,7 +674,7 @@ "description": "Label for the avoid ambiguous characters checkbox." }, "generatorPolicyInEffect": { - "message": "Wymagania polityki przedsiębiorstwa zostały użyte do ustawienia opcji generatora.", + "message": "Zasady organizacji zostały zastosowane do opcji generatora.", "description": "Indicates that a policy limits the credential generator screen." }, "searchCollection": { @@ -691,13 +691,13 @@ "description": "Search item type" }, "newAttachment": { - "message": "Dodaj załącznik" + "message": "Dodaj nowy załącznik" }, "deletedAttachment": { "message": "Załącznik został usunięty" }, "deleteAttachmentConfirmation": { - "message": "Czy na pewno chcesz usunąć ten załącznik?" + "message": "Czy na pewno chcesz usunąć załącznik?" }, "attachmentSaved": { "message": "Załącznik został zapisany" @@ -712,7 +712,7 @@ "message": "Maksymalny rozmiar pliku to 500 MB." }, "legacyEncryptionUnsupported": { - "message": "Starsze szyfrowanie nie jest już obsługiwane. Skontaktuj się z pomocą techniczną, aby odzyskać swoje konto." + "message": "Starsze szyfrowanie nie jest już obsługiwane. Skontaktuj się z pomocą techniczną, aby odzyskać konto." }, "editedFolder": { "message": "Folder został zapisany" @@ -721,49 +721,49 @@ "message": "Folder został dodany" }, "deleteFolderConfirmation": { - "message": "Czy na pewno chcesz usunąć ten folder?" + "message": "Czy na pewno chcesz usunąć folder?" }, "deletedFolder": { "message": "Folder został usunięty" }, "loginOrCreateNewAccount": { - "message": "Zaloguj się lub utwórz nowe konto, aby uzyskać dostęp do Twojego bezpiecznego sejfu." + "message": "Zaloguj się lub utwórz nowe konto, aby uzyskać dostęp do bezpiecznego sejfu." }, "createAccount": { "message": "Utwórz konto" }, "newToBitwarden": { - "message": "Nowy na Bitwarden?" + "message": "Nowy w Bitwarden?" }, "setAStrongPassword": { "message": "Ustaw silne hasło" }, "finishCreatingYourAccountBySettingAPassword": { - "message": "Ukończ tworzenie konta poprzez ustawienie hasła" + "message": "Zakończ tworzenie konta poprzez ustawienie hasła" }, "logIn": { "message": "Zaloguj się" }, "logInToBitwarden": { - "message": "Zaloguj do Bitwarden" + "message": "Zaloguj się do Bitwarden" }, "enterTheCodeSentToYourEmail": { - "message": "Wpisz kod wysłany na Twój adres e-mail" + "message": "Wpisz kod został wysłany na adres e-mail" }, "enterTheCodeFromYourAuthenticatorApp": { "message": "Wpisz kod z aplikacji uwierzytelniającej" }, "pressYourYubiKeyToAuthenticate": { - "message": "Naciśnij YubiKey aby uwierzytelnić" + "message": "Naciśnij klucz YubiKey, aby uwierzytelnić" }, "logInWithPasskey": { - "message": "Zaloguj się używając klucza dostępu" + "message": "Logowanie kluczem dostępu" }, "loginWithDevice": { "message": "Zaloguj się za pomocą urządzenia" }, "useSingleSignOn": { - "message": "Użyj jednokrotnego logowania" + "message": "Użyj logowania jednokrotnego" }, "submit": { "message": "Wyślij" @@ -784,7 +784,7 @@ "message": "Podpowiedź do hasła głównego (opcjonalnie)" }, "masterPassHintText": { - "message": "Jeśli zapomnisz hasła, podpowiedź hasła może zostać wysłana na Twój adres e-mail. $CURRENT$ z $MAXIMUM$ znaków.", + "message": "Podpowiedź do hasła zostanie wysłana na adres e-mail, jeśli je zapomnisz. Liczba znaków: $CURRENT$ / $MAXIMUM$.", "placeholders": { "current": { "content": "$1", @@ -800,7 +800,7 @@ "message": "Hasło główne" }, "masterPassImportant": { - "message": "Twoje hasło główne nie może zostać odzyskane, jeśli je zapomnisz!" + "message": "Zapomniane hasło główne nie może zostać odzyskane!" }, "confirmMasterPassword": { "message": "Potwierdź hasło główne" @@ -809,7 +809,7 @@ "message": "Podpowiedź do hasła głównego" }, "passwordStrengthScore": { - "message": "Siła hasła: $SCORE$", + "message": "Siła hasła wynosi $SCORE$", "placeholders": { "score": { "content": "$1", @@ -821,7 +821,7 @@ "message": "Dołącz do organizacji" }, "joinOrganizationName": { - "message": "Dołącz do $ORGANIZATIONNAME$", + "message": "Dołącz do organizacji $ORGANIZATIONNAME$", "placeholders": { "organizationName": { "content": "$1", @@ -830,7 +830,7 @@ } }, "finishJoiningThisOrganizationBySettingAMasterPassword": { - "message": "Zakończ dołączanie do tej organizacji przez ustawienie hasła głównego." + "message": "Zakończ dołączanie do organizacji poprzez ustawienie hasła głównego." }, "settings": { "message": "Ustawienia" @@ -839,13 +839,13 @@ "message": "Adres e-mail konta" }, "requestHint": { - "message": "Poproś o podpowiedź" + "message": "Uzyskaj podpowiedź" }, "requestPasswordHint": { - "message": "Poproś o podpowiedź do hasła" + "message": "Uzyskaj podpowiedź do hasła" }, "enterYourAccountEmailAddressAndYourPasswordHintWillBeSentToYou": { - "message": "Wprowadź adres e-mail swojego konta, a podpowiedź hasła zostanie wysłana do Ciebie" + "message": "Wpisz adres e-mail konta. Podpowiedź do hasła zostanie wysłana na adres e-mail" }, "getMasterPasswordHint": { "message": "Uzyskaj podpowiedź do hasła głównego" @@ -863,7 +863,7 @@ "message": "Wymagane jest ponowne wpisanie hasła głównego." }, "masterPasswordMinlength": { - "message": "Hasło główne musi zawierać co najmniej $VALUE$ znaki(-ów).", + "message": "Hasło główne musi składać się z co najmniej $VALUE$ znaków.", "description": "The Master Password must be at least a specific number of characters long.", "placeholders": { "value": { @@ -873,7 +873,7 @@ } }, "youSuccessfullyLoggedIn": { - "message": "Zalogowałeś się pomyślnie" + "message": "Zalogowano" }, "youMayCloseThisWindow": { "message": "Możesz zamknąć to okno" @@ -885,13 +885,13 @@ "message": "Konto zostało utworzone! Teraz możesz się zalogować." }, "newAccountCreated2": { - "message": "Twoje nowe konto zostało utworzone!" + "message": "Nowe konto zostało utworzone!" }, "youHaveBeenLoggedIn": { - "message": "Zalogowano Cię!" + "message": "Zalogowano!" }, "masterPassSent": { - "message": "Wysłaliśmy Tobie wiadomość e-mail z podpowiedzią do hasła głównego." + "message": "Wysłaliśmy wiadomość z podpowiedzią do hasła głównego." }, "unexpectedError": { "message": "Wystąpił nieoczekiwany błąd." @@ -900,7 +900,7 @@ "message": "Informacje o elemencie" }, "noItemsInList": { - "message": "Brak elementów." + "message": "Brak elementów do wyświetlenia." }, "sendVerificationCode": { "message": "Wyślij kod weryfikacyjny na adres e-mail" @@ -933,7 +933,7 @@ "message": "Kontynuuj" }, "verificationCodeEmailSent": { - "message": "Kod weryfikacyjny został wysłany na adres $EMAIL$.", + "message": "Wiadomość weryfikacyjna została wysłana na adres $EMAIL$.", "placeholders": { "email": { "content": "$1", @@ -952,10 +952,10 @@ "message": "Użyj kodu odzyskiwania" }, "insertU2f": { - "message": "Włóż klucz bezpieczeństwa do portu USB komputera. Jeśli klucz posiada przycisk, dotknij go." + "message": "Włóż klucz bezpieczeństwa do portu USB urządzenia. Jeśli klucz ma przycisk, dotknij go." }, "recoveryCodeDesc": { - "message": "Utraciłeś dostęp do wszystkich swoich mechanizmów dwustopniowego logowania? Użyj kodów odzyskiwania, aby wyłączyć dwustopniowe logowanie na Twoim koncie." + "message": "Nie masz dostępu do logowania dwustopniowego? Użyj kodu odzyskiwania, aby je wyłączyć." }, "recoveryCodeTitle": { "message": "Kod odzyskiwania" @@ -964,28 +964,28 @@ "message": "Aplikacja uwierzytelniająca" }, "authenticatorAppDescV2": { - "message": "Wprowadź kod wygenerowany przez aplikację uwierzytelniającą, jak Bitwarden Authenticator.", + "message": "Wpisz kod wygenerowany przez aplikację uwierzytelniającą, taką jak Bitwarden Authenticator.", "description": "'Bitwarden Authenticator' is a product name and should not be translated." }, "yubiKeyTitleV2": { "message": "Klucz bezpieczeństwa Yubico OTP" }, "yubiKeyDesc": { - "message": "Użyj YubiKey jako metody dostępu do konta. Działa z YubiKey 4, 4 Nano, 4C i urządzeniami NEO." + "message": "Użyj klucza YubiKey, aby uzyskać dostęp do konta. Działa z urządzeniami YubiKey 4, 4 Nano, 4C i NEO." }, "duoDescV2": { - "message": "Wprowadź kod wygenerowany przez Duo Security.", + "message": "Wpisz kod wygenerowany przez Duo Security.", "description": "'Duo Security' and 'Duo Mobile' are product names and should not be translated." }, "duoOrganizationDesc": { - "message": "Weryfikacja dostępu do Twojej organizacji z użyciem Duo Security poprzez aplikację Duo Mobile, SMS, połączenie telefoniczne lub klucz bezpieczeństwa U2F.", + "message": "Weryfikacja Duo Security za pomocą aplikacji Duo Mobile, wiadomości SMS, połączenia telefonicznego lub klucza bezpieczeństwa U2F.", "description": "'Duo Security' and 'Duo Mobile' are product names and should not be translated." }, "verifyYourIdentity": { - "message": "Potwierdź swoją tożsamość" + "message": "Zweryfikuj tożsamość" }, "weDontRecognizeThisDevice": { - "message": "Nie rozpoznajemy tego urządzenia. Wpisz kod wysłany na Twój e-mail, aby zweryfikować tożsamość." + "message": "Nie rozpoznajemy tego urządzenia. Wpisz kod wysłany na adres e-mail, aby zweryfikować swoją tożsamość." }, "continueLoggingIn": { "message": "Kontynuuj logowanie" @@ -994,7 +994,7 @@ "message": "FIDO2 WebAuthn" }, "webAuthnDesc": { - "message": "Użyj dowolnego klucza bezpieczeństwa WebAuthn, aby uzyskać dostęp do swojego konta." + "message": "Użyj dowolnego klucza bezpieczeństwa WebAuthn, aby uzyskać dostęp do konta." }, "emailTitle": { "message": "Adres e-mail" @@ -1006,7 +1006,7 @@ "message": "Logowanie jest niedostępne" }, "noTwoStepProviders": { - "message": "Konto posiada włączoną opcję logowania dwustopniowego, jednak to urządzenie nie wspiera żadnego ze skonfigurowanych mechanizmów autoryzacji dwustopniowej." + "message": "Konto jest zabezpieczone logowaniem dwustopniowym, ale żadna ze skonfigurowanych metod nie jest obsługiwana na tym urządzeniu." }, "noTwoStepProviders2": { "message": "Dodaj dodatkowe mechanizmy, które są lepiej obsługiwane przez różne urządzenia (np. aplikacje uwierzytelniające)." @@ -1021,7 +1021,7 @@ "message": "Samodzielnie hostowane środowisko" }, "selfHostedBaseUrlHint": { - "message": "Określ bazowy adres URL swojej instalacji Bitwarden. Przykład: https://bitwarden.company.com" + "message": "Określ podstawowy adres URL instalacji Bitwarden. Przykład: https://bitwarden.mojafirma.pl" }, "selfHostedCustomEnvHeader": { "message": "Dla zaawansowanych konfiguracji możesz określić podstawowy adres URL niezależnie dla każdej usługi." @@ -1036,13 +1036,13 @@ "message": "Adres URL serwera" }, "authenticationTimeout": { - "message": "Limit czasu uwierzytelniania" + "message": "Przekroczono limit czasu uwierzytelniania" }, "authenticationSessionTimedOut": { - "message": "Upłynął limit czasu uwierzytelniania. Uruchom ponownie proces logowania." + "message": "Upłynął limit czasu uwierzytelniania. Zaloguj się ponownie." }, "selfHostBaseUrl": { - "message": "URL samodzielnie hostowanego serwera", + "message": "Adres URL hostowanego serwera", "description": "Label for field requesting a self-hosted integration service URL" }, "apiUrl": { @@ -1088,19 +1088,19 @@ "message": "Wylogowano" }, "loggedOutDesc": { - "message": "Zostałeś wylogowany z konta." + "message": "Wylogowano z konta." }, "loginExpired": { "message": "Twoja sesja wygasła." }, "restartRegistration": { - "message": "Zrestartuj rejestrację" + "message": "Rozpocznij rejestrację od początku" }, "expiredLink": { "message": "Link wygasł" }, "pleaseRestartRegistrationOrTryLoggingIn": { - "message": "Zrestartuj rejestrację lub spróbuj się zalogować." + "message": "Rozpocznij rejestrację od początku lub spróbuj się zalogować." }, "youMayAlreadyHaveAnAccount": { "message": "Możesz mieć już konto" @@ -1118,7 +1118,7 @@ "message": "Nowy element" }, "view": { - "message": "Widok" + "message": "Pokaż" }, "account": { "message": "Konto" @@ -1157,17 +1157,17 @@ "message": "Zmień hasło główne" }, "continueToWebApp": { - "message": "Kontynuować do aplikacji internetowej?" + "message": "Przejść do aplikacji internetowej?" }, "changeMasterPasswordOnWebConfirmation": { - "message": "Możesz zmienić swoje hasło główne w aplikacji internetowej Bitwarden." + "message": "Możesz zmienić hasło główne w aplikacji internetowej Bitwarden." }, "fingerprintPhrase": { "message": "Unikalny identyfikator konta", "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": "Unikalny identyfikator Twojego konta", + "message": "Twój unikalny identyfikator konta", "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." }, "goToWebVault": { @@ -1189,16 +1189,16 @@ "message": "Sejf jest zablokowany. Zweryfikuj swoją tożsamość, aby kontynuować." }, "yourAccountIsLocked": { - "message": "Twoje konto jest zablokowane" + "message": "Konto jest zablokowane" }, "or": { "message": "lub" }, "unlockWithBiometrics": { - "message": "Odblokuj za pomocą danych biometrycznych" + "message": "Odblokuj biometrią" }, "unlockWithMasterPassword": { - "message": "Odblokuj przy użyciu hasła głównego" + "message": "Odblokuj hasłem głównym" }, "unlock": { "message": "Odblokuj" @@ -1220,22 +1220,22 @@ "message": "Hasło główne jest nieprawidłowe" }, "twoStepLoginConfirmation": { - "message": "Logowanie dwustopniowe sprawia, że konto jest bardziej bezpieczne poprzez wymuszenie potwierdzenia logowania z innego urządzenia, takiego jak z klucza bezpieczeństwa, aplikacji uwierzytelniającej, wiadomości SMS, telefonu lub adresu e-mail. Logowanie dwustopniowe możesz włączyć w sejfie internetowym bitwarden.com. Czy chcesz przejść do tej strony?" + "message": "Logowanie dwustopniowe zwiększa bezpieczeństwo konta, wymagając weryfikacji logowania za pomocą innego urządzenia, takiego jak klucz bezpieczeństwa, aplikacja uwierzytelniająca, wiadomość SMS, połączenie telefoniczne lub wiadomość e-mail. Logowanie dwustopniowe możesz skonfigurować w sejfie internetowym bitwarden.com. Czy chcesz przejść do strony?" }, "twoStepLogin": { "message": "Logowanie dwustopniowe" }, "vaultTimeoutHeader": { - "message": "Vault timeout" + "message": "Blokowanie sejfu" }, "vaultTimeout": { "message": "Blokowanie sejfu" }, "vaultTimeout1": { - "message": "Limit czasu" + "message": "Blokada aplikacji" }, "vaultTimeoutAction1": { - "message": "Timeout action" + "message": "Sposób blokady" }, "vaultTimeoutDesc": { "message": "Wybierz, kiedy sejf zostanie zablokowany i wykonaj następującą akcję." @@ -1277,13 +1277,13 @@ "message": "Podczas bezczynności systemu" }, "onSleep": { - "message": "Po uśpieniu komputera" + "message": "Podczas uśpienia systemu" }, "onLocked": { - "message": "Po zablokowaniu komputera" + "message": "Po zablokowaniu urządzenia" }, "onRestart": { - "message": "Po restarcie aplikacji" + "message": "Po uruchomieniu komputera" }, "never": { "message": "Nigdy" @@ -1300,10 +1300,10 @@ "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "enableFavicon": { - "message": "Pokaż ikony witryn" + "message": "Pokaż ikony stron internetowych" }, "faviconDesc": { - "message": "Pokaż rozpoznawalny obraz obok danych logowania." + "message": "Pokaż rozpoznawalną ikonę obok danych logowania." }, "enableMinToTray": { "message": "Minimalizuj do zasobnika systemowego" @@ -1336,7 +1336,7 @@ "message": "Zawsze pokazuj ikonę w zasobniku systemowym." }, "startToTray": { - "message": "Uruchom zminimalizowany do zasobnika systemowego" + "message": "Uruchom w zasobniku systemowym" }, "startToTrayDesc": { "message": "Przy pierwszym uruchomieniu aplikacji, pokaż tylko ikonę w zasobniku systemowym." @@ -1369,7 +1369,7 @@ "message": "Język" }, "languageDesc": { - "message": "Zmień język aplikacji. Uruchomienie ponowne jest wymagane." + "message": "Zmień język aplikacji. Wymagane jest ponowne uruchomienie aplikacji." }, "theme": { "message": "Motyw" @@ -1426,7 +1426,7 @@ "message": "Później" }, "noUpdatesAvailable": { - "message": "Aktualizacje nie są obecnie dostępne. Używasz najnowszej wersji." + "message": "Brak dostępnych aktualizacji. Korzystasz z najnowszej wersji." }, "updateError": { "message": "Błąd aktualizacji" @@ -1442,41 +1442,41 @@ "description": "Copy credit card number" }, "copyEmail": { - "message": "Skopiuj e-mail" + "message": "Kopiuj adres e-mail" }, "copySecurityCode": { "message": "Kopiuj kod zabezpieczający", "description": "Copy credit card security code (CVV)" }, "cardNumber": { - "message": "card number" + "message": "numer karty" }, "premiumMembership": { - "message": "Konto Premium" + "message": "Konto premium" }, "premiumManage": { - "message": "Zarządzaj kontem Premium" + "message": "Zarządzaj kontem premium" }, "premiumManageAlert": { - "message": "Kontem Premium możesz zarządzać na stronie sejfu bitwarden.com. Czy chcesz otworzyć tę stronę?" + "message": "Zarządzaj kontem premium na stronie internetowej bitwarden.com. Czy chcesz otworzyć stronę?" }, "premiumRefresh": { - "message": "Przedłuż konto Premium" + "message": "Odśwież konto premium" }, "premiumNotCurrentMember": { - "message": "Nie posiadasz obecnie konta Premium." + "message": "Nie masz konta premium." }, "premiumSignUpAndGet": { - "message": "Zarejestruj konto Premium, aby otrzymać:" + "message": "Ulepsz konto do wersji premium, aby otrzymać:" }, "premiumSignUpStorage": { "message": "1 GB miejsca na zaszyfrowane załączniki." }, "premiumSignUpTwoStepOptions": { - "message": "Własnościowe opcje logowania dwuetapowego, takie jak YubiKey i Duo." + "message": "Specjalne opcje logowania dwustopniowego, takie jak YubiKey i Duo." }, "premiumSignUpReports": { - "message": "Raporty bezpieczeństwa haseł, stanu konta i raporty wycieków danych, aby Twoje dane były bezpieczne." + "message": "Raporty bezpieczeństwa haseł, konta i wycieków danych, aby Twoje dane były bezpieczne." }, "premiumSignUpTotp": { "message": "Generator kodów weryfikacyjnych TOTP (2FA) dla danych logowania w sejfie." @@ -1488,19 +1488,19 @@ "message": "Wszystkie przyszłe funkcje premium. Więcej już wkrótce!" }, "premiumPurchase": { - "message": "Kup konto Premium" + "message": "Kup konto premium" }, "premiumPurchaseAlertV2": { - "message": "Możesz kupić Premium w ustawieniach konta w aplikacji internetowej Bitwarden." + "message": "Możesz kupić konto premium w aplikacji internetowej Bitwarden." }, "premiumCurrentMember": { - "message": "Posiadasz konto Premium!" + "message": "Masz konto premium!" }, "premiumCurrentMemberThanks": { "message": "Dziękujemy za wspieranie Bitwarden." }, "premiumPrice": { - "message": "Wszystko to jedynie za $PRICE$ /rok!", + "message": "Tylko $PRICE$ / rok!", "placeholders": { "price": { "content": "$1", @@ -1521,14 +1521,14 @@ "message": "Wyczyść historię generatora" }, "cleargGeneratorHistoryDescription": { - "message": "Jeśli zatwierdzisz, wszystkie wygenerowane hasła zostaną usunięte z historii generatora. Czy chcesz kontynuować mimo to?" + "message": "Wszystkie wpisy zostaną trwale usunięte z historii generatora. Czy na pewno chcesz kontynuować?" }, "clear": { "message": "Wyczyść", "description": "To clear something out. example: To clear browser history." }, "noPasswordsInList": { - "message": "Brak haseł." + "message": "Brak haseł do wyświetlenia." }, "clearHistory": { "message": "Wyczyść historię" @@ -1537,7 +1537,7 @@ "message": "Brak zawartości do pokazania" }, "nothingGeneratedRecently": { - "message": "Nic nie zostało wygenerowane przez ciebie w ostatnim czasie" + "message": "Nic nie zostało wygenerowane w ostatnim czasie" }, "undo": { "message": "Cofnij" @@ -1566,13 +1566,13 @@ "message": "Zresetuj powiększenie" }, "toggleFullScreen": { - "message": "Włącz/wyłącz pełny ekran" + "message": "Pełny ekran" }, "reload": { "message": "Odśwież" }, "toggleDevTools": { - "message": "Włącz/wyłącz narzędzia dla deweloperów" + "message": "Narzędzia dla deweloperów" }, "minimize": { "message": "Minimalizuj", @@ -1598,7 +1598,7 @@ "message": "Ukryj inne" }, "showAll": { - "message": "Pokaż wszystkie" + "message": "Pokaż wszystko" }, "quitBitwarden": { "message": "Zamknij Bitwarden" @@ -1614,13 +1614,13 @@ } }, "copySuccessful": { - "message": "Kopiowanie zakończone sukcesem" + "message": "Skopiowano" }, "errorRefreshingAccessToken": { - "message": "Błąd podczas odświeżania tokenu" + "message": "Wystąpił błąd podczas odświeżania tokena" }, "errorRefreshingAccessTokenDesc": { - "message": "Nie znaleziono tokenu odświeżającego ani kluczy API. Spróbuj wylogować się i zalogować ponownie." + "message": "Nie znaleziono tokena odświeżania ani kluczy API. Zaloguj się ponownie." }, "help": { "message": "Pomoc" @@ -1684,14 +1684,14 @@ "message": "Domyślny" }, "exit": { - "message": "Wyjście" + "message": "Wyjdź" }, "showHide": { "message": "Pokaż / Ukryj", "description": "Text for a button that toggles the visibility of the window. Shows the window when it is hidden or hides the window if it is currently open." }, "hideToTray": { - "message": "Ukryj w zasobniku systemowym" + "message": "Ukryj do zasobnika systemowego" }, "alwaysOnTop": { "message": "Zawsze na wierzchu", @@ -1719,50 +1719,50 @@ "message": "Format pliku" }, "fileEncryptedExportWarningDesc": { - "message": "Plik będzie chroniony hasłem, które będzie wymagane do odszyfrowania pliku." + "message": "Plik zostanie zaszyfrowany hasłem." }, "filePassword": { - "message": "Hasło do pliku" + "message": "Hasło pliku" }, "exportPasswordDescription": { "message": "Hasło będzie używane do eksportowania i importowania pliku" }, "accountRestrictedOptionDescription": { - "message": "Użyj klucza szyfrowania konta, pochodzącego z nazwy użytkownika konta i hasła głównego, aby zaszyfrować eksport i ograniczyć import tylko do bieżącego konta Bitwarden." + "message": "Użyj klucza szyfrowania konta, pochodzącego z nazwy użytkownika konta i hasła głównego, aby zaszyfrować eksport i ograniczyć import tylko do obecnego konta Bitwarden." }, "passwordProtected": { - "message": "Chroniona hasłem" + "message": "Zabezpieczone hasłem" }, "passwordProtectedOptionDescription": { - "message": "Ustaw hasło dla pliku, aby zaszyfrować eksport i zaimportować je na dowolne konto Bitwarden przy użyciu hasła do odszyfrowania." + "message": "Ustaw hasło pliku, aby zaszyfrować eksport i zaimportować je na dowolne konto Bitwarden przy użyciu hasła do odszyfrowania." }, "exportTypeHeading": { "message": "Rodzaj eksportu" }, "accountRestricted": { - "message": "Konto ograniczone" + "message": "Konto zostało ograniczone" }, "restrictCardTypeImport": { - "message": "Cannot import card item types" + "message": "Nie można zaimportować karty" }, "restrictCardTypeImportDesc": { - "message": "A policy set by 1 or more organizations prevents you from importing cards to your vaults." + "message": "Zasada ustawiona przez co najmniej 1 organizację uniemożliwia importowanie kart do sejfów." }, "filePasswordAndConfirmFilePasswordDoNotMatch": { - "message": "“Hasło pliku” i “Potwierdź hasło pliku“ nie pasują do siebie." + "message": "Hasła pliku nie pasują do siebie." }, "done": { "message": "Gotowe" }, "warning": { - "message": "UWAGA", + "message": "OSTRZEŻENIE", "description": "WARNING (should stay in capitalized letters if the language permits)" }, "confirmVaultExport": { "message": "Potwierdź eksportowanie sejfu" }, "exportWarningDesc": { - "message": "Plik zawiera dane sejfu w niezaszyfrowanym formacie. Nie powinieneś go przechowywać, ani przesyłać poprzez niezabezpieczone kanały (takie jak poczta e-mail). Skasuj go natychmiast po użyciu." + "message": "Plik zawiera dane sejfu w niezaszyfrowanym formacie. Nie należy go przechowywać ani przesyłać poprzez niezabezpieczone kanały (takie jak poczta e-mail). Usuń go natychmiast po użyciu." }, "encExportKeyWarningDesc": { "message": "Dane eksportu zostaną zaszyfrowane za pomocą klucza szyfrowania konta. Jeśli kiedykolwiek zmienisz ten klucz, wyeksportuj dane ponownie, ponieważ nie będziesz w stanie odszyfrować tego pliku." @@ -1780,7 +1780,7 @@ "message": "Właściciel" }, "whoOwnsThisItem": { - "message": "Kto jest właścicielem tego elementu?" + "message": "Kto jest właścicielem elementu?" }, "strong": { "message": "Silne", @@ -1795,10 +1795,10 @@ "description": "ex. A weak password. Scale: Weak -> Good -> Strong" }, "weakMasterPassword": { - "message": "Słabe hasło główne" + "message": "Hasło główne jest słabe" }, "weakMasterPasswordDesc": { - "message": "Wybrane przez Ciebie hasło główne jest słabe. Powinieneś użyć silniejszego hasła (lub frazy), aby właściwie chronić swoje konto Bitwarden. Czy na pewno chcesz użyć tego hasła głównego?" + "message": "Użyj silniejszego hasła, aby odpowiednio chronić konto Bitwarden. Czy na pewno chcesz użyć tego hasła głównego?" }, "pin": { "message": "Kod PIN", @@ -1808,7 +1808,7 @@ "message": "Odblokuj kodem PIN" }, "setYourPinCode": { - "message": "Ustaw kod PIN do odblokowywania aplikacji Bitwarden. Ustawienia odblokowywania kodem PIN zostaną zresetowane po wylogowaniu." + "message": "Ustaw kod PIN do odblokowania aplikacji Bitwarden. Ustawienia kodu PIN zostaną zresetowane po wylogowaniu." }, "pinRequired": { "message": "Kod PIN jest wymagany." @@ -1817,10 +1817,10 @@ "message": "Kod PIN jest nieprawidłowy." }, "tooManyInvalidPinEntryAttemptsLoggingOut": { - "message": "Zbyt wiele nieprawidłowych prób wpisywania PIN. Wylogowywanie." + "message": "Zbyt wiele nieprawidłowych prób wpisywania kodu PIN. Trwa wylogowanie" }, "unlockWithWindowsHello": { - "message": "Odblokuj za pomocą Windows Hello" + "message": "Odblokuj przez Windows Hello" }, "unlockWithPolkit": { "message": "Odblokuj za pomocą uwierzytelniania systemowego" @@ -1829,7 +1829,7 @@ "message": "Zweryfikuj dla Bitwarden." }, "unlockWithTouchId": { - "message": "Odblokuj za pomocą Touch ID" + "message": "Odblokuj przez Touch ID" }, "additionalTouchIdSettings": { "message": "Dodatkowe ustawienia Touch ID" @@ -1853,16 +1853,16 @@ "message": "Usuń konto" }, "deleteAccountDesc": { - "message": "Kontynuuj poniżej, aby usunąć swoje konto i wszystkie dane sejfu." + "message": "Kontynuuj poniżej, aby usunąć konto i wszystkie dane sejfu." }, "deleteAccountWarning": { - "message": "Usunięcie konta jest nieodwracalne. Ta czynność nie może zostać cofnięta." + "message": "Usunięcie konta jest nieodwracalne." }, "cannotDeleteAccount": { "message": "Nie można usunąć konta" }, "cannotDeleteAccountDesc": { - "message": "Tej akcji nie można zakończyć, ponieważ Twoje konto jest zarządzane przez organizację. Skontaktuj się z administratorem organizacji, aby uzyskać dodatkowe informacje." + "message": "Nie możesz usunąć konta, ponieważ jest ono własnością organizacji. Skontaktuj się z administratorem organizacji, aby uzyskać dodatkowe informacje." }, "accountDeleted": { "message": "Konto zostało usunięte" @@ -1880,19 +1880,19 @@ "message": "Zawsze pokazuj ikonę na pasku menu." }, "hideToMenuBar": { - "message": "Schowaj do paska menu" + "message": "Ukryj do paska menu" }, "selectOneCollection": { "message": "Musisz wybrać co najmniej jedną kolekcję." }, "premiumUpdated": { - "message": "Konto Premium zostało zaktualizowane." + "message": "Konto premium zostało zaktualizowane." }, "restore": { "message": "Przywróć" }, "premiumManageAlertAppStore": { - "message": "Możesz zarządzać subskrypcją w sklepie App Store. Czy chcesz przejść do sklepu App Store?" + "message": "Zarządzaj subskrypcją w App Store. Czy chcesz przejść do App Store?" }, "legal": { "message": "Informacje prawne", @@ -1926,7 +1926,7 @@ "message": "Zaloguj się ponownie, aby uzyskać dostęp do sejfu." }, "unlockMethodNeededToChangeTimeoutActionDesc": { - "message": "Ustaw metodę odblokowania, aby zmienić czas blokowania sejfu." + "message": "Ustaw metodę odblokowania, aby zmienić sposób blokowania sejfu." }, "lock": { "message": "Zablokuj", @@ -1943,7 +1943,7 @@ "message": "Usuń trwale element" }, "permanentlyDeleteItemConfirmation": { - "message": "Czy na pewno chcesz usunąć trwale ten element?" + "message": "Czy na pewno chcesz usunąć trwale element?" }, "permanentlyDeletedItem": { "message": "Element został trwale usunięty" @@ -1958,7 +1958,7 @@ "message": "Po wylogowaniu się z sejfu musisz ponownie zalogować się, aby uzyskać do niego dostęp. Czy na pewno chcesz użyć tego ustawienia?" }, "vaultTimeoutLogOutConfirmationTitle": { - "message": "Potwierdź sposób blokowania sejfu" + "message": "Potwierdź sposób blokady" }, "enterpriseSingleSignOn": { "message": "Logowanie jednokrotne" @@ -1967,7 +1967,7 @@ "message": "Ustaw hasło główne" }, "orgPermissionsUpdatedMustSetPassword": { - "message": "Uprawnienia w Twojej organizacji zostały zaktualizowane, musisz teraz ustawić hasło główne.", + "message": "Uprawnienia organizacji zostały zaktualizowane. Ustaw hasło główne.", "description": "Used as a card title description on the set password page to explain why the user is there" }, "orgRequiresYouToSetPassword": { @@ -1996,19 +1996,19 @@ } }, "learnMoreAboutAuthenticators": { - "message": "Dowiedz się więcej o uwierzytelniaczach" + "message": "Dowiedz się więcej o uwierzytelnianiu" }, "copyTOTP": { "message": "Kopiuj klucz uwierzytelniający (TOTP)" }, "totpHelperTitle": { - "message": "Spraw, aby dwuetapowa weryfikacja była bezproblemowa" + "message": "Bezproblemowa weryfikacja dwustopniowa" }, "totpHelper": { - "message": "Bitwarden może przechowywać i wypełniać kody weryfikacyjne. Skopiuj i wklej klucz do tego pola." + "message": "Bitwarden może przechowywać i uzupełniać kody weryfikacyjne. Skopiuj i wklej klucz do tego pola." }, "totpHelperWithCapture": { - "message": "Bitwarden może przechowywać i wypełniać kody weryfikacyjne. Wybierz ikonę aparatu, aby zrobić zrzut ekranu z kodem QR lub skopiuj i wklej klucz do tego pola." + "message": "Bitwarden może przechowywać i uzupełniać kody weryfikacyjne. Wybierz ikonę aparatu, aby zrobić zrzut ekranu z kodem QR lub skopiuj i wklej klucz do tego pola." }, "premium": { "message": "Premium", @@ -2018,7 +2018,7 @@ "message": "Darmowe organizacje nie mogą używać załączników" }, "singleFieldNeedsAttention": { - "message": "1 pole wymaga Twojej uwagi." + "message": "1 pole wymaga uwagi." }, "multipleFieldsNeedAttention": { "message": "Pola wymagające Twojej uwagi: $COUNT$.", @@ -2033,14 +2033,14 @@ "message": "Karta wygasła" }, "cardExpiredMessage": { - "message": "Jeśli ją wznowiłeś, zaktualizuj informacje o karcie" + "message": "Jeśli karta została odnowiona, zaktualizuj informacje o niej" }, "verificationRequired": { - "message": "Wymagana weryfikacja", + "message": "Weryfikacja jest wymagana", "description": "Default title for the user verification dialog." }, "currentMasterPass": { - "message": "Aktualne hasło główne" + "message": "Obecne hasło główne" }, "newMasterPass": { "message": "Nowe hasło główne" @@ -2091,16 +2091,16 @@ "message": "Nowe hasło główne nie spełnia wymaganych zasad." }, "receiveMarketingEmailsV2": { - "message": "Uzyskaj poradę, ogłoszenia i możliwości badawcze od Bitwarden w swojej skrzynce odbiorczej." + "message": "Otrzymuj porady, ogłoszenia i możliwości badawcze od Bitwarden na swoją skrzynkę odbiorczą." }, "unsubscribe": { "message": "Anuluj subskrypcję" }, "atAnyTime": { - "message": "w każdej chwili." + "message": "w dowolnym momencie." }, "byContinuingYouAgreeToThe": { - "message": "Kontynuując, zgadzasz się na" + "message": "Kontynuując, akceptujesz" }, "and": { "message": "i" @@ -2121,7 +2121,7 @@ "message": "Włącz połączenie z przeglądarką DuckDuckGo" }, "enableDuckDuckGoBrowserIntegrationDesc": { - "message": "Korzystaj z sejfu Bitwarden podczas przeglądania za pomocą przeglądarki DuckDuckGo." + "message": "Korzystaj z sejfu Bitwarden w przeglądarce DuckDuckGo." }, "browserIntegrationUnsupportedTitle": { "message": "Połączenie z przeglądarką nie jest obsługiwane" @@ -2154,13 +2154,13 @@ "message": "Domyślnie to ustawienie jest włączone. Wyłącz tylko wtedy, gdy wystąpią problemy graficzne. Wymagane jest ponowne uruchomienie." }, "approve": { - "message": "Zatwierdź" + "message": "Potwierdź" }, "verifyBrowserTitle": { "message": "Zweryfikuj połączenie z przeglądarką" }, "verifyBrowserDesc": { - "message": "Upewnij się, że wyświetlony identyfikator jest identyczny z pokazanym w rozszerzeniu przeglądarki." + "message": "Upewnij się, że identyfikator jest zgodny." }, "verifyNativeMessagingConnectionTitle": { "message": "Aplikacja $APPID$ chce połączyć się z Bitwarden", @@ -2172,16 +2172,16 @@ } }, "verifyNativeMessagingConnectionDesc": { - "message": "Czy chcesz zatwierdzić to żądanie?" + "message": "Czy chcesz potwierdzić żądanie?" }, "verifyNativeMessagingConnectionWarning": { - "message": "Jeśli to żądanie nie zostało zainicjowane przez Ciebie, nie zatwierdzaj go." + "message": "Jeśli żądanie nie zostało zainicjowane przez Ciebie, nie potwierdzaj go." }, "biometricsNotEnabledTitle": { - "message": "Dane biometryczne są wyłączone" + "message": "Biometria jest wyłączona" }, "biometricsNotEnabledDesc": { - "message": "Aby włączyć dane biometryczne w przeglądarce, musisz włączyć tę samą funkcję w ustawianiach aplikacji." + "message": "Aby skonfigurować dane biometryczne w przeglądarce, włącz najpierw biometrię w aplikacji desktopowej." }, "biometricsManualSetupTitle": { "message": "Automatyczna konfiguracja niedostępna" @@ -2193,7 +2193,7 @@ "message": "Ze względu na zasadę przedsiębiorstwa, nie możesz zapisywać elementów w osobistym sejfie. Zmień właściciela elementu na organizację i wybierz jedną z dostępnych kolekcji." }, "yourNewPasswordCannotBeTheSameAsYourCurrentPassword": { - "message": "Twoje nowe hasło nie może być takie samo jak Twoje aktualne hasło." + "message": "Nowe hasło nie może być takie samo jak obecne." }, "hintEqualsPassword": { "message": "Podpowiedź do hasła nie może być taka sama jak hasło." @@ -2202,13 +2202,13 @@ "message": "Zasada organizacji ma wpływ na opcję własności elementów." }, "personalOwnershipPolicyInEffectImports": { - "message": "Polityka organizacji zablokowała importowanie elementów do Twojego sejfu." + "message": "Zasada organizacji zablokowała importowanie elementów do osobistego sejfu." }, "personalDetails": { "message": "Dane osobowe" }, "identification": { - "message": "Tożsamość" + "message": "Identyfikacja" }, "contactInfo": { "message": "Informacje kontaktowe" @@ -2232,7 +2232,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "myVault": { - "message": "Mój sejf" + "message": "Sejf" }, "text": { "message": "Tekst" @@ -2248,7 +2248,7 @@ "message": "Data wygaśnięcia" }, "expirationDateDesc": { - "message": "Jeśli funkcja jest włączona, dostęp do wysyłki wygaśnie po określonym czasie.", + "message": "Wysyłka zostanie trwale usunięta w określonym czasie.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "maxAccessCount": { @@ -2256,7 +2256,7 @@ "description": "This text will be displayed after a Send has been accessed the maximum amount of times." }, "maxAccessCountDesc": { - "message": "Jeśli funkcja jest włączona, po osiągnięciu maksymalnej liczby dostępów, użytkownicy nie będą mieli dostępu do tej wysyłki.", + "message": "Po osiągnięciu maksymalnej liczby dostępów użytkownicy nie będą mieli dostępu do wysyłki.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "currentAccessCount": { @@ -2328,10 +2328,10 @@ "message": "1 dzień" }, "custom": { - "message": "Niestandardowe" + "message": "Niestandardowa" }, "deleteSendConfirmation": { - "message": "Czy na pewno chcesz usunąć tę wysyłkę?", + "message": "Czy na pewno chcesz usunąć wysyłkę?", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "copySendLinkToClipboard": { @@ -2339,14 +2339,14 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "copySendLinkOnSave": { - "message": "Po zapisaniu wysyłki, skopiuj link do schowka." + "message": "Skopiuj link do schowka po zapisaniu wysyłki." }, "sendDisabled": { "message": "Wysyłka została usunięta", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendDisabledWarning": { - "message": "Ze względu na zasadę przedsiębiorstwa, tylko Ty możesz usunąć obecną wysyłkę.", + "message": "Ze względu na zasadę organizacji, tylko Ty możesz usunąć obecną wysyłkę.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "copyLink": { @@ -2380,7 +2380,7 @@ "message": "Odczytaj klucz bezpieczeństwa" }, "awaitingSecurityKeyInteraction": { - "message": "Oczekiwanie na interakcję z kluczem bezpieczeństwa..." + "message": "Oczekiwanie na klucz bezpieczeństwa..." }, "hideEmail": { "message": "Ukryj mój adres e-mail przed odbiorcami." @@ -2392,7 +2392,7 @@ "message": "Weryfikacja adresu e-mail jest wymagana" }, "emailVerifiedV2": { - "message": "E-mail zweryfikowany" + "message": "Adres e-mail został zweryfikowany" }, "emailVerificationRequiredDesc": { "message": "Musisz zweryfikować adres e-mail, aby używać tej funkcji." @@ -2404,10 +2404,10 @@ "message": "Potwierdź hasło główne" }, "passwordConfirmationDesc": { - "message": "Ta operacja jest chroniona. Aby kontynuować, wpisz ponownie hasło główne." + "message": "Operacja jest chroniona. Aby kontynuować, wpisz ponownie hasło główne." }, "masterPasswordSuccessfullySet": { - "message": "Master password successfully set" + "message": "Hasło główne zostało ustawione" }, "updatedMasterPassword": { "message": "Hasło główne zostało zaktualizowane" @@ -2416,19 +2416,19 @@ "message": "Zaktualizuj hasło główne" }, "updateMasterPasswordWarning": { - "message": "Hasło główne zostało zmienione przez administratora Twojej organizacji. Musisz je zaktualizować, aby uzyskać dostęp do sejfu. Ta czynność spowoduje wylogowanie z bieżącej sesji, przez co konieczne będzie ponowne zalogowanie się. Aktywne sesje na innych urządzeniach mogą pozostać aktywne przez maksymalnie godzinę." + "message": "Hasło główne zostało zmienione przez administratora Twojej organizacji. Aby uzyskać dostęp do sejfu, zaktualizuj hasło główne. Kontynuowanie spowoduje wylogowanie z obecnej sesji i konieczność ponownego zalogowania się. Aktywne sesje na innych urządzeniach mogą pozostać aktywne przez maksymalnie godzinę." }, "updateWeakMasterPasswordWarning": { - "message": "Twoje hasło główne nie spełnia jednej lub kilku zasad organizacji. Aby uzyskać dostęp do sejfu, musisz teraz zaktualizować swoje hasło główne. Kontynuacja wyloguje Cię z bieżącej sesji, wymagając zalogowania się ponownie. Aktywne sesje na innych urządzeniach mogą pozostać aktywne przez maksymalnie jedną godzinę." + "message": "Hasło główne nie spełnia co najmniej jednej zasady organizacji. Aby uzyskać dostęp do sejfu, zaktualizuj hasło główne. Kontynuowanie spowoduje wylogowanie z obecnej sesji i konieczność ponownego zalogowania się. Aktywne sesje na innych urządzeniach mogą pozostać aktywne przez maksymalnie godzinę." }, "changePasswordWarning": { - "message": "After changing your password, you will need to log in with your new password. Active sessions on other devices will be logged out within one hour." + "message": "Po zmianie hasła zaloguj się za pomocą nowego hasła. Aktywne sesje na innych urządzeniach zostaną wylogowane w ciągu jednej godziny." }, "accountRecoveryUpdateMasterPasswordSubtitle": { - "message": "Change your master password to complete account recovery." + "message": "Zmień hasło główne, aby zakończyć odzyskiwanie konta." }, "updateMasterPasswordSubtitle": { - "message": "Your master password does not meet this organization’s requirements. Change your master password to continue." + "message": "Hasło główne nie spełnia wymagań organizacji. Zmień hasło główne, aby kontynuować." }, "tdeDisabledMasterPasswordRequired": { "message": "Twoja organizacja wyłączyła szyfrowanie zaufanego urządzenia. Ustaw hasło główne, aby uzyskać dostęp do sejfu." @@ -2440,16 +2440,16 @@ "message": "Weryfikacja dla tej akcji jest wymagana. Ustaw kod PIN, aby kontynuować." }, "setPin": { - "message": "Ustaw PIN" + "message": "Ustaw kod PIN" }, "verifyWithBiometrics": { - "message": "Weryfikuj za pomocą biometrii" + "message": "Zweryfikuj biometrią" }, "awaitingConfirmation": { "message": "Oczekiwanie na potwierdzenie" }, "couldNotCompleteBiometrics": { - "message": "Nie można ukończyć z użyciem biometrii." + "message": "Logowanie biometrią nie powiodło się" }, "needADifferentMethod": { "message": "Potrzebujesz innej metody?" @@ -2458,16 +2458,16 @@ "message": "Użyj hasła głównego" }, "usePin": { - "message": "Użyj PINu" + "message": "Użyj kodu PIN" }, "useBiometrics": { "message": "Użyj biometrii" }, "enterVerificationCodeSentToEmail": { - "message": "Wpisz kod weryfikacyjny, który został wysłany na adres e-mail." + "message": "Wpisz kod weryfikacyjny wysłany na adres e-mail." }, "resendCode": { - "message": "Wysłać kod ponownie" + "message": "Wyślij ponownie kod" }, "hours": { "message": "Godziny" @@ -2476,7 +2476,7 @@ "message": "Minuty" }, "vaultTimeoutPolicyInEffect1": { - "message": "$HOURS$ godzin(y) i $MINUTES$ minut(y) maksymalnie.", + "message": "Maksymalnie $HOURS$ godz. i $MINUTES$ min.", "placeholders": { "hours": { "content": "$1", @@ -2506,7 +2506,7 @@ } }, "vaultTimeoutActionPolicyInEffect": { - "message": "Zasady organizacji ustawiły czas blokowania sejfu na $ACTION$.", + "message": "Zasady organizacji wymuszają sposób blokowania sejfu na $ACTION$.", "placeholders": { "action": { "content": "$1", @@ -2515,13 +2515,13 @@ } }, "vaultTimeoutTooLarge": { - "message": "Czas blokowania sejfu przekracza limit określony przez organizację." + "message": "Czas blokowania aplikacji przekracza limit określony przez organizację." }, "vaultTimeoutPolicyAffectingOptions": { - "message": "Enterprise policy requirements have been applied to your timeout options" + "message": "Zasady organizacji zostały zastosowane do opcji blokowania sejfu" }, "vaultTimeoutPolicyInEffect": { - "message": "Your organization policies have set your maximum allowed vault timeout to $HOURS$ hour(s) and $MINUTES$ minute(s).", + "message": "Zasady organizacji mają wpływ na czas blokowania sejfu. Maksymalny dozwolony czas wynosi $HOURS$ godz. i $MINUTES$ min.", "placeholders": { "hours": { "content": "$1", @@ -2534,7 +2534,7 @@ } }, "vaultTimeoutPolicyMaximumError": { - "message": "Timeout exceeds the restriction set by your organization: $HOURS$ hour(s) and $MINUTES$ minute(s) maximum", + "message": "Czas blokowania sejfu przekracza zasady organizacji. Maksymalny dozwolony czas wynosi $HOURS$ godz. i $MINUTES$ min.", "placeholders": { "hours": { "content": "$1", @@ -2553,7 +2553,7 @@ "message": "Automatyczne rejestrowanie użytkowników" }, "resetPasswordAutoEnrollInviteWarning": { - "message": "Ta organizacja posługuje się zasadą, która automatycznie rejestruje użytkowników do resetowania hasła. Rejestracja umożliwia administratorom organizacji zmianę Twojego hasła głównego." + "message": "Zasada organizacji umożliwia administratorom organizacji zmianę Twojego hasła głównego." }, "vaultExportDisabled": { "message": "Eksportowanie sejfu zostało wyłączone" @@ -2571,25 +2571,25 @@ "message": "Hasło główne zostało usunięte" }, "removeMasterPasswordForOrganizationUserKeyConnector": { - "message": "Hasło główne nie jest już wymagane dla członków następującej organizacji. Proszę potwierdzić poniższą domenę u administratora organizacji." + "message": "Hasło główne nie jest już wymagane dla członków następującej organizacji. Potwierdź poniższą domenę z administratorem organizacji." }, "organizationName": { "message": "Nazwa organizacji" }, "keyConnectorDomain": { - "message": "Domena Key Connector'a" + "message": "Domena Key Connector" }, "leaveOrganization": { "message": "Opuść organizację" }, "leaveOrganizationConfirmation": { - "message": "Czy na pewno chcesz opuścić tę organizację?" + "message": "Czy na pewno chcesz opuścić organizację?" }, "leftOrganization": { - "message": "Nie należysz już do tej organizacji." + "message": "Opuszczono organizację." }, "ssoKeyConnectorError": { - "message": "Błąd serwera Key Connector: upewnij się, że serwer Key Connector jest dostępny i działa poprawnie." + "message": "Wystąpił błąd serwera Key Connector. Upewnij się, że serwer jest dostępny i działa poprawnie." }, "lockAllVaults": { "message": "Zablokuj wszystkie sejfy" @@ -2604,7 +2604,7 @@ "message": "Ustawienia aplikacji (wszystkie konta)" }, "accountSwitcherLimitReached": { - "message": "Limit konta został osiągnięty. Wyloguj się z konta, aby dodać inne." + "message": "Limit kont został osiągnięty. Wyloguj się z konta, aby dodać inne." }, "settingsTitle": { "message": "Ustawienia aplikacji (konto $EMAIL$)", @@ -2631,7 +2631,7 @@ "message": "Eksportowanie osobistego sejfu" }, "exportingIndividualVaultDescription": { - "message": "Z sejfu zostaną wyeksportowane tylko elementy powiązane z $EMAIL$. Elementy z sejfu organizacji nie będą uwzględnione. Tylko informacje o elemencie zostaną wyeksportowane i nie będą zawierać powiązanych załączników.", + "message": "Wyeksportowane zostaną tylko osobiste elementy konta $EMAIL$. Elementy organizacji nie zostaną uwzględnione. Wyeksportowane zostaną tylko informacje o elementach sejfu i nie będą one zawierać powiązanych załączników.", "placeholders": { "email": { "content": "$1", @@ -2640,7 +2640,7 @@ } }, "exportingIndividualVaultWithAttachmentsDescription": { - "message": "Tylko poszczególne elementy sejfu łącznie z załącznikami powiązanymi z $EMAIL$ zostaną wyeksportowane. Elementy sejfu organizacji nie będą dołączone", + "message": "Tylko osobisty sejf $EMAIL$ zostanie wyeksportowany. Elementy organizacji nie zostaną uwzględnione.", "placeholders": { "email": { "content": "$1", @@ -2652,7 +2652,7 @@ "message": "Eksportowanie sejfu organizacji" }, "exportingOrganizationVaultDesc": { - "message": "Tylko sejf organizacji powiązany z $ORGANIZATION$ zostanie wyeksportowany. Pozycje w poszczególnych sejfach lub innych organizacji nie będą uwzględnione.", + "message": "Tylko sejf organizacji $ORGANIZATION$ zostanie wyeksportowany. Elementy innych sejfów nie zostaną uwzględnione.", "placeholders": { "organization": { "content": "$1", @@ -2661,13 +2661,13 @@ } }, "locked": { - "message": "Zablokowany" + "message": "Zablokowane" }, "yourVaultIsLockedV2": { - "message": "Twój sejf jest zablokowany" + "message": "Sejf jest zablokowany" }, "unlocked": { - "message": "Odblokowany" + "message": "Odblokowane" }, "generator": { "message": "Generator", @@ -2686,10 +2686,10 @@ "message": "Wygeneruj nazwę użytkownika" }, "generateEmail": { - "message": "Wygeneruj e-mail" + "message": "Wygeneruj adres e-mail" }, "usernameGenerator": { - "message": "Generator nazw użytkownika" + "message": "Generator nazwy użytkownika" }, "generatePassword": { "message": "Wygeneruj hasło" @@ -2707,7 +2707,7 @@ "message": "Nazwa użytkownika została wygenerowana" }, "emailGenerated": { - "message": "E-mail został wygenerowany" + "message": "Adres e-mail został wygenerowany" }, "spinboxBoundariesHint": { "message": "Wartość musi być pomiędzy $MIN$ a $MAX$.", @@ -2724,7 +2724,7 @@ } }, "passwordLengthRecommendationHint": { - "message": " Użyj $RECOMMENDED$ znaków lub więcej, aby wygenerować silne hasło.", + "message": "Użyj co najmniej $RECOMMENDED$ znaków, aby utworzyć silne hasło.", "description": "Appended to `spinboxBoundariesHint` to recommend a length to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -2734,7 +2734,7 @@ } }, "passphraseNumWordsRecommendationHint": { - "message": " Użyj $RECOMMENDED$ słów lub więcej, aby wygenerować silne hasło.", + "message": "Użyj co najmniej $RECOMMENDED$ słów, aby wygenerować silne hasło wyrazowe.", "description": "Appended to `spinboxBoundariesHint` to recommend a number of words to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -2772,13 +2772,13 @@ "message": "Użyj tej nazwy użytkownika" }, "random": { - "message": "Losowa" + "message": "Losowe" }, "randomWord": { "message": "Losowe słowo" }, "websiteName": { - "message": "Nazwa strony" + "message": "Nazwa strony internetowej" }, "service": { "message": "Usługa" @@ -2796,10 +2796,10 @@ "message": "Alias przekierowania" }, "forwardedEmailDesc": { - "message": "Wygeneruj alias adresu e-mail z zewnętrznej usługi przekazywania." + "message": "Wygeneruj alias za pomocą zewnętrznej usługi." }, "forwarderDomainName": { - "message": "Domena e-mail", + "message": "Domena adresu e-mail", "description": "Labels the domain name email forwarder service option" }, "forwarderDomainNameHint": { @@ -2821,7 +2821,7 @@ } }, "forwarderGeneratedBy": { - "message": "Wygenerowane przez Bitwarden.", + "message": "Wygenerowano przez Bitwarden.", "description": "Displayed with the address on the forwarding service's configuration screen." }, "forwarderGeneratedByWithWebsite": { @@ -2835,7 +2835,7 @@ } }, "forwaderInvalidToken": { - "message": "Nieprawidłowy token API dla $SERVICENAME$", + "message": "Token API $SERVICENAME$ jest nieprawidłowy", "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", "placeholders": { "servicename": { @@ -2845,7 +2845,7 @@ } }, "forwaderInvalidTokenWithMessage": { - "message": "Nieprawidłowy token API dla $SERVICENAME$, błąd: $ERRORMESSAGE$", + "message": "Token API $SERVICENAME$ jest nieprawidłowy: $ERRORMESSAGE$", "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", "placeholders": { "servicename": { @@ -2859,7 +2859,7 @@ } }, "forwaderInvalidOperation": { - "message": "$SERVICENAME$ odrzucił Twoje żądanie. Skontaktuj się z dostawcą usług w celu uzyskania pomocy.", + "message": "$SERVICENAME$ odrzucił żądanie. Skontaktuj się z dostawcą usługi w celu uzyskania pomocy.", "description": "Displayed when the user is forbidden from using the API by the forwarding service.", "placeholders": { "servicename": { @@ -2869,7 +2869,7 @@ } }, "forwaderInvalidOperationWithMessage": { - "message": "$SERVICENAME$ odrzucił Twoje żądanie: $ERRORMESSAGE$", + "message": "$SERVICENAME$ odrzucił żądanie: $ERRORMESSAGE$", "description": "Displayed when the user is forbidden from using the API by the forwarding service with an error message.", "placeholders": { "servicename": { @@ -2883,7 +2883,7 @@ } }, "forwarderNoAccountId": { - "message": "Nie można uzyskać ID maskowanego konta e-mail dla $SERVICENAME$.", + "message": "Nie można uzyskać identyfikatora konta e-mail $SERVICENAME$.", "description": "Displayed when the forwarding service fails to return an account ID.", "placeholders": { "servicename": { @@ -2893,7 +2893,7 @@ } }, "forwarderNoDomain": { - "message": "Nieprawidłowa domena $SERVICENAME$.", + "message": "Domena $SERVICENAME$ jest nieprawidłowa.", "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", "placeholders": { "servicename": { @@ -2903,7 +2903,7 @@ } }, "forwarderNoUrl": { - "message": "Nieprawidłowy adres URL $SERVICENAME$.", + "message": "Adres URL $SERVICENAME$ jest nieprawidłowy.", "description": "Displayed when the url of the forwarding service wasn't supplied.", "placeholders": { "servicename": { @@ -2913,7 +2913,7 @@ } }, "forwarderUnknownError": { - "message": "Wystąpił nieznany błąd w $SERVICENAME$.", + "message": "Wystąpił nieznany błąd $SERVICENAME$.", "description": "Displayed when the forwarding service failed due to an unknown error.", "placeholders": { "servicename": { @@ -2923,7 +2923,7 @@ } }, "forwarderUnknownForwarder": { - "message": "Nieznana usługa przekierowania: '$SERVICENAME$'.", + "message": "Usługa „$SERVICENAME$” jest nieznana.", "description": "Displayed when the forwarding service is not supported.", "placeholders": { "servicename": { @@ -2943,7 +2943,7 @@ "message": "Klucz API" }, "premiumSubcriptionRequired": { - "message": "Wymagana jest subskrypcja Premium" + "message": "Wymagana jest subskrypcja premium" }, "organizationIsDisabled": { "message": "Organizacja została zawieszona" @@ -2952,7 +2952,7 @@ "message": "Nie można uzyskać dostępu do elementów w zawieszonych organizacjach. Skontaktuj się z właścicielem organizacji, aby uzyskać pomoc." }, "neverLockWarning": { - "message": "Czy na pewno chcesz użyć opcji „Nigdy”? Ustawienie opcji blokady na „Nigdy” spowoduje zapisanie klucza szyfrowania sejfu na urządzeniu. Jeśli korzystasz z tej opcji, upewnij się, że urządzenie jest odpowiednio chronione." + "message": "Czy na pewno chcesz użyć opcji „Nigdy”? Ustawienie blokady na „Nigdy” spowoduje przechowywanie klucza szyfrowania sejfu na urządzeniu. Upewnij się, że urządzenie jest odpowiednio chronione." }, "vault": { "message": "Sejf" @@ -2967,7 +2967,7 @@ "message": "Nowy użytkownik?" }, "loggingInTo": { - "message": "Logowanie do $DOMAIN$", + "message": "Serwer: $DOMAIN$", "placeholders": { "domain": { "content": "$1", @@ -2982,13 +2982,13 @@ "message": "Logowanie rozpoczęte" }, "logInRequestSent": { - "message": "Żądanie wysłane" + "message": "Prośba została wysłana" }, "notificationSentDevice": { "message": "Powiadomienie zostało wysłane na urządzenie." }, "aNotificationWasSentToYourDevice": { - "message": "Powiadomienie zostało wysłane na twoje urządzenie" + "message": "Powiadomienie zostało wysłane na urządzenie" }, "notificationSentDevicePart1": { "message": "Odblokuj Bitwarden na swoim urządzeniu lub w" @@ -2997,19 +2997,19 @@ "message": "aplikacji internetowej" }, "notificationSentDevicePart2": { - "message": "Upewnij się, że fraza odcisku palca zgadza się z tą poniżej, zanim zatwierdzisz." + "message": "Upewnij się, że identyfikator jest zgodny." }, "needAnotherOptionV1": { - "message": "Potrzebujesz innego sposobu?" + "message": "Potrzebujesz innej opcji?" }, "fingerprintMatchInfo": { "message": "Upewnij się, że sejf jest odblokowany, a unikalny identyfikator konta pasuje do innego urządzenia." }, "fingerprintPhraseHeader": { - "message": "Unikalny identyfikator konta" + "message": "Twój unikalny identyfikator konta" }, "youWillBeNotifiedOnceTheRequestIsApproved": { - "message": "Zostaniesz powiadomiony po zatwierdzeniu prośby" + "message": "Zostaniesz powiadomiony po potwierdzeniu" }, "needAnotherOption": { "message": "Logowanie za pomocą urządzenia musi być włączone w ustawieniach aplikacji Bitwarden. Potrzebujesz innej opcji?" @@ -3024,7 +3024,7 @@ "message": "Wyślij ponownie powiadomienie" }, "toggleCharacterCount": { - "message": "Pokaż / Ukryj licznik znaków", + "message": "Pokaż / ukryj licznik znaków", "description": "'Character count' describes a feature that displays a number next to each character of the password." }, "accessAttemptBy": { @@ -3037,7 +3037,7 @@ } }, "loginRequestApprovedForEmailOnDevice": { - "message": "Login request approved for $EMAIL$ on $DEVICE$", + "message": "Potwierdzono logowanie $EMAIL$ ($DEVICE$)", "placeholders": { "email": { "content": "$1", @@ -3050,21 +3050,21 @@ } }, "youDeniedLoginAttemptFromAnotherDevice": { - "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + "message": "Odrzucono próbę logowania z innego urządzenia. Zaloguj się ponownie z tego urządzenia." }, "webApp": { - "message": "Web app" + "message": "Aplikacja internetowa" }, "mobile": { - "message": "Mobile", + "message": "Telefon", "description": "Mobile app" }, "extension": { - "message": "Extension", + "message": "Rozszerzenie", "description": "Browser extension/addon" }, "desktop": { - "message": "Desktop", + "message": "Komputer", "description": "Desktop app" }, "cli": { @@ -3075,19 +3075,19 @@ "description": "Software Development Kit" }, "server": { - "message": "Server" + "message": "Serwer" }, "loginRequest": { - "message": "Login request" + "message": "Prośba logowania" }, "deviceType": { - "message": "Typ urządenia" + "message": "Rodzaj urządzenia" }, "ipAddress": { "message": "Adres IP" }, "time": { - "message": "Godzina" + "message": "Czas" }, "confirmAccess": { "message": "Potwierdź dostęp" @@ -3099,7 +3099,7 @@ "message": "Teraz" }, "requestedXMinutesAgo": { - "message": "Poproszono $MINUTES$ minut temu", + "message": "$MINUTES$ min temu", "placeholders": { "minutes": { "content": "$1", @@ -3111,7 +3111,7 @@ "message": "Prośba logowania wygasła." }, "thisRequestIsNoLongerValid": { - "message": "Ta prośba nie jest już ważna." + "message": "Prośba nie jest już ważna." }, "confirmAccessAttempt": { "message": "Potwierdź próbę dostępu dla $EMAIL$", @@ -3135,34 +3135,34 @@ "message": "Sprawdź swoją pocztę e-mail" }, "followTheLinkInTheEmailSentTo": { - "message": "Kliknij łącze w wiadomości e-mail wysłanej do" + "message": "Kliknij link w wiadomości wysłanej na adres" }, "andContinueCreatingYourAccount": { "message": "i kontynuuj tworzenie konta." }, "noEmail": { - "message": "Brak wiadomości e-mail?" + "message": "Brak wiadomości?" }, "goBack": { "message": "Wróć" }, "toEditYourEmailAddress": { - "message": "aby edytować swój adres e-mail." + "message": ", aby edytować adres e-mail." }, "exposedMasterPassword": { - "message": "Ujawnione hasło główne" + "message": "Hasło główne zostało ujawnione" }, "exposedMasterPasswordDesc": { - "message": "Hasło ujawnione w wyniku naruszenia ochrony danych. Użyj unikalnego hasła, aby chronić swoje konto. Czy na pewno chcesz użyć ujawnionego hasła?" + "message": "Hasło zostało ujawnione w wycieku danych. Użyj unikalnego hasła, aby chronić konto. Czy na pewno chcesz użyć ujawnionego hasła?" }, "weakAndExposedMasterPassword": { - "message": "Słabe i ujawnione hasło główne" + "message": "Hasło główne jest słabe i ujawnione" }, "weakAndBreachedMasterPasswordDesc": { - "message": "Słabe hasło ujawnione w wyniku naruszenia ochrony danych. Użyj silnego i unikalnego hasła, aby chronić swoje konto. Czy na pewno chcesz użyć tego hasła?" + "message": "Hasło jest słabe i zostało ujawnione w wycieku danych. Użyj mocnego i unikalnego hasła, aby chronić konto. Czy na pewno chcesz użyć tego hasła?" }, "checkForBreaches": { - "message": "Sprawdź znane naruszenia ochrony danych tego hasła" + "message": "Sprawdź hasło w znanych wyciekach danych" }, "loggedInExclamation": { "message": "Zalogowano!" @@ -3180,7 +3180,7 @@ "message": "Zostałeś wylogowany, ponieważ Twój token odświeżania nie mógł zostać pobrany. Zaloguj się ponownie, aby rozwiązać ten problem." }, "masterPasswordHint": { - "message": "Twoje hasło główne nie może zostać odzyskane, jeśli je zapomnisz!" + "message": "Zapomniane hasło główne nie może zostać odzyskane!" }, "characterMinimum": { "message": "Minimum znaków: $LENGTH$", @@ -3198,34 +3198,34 @@ "message": "Aktualizacja ustawień zalecanych" }, "rememberThisDeviceToMakeFutureLoginsSeamless": { - "message": "Zapamiętaj to urządzenie, aby przyszłe logowania były bezproblemowe" + "message": "Zapamiętaj urządzenie, aby przyszłe logowania były bezproblemowe" }, "deviceApprovalRequired": { - "message": "Wymagane zatwierdzenie urządzenia. Wybierz opcję zatwierdzenia poniżej:" + "message": "Potwierdzenie urządzenia jest wymagane. Wybierz opcję:" }, "deviceApprovalRequiredV2": { - "message": "Wymagane zatwierdzenie urządzenia" + "message": "Potwierdzenie urządzenia jest wymagane" }, "selectAnApprovalOptionBelow": { - "message": "Wybierz opcję zatwierdzenia poniżej" + "message": "Wybierz opcję potwierdzenia" }, "rememberThisDevice": { - "message": "Zapamiętaj to urządzenie" + "message": "Zapamiętaj urządzenie" }, "uncheckIfPublicDevice": { - "message": "Odznacz jeśli używasz publicznego urządzenia" + "message": "Wyłącz na obcych urządzeniach" }, "approveFromYourOtherDevice": { - "message": "Zatwierdź z twojego innego urządzenia" + "message": "Potwierdź za pomocą innego urządzenia" }, "requestAdminApproval": { - "message": "Poproś administratora o zatwierdzenie" + "message": "Poproś administratora o potwierdzenie" }, "unableToCompleteLogin": { - "message": "Unable to complete login" + "message": "Logowanie nie powiodło się" }, "loginOnTrustedDeviceOrAskAdminToAssignPassword": { - "message": "You need to log in on a trusted device or ask your administrator to assign you a password." + "message": "Musisz zalogować się na zaufanym urządzeniu lub poprosić administratora o przypisanie hasła." }, "region": { "message": "Region" @@ -3241,22 +3241,22 @@ "message": "samodzielnie hostowany" }, "accessDenied": { - "message": "Odmowa dostępu. Nie masz uprawnień do przeglądania tej strony." + "message": "Odmowa dostępu. Nie masz uprawnień do wyświetlenia tej strony." }, "accountSuccessfullyCreated": { - "message": "Konto pomyślnie utworzone!" + "message": "Konto zostało utworzone!" }, "adminApprovalRequested": { - "message": "Poproszono administratora o zatwierdzenie" + "message": "Poproszono administratora o potwierdzenie" }, "adminApprovalRequestSentToAdmins": { - "message": "Twoja prośba została wysłana do Twojego administratora." + "message": "Prośba została wysłana do administratora." }, "troubleLoggingIn": { - "message": "Problem z zalogowaniem?" + "message": "Problem z logowaniem?" }, "loginApproved": { - "message": "Logowanie zatwierdzone" + "message": "Logowanie zostało potwierdzone" }, "userEmailMissing": { "message": "Brak adresu e-mail użytkownika" @@ -3265,7 +3265,7 @@ "message": "Nie znaleziono aktywnego adresu e-mail. Trwa wylogowanie." }, "deviceTrusted": { - "message": "Zaufano urządzeniu" + "message": "Urządzenie zostało zaufane" }, "trustOrganization": { "message": "Zaufaj organizacji" @@ -3280,13 +3280,13 @@ "message": "Organizacja nie jest zaufana" }, "emergencyAccessTrustWarning": { - "message": "Dla bezpieczeństwa Twojego konta potwierdź tylko, jeśli przyznano temu użytkownikowi dostęp awaryjny i jego odcisk palca pasuje do tego, co widnieje na jego koncie" + "message": "Potwierdź tylko wtedy, gdy chcesz przyznać użytkownikowi dostęp awaryjny i jego unikalny identyfikator konta jest prawidłowy." }, "orgTrustWarning": { - "message": "Dla zapewnienia bezpieczeństwa konta kontynuuj tylko wtedy, gdy jesteś członkiem tej organizacji, włączono odzyskiwanie konta, a odcisk palca wyświetlany poniżej pasuje do odcisku palca organizacji." + "message": "Kontynuuj tylko wtedy, gdy jesteś członkiem organizacji, masz włączone odzyskiwanie konta, a unikalny identyfikator pasuje do organizacji." }, "orgTrustWarning1": { - "message": "Polityka korporacyjna tej organizacji umożliwia zapisanie Cię do programu odzyskiwania kont. Rejestracja umożliwi administratorom organizacji zmianę Twojego hasła. Możesz kontynuować tylko wtedy, gdy znasz tę organizację, a odcisk palca pokazany poniżej pasuje do odcisku palca tej organizacji." + "message": "Zasada organizacji pozwala administratorom organizacji na zmianę Twojego hasła. Kontynuuj tylko wtedy, gdy rozpoznajesz organizację, a unikalny identyfikator pasuje do organizacji." }, "trustUser": { "message": "Zaufaj użytkownikowi" @@ -3301,7 +3301,7 @@ "message": "Szukaj" }, "inputMinLength": { - "message": "Dane wejściowe muszą zawierać co najmniej $COUNT$ znaki(-ów).", + "message": "Dane wejściowe muszą składać się z co najmniej $COUNT$ znaków.", "placeholders": { "count": { "content": "$1", @@ -3346,17 +3346,17 @@ } }, "multipleInputEmails": { - "message": "Co najmniej 1 e-mail jest nieprawidłowy" + "message": "Co najmniej 1 adres e-mail jest nieprawidłowy" }, "inputTrimValidator": { "message": "Tekst nie może zawierać tylko spacji.", "description": "Notification to inform the user that a form's input can't contain only whitespace." }, "inputEmail": { - "message": "Dane wejściowe nie są adresem e-mail." + "message": "To nie jest adres e-mail." }, "fieldsNeedAttention": { - "message": "Pola powyżej wymagające Twojej uwagi: $COUNT$.", + "message": "Pola wymagające uwagi: $COUNT$.", "placeholders": { "count": { "content": "$1", @@ -3374,7 +3374,7 @@ "message": "Pobieranie opcji..." }, "multiSelectNotFound": { - "message": "Nie znaleziono żadnych pozycji" + "message": "Nie znaleziono elementów" }, "multiSelectClearAll": { "message": "Wyczyść wszystko" @@ -3395,16 +3395,16 @@ "message": "Przełącz nawigację boczną" }, "skipToContent": { - "message": "Przejdź do treści" + "message": "Przejdź do zawartości" }, "typePasskey": { - "message": "Passkey" + "message": "Klucz dostępu" }, "passkeyNotCopied": { - "message": "Passkey nie zostanie skopiowany" + "message": "Klucz dostępu nie zostanie skopiowany" }, "passkeyNotCopiedAlert": { - "message": "Passkey nie zostanie skopiowane do sklonowanego elementu. Czy chcesz kontynuować klonowanie tego elementu?" + "message": "Klucz dostępu nie zostanie skopiowany do sklonowanego elementu. Czy chcesz kontynuować klonowanie elementu?" }, "aliasDomain": { "message": "Domena aliasu" @@ -3414,10 +3414,10 @@ "description": "Used for the desktop menu item and the header of the import dialog" }, "importError": { - "message": "Błąd importu" + "message": "Błąd importowania" }, "importErrorDesc": { - "message": "Wystąpił problem z danymi, które chcesz zaimportować. Rozwiąż poniższe problemy w Twoim pliku i spróbuj ponownie." + "message": "Wystąpił problem podczas importowania danych. Usuń poniższe błędy w pliku źródłowym i spróbuj ponownie." }, "resolveTheErrorsBelowAndTryAgain": { "message": "Rozwiąż poniższe błędy i spróbuj ponownie." @@ -3426,7 +3426,7 @@ "message": "Opis" }, "importSuccess": { - "message": "Importowanie danych zakończone sukcesem" + "message": "Dane zostały zaimportowane" }, "importSuccessNumberOfItems": { "message": "Zaimportowano elementów: $AMOUNT$.", @@ -3450,16 +3450,16 @@ } }, "duoHealthCheckResultsInNullAuthUrlError": { - "message": "Wystąpił błąd podczas połączenia z usługą Duo. Aby uzyskać pomoc, użyj innej metody dwustopniowego logowania lub skontaktuj się z Duo." + "message": "Wystąpił błąd podczas połączenia z usługą Duo. Użyj innej metody logowania dwustopniowego lub skontaktuj się z Duo w celu uzyskania pomocy." }, "duoRequiredByOrgForAccount": { - "message": "Dwustopniowe logowanie Duo jest wymagane dla Twojego konta." + "message": "Konto wymaga logowania dwustopniowego Duo." }, "duoTwoFactorRequiredPageSubtitle": { "message": "Logowanie dwustopniowe Duo jest wymagane dla twojego konta. Wykonaj poniższe kroki, by dokończyć logowanie" }, "followTheStepsBelowToFinishLoggingIn": { - "message": "Wykonaj poniższe kroki, by dokończyć logowanie" + "message": "Wykonaj poniższe kroki, by zakończyć logowanie." }, "followTheStepsBelowToFinishLoggingInWithSecurityKey": { "message": "Wykonaj poniższe kroki, aby zakończyć logowanie za pomocą klucza bezpieczeństwa." @@ -3468,7 +3468,7 @@ "message": "Uruchom Duo w przeglądarce" }, "importFormatError": { - "message": "Dane nie są poprawnie sformatowane. Sprawdź importowany plik i spróbuj ponownie." + "message": "Dane nie są prawidłowo sformatowane. Sprawdź plik i spróbuj ponownie." }, "importNothingError": { "message": "Nic nie zostało zaimportowane." @@ -3477,7 +3477,7 @@ "message": "Wystąpił błąd podczas odszyfrowywania pliku. Klucz szyfrowania nie pasuje do klucza użytego podczas eksportowania danych." }, "invalidFilePassword": { - "message": "Hasło do pliku jest nieprawidłowe. Użyj hasła które podano przy tworzeniu pliku eksportu." + "message": "Hasło pliku jest nieprawidłowe. Użyj prawidłowego hasła." }, "destination": { "message": "Miejsce docelowe" @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Wybierz kolekcję" }, - "importTargetHint": { - "message": "Wybierz tę opcję, jeśli chcesz, aby zawartość zaimportowanego pliku została przeniesiona do $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Wybierz tę opcję, jeśli chcesz przenieść dane do kolekcji" + }, + "importTargetHintFolder": { + "message": "Wybierz tę opcję, jeśli chcesz przenieść dane do folderu" }, "importUnassignedItemsError": { "message": "Plik zawiera nieprzypisane elementy." @@ -3533,7 +3529,7 @@ "message": "Potwierdź importowanie sejfu" }, "confirmVaultImportDesc": { - "message": "Plik jest chroniony hasłem. Wprowadź hasło pliku, aby zaimportować dane." + "message": "Plik jest chroniony hasłem. Wpisz hasło pliku, aby zaimportować dane." }, "confirmFilePassword": { "message": "Potwierdź hasło pliku" @@ -3542,43 +3538,43 @@ "message": "Dane sejfu zostały wyeksportowane" }, "multifactorAuthenticationCancelled": { - "message": "Uwierzytelnianie wieloskładnikowe zostało anulowane" + "message": "Logowanie dwustopniowe zostało anulowane" }, "noLastPassDataFound": { "message": "Nie znaleziono danych LastPass" }, "incorrectUsernameOrPassword": { - "message": "Nieprawidłowa nazwa użytkownika lub hasło" + "message": "Nazwa użytkownika lub hasło są nieprawidłowe" }, "incorrectPassword": { - "message": "Błędne hasło" + "message": "Hasło jest nieprawidłowe" }, "incorrectCode": { - "message": "Błędny kod" + "message": "Kod jest nieprawidłowy" }, "incorrectPin": { - "message": "Niepoprawny PIN" + "message": "Kod PIN jest nieprawidłowy" }, "multifactorAuthenticationFailed": { - "message": "Uwierzytelnianie wieloskładnikowe nie powiodło się" + "message": "Logowanie dwustopniowe nie powiodło się" }, "includeSharedFolders": { "message": "Dołącz udostępnione foldery" }, "lastPassEmail": { - "message": "E-mail LastPass" + "message": "Adres e-mail LastPass" }, "importingYourAccount": { "message": "Importowanie konta..." }, "lastPassMFARequired": { - "message": "Wymagane jest uwierzytelnianie wieloskładnikowe LastPass" + "message": "Logowanie dwustopniowe LastPass jest wymagane" }, "lastPassMFADesc": { - "message": "Wprowadź jednorazowy kod z aplikacji uwierzytelniającej" + "message": "Wpisz jednorazowy kod z aplikacji uwierzytelniającej" }, "lastPassOOBDesc": { - "message": "Zatwierdź żądanie logowania w aplikacji uwierzytelniającej lub wprowadź jednorazowe hasło." + "message": "Potwierdź logowanie w aplikacji uwierzytelniającej lub wpisz jednorazowy kod." }, "passcode": { "message": "Kod" @@ -3587,10 +3583,10 @@ "message": "Hasło główne LastPass" }, "lastPassAuthRequired": { - "message": "Wymagane uwierzytelnianie LastPass" + "message": "Uwierzytelnianie LastPass jest wymagane" }, "awaitingSSO": { - "message": "Oczekiwanie na uwierzytelnianie SSO" + "message": "Oczekiwanie na logowanie jednokrotne" }, "awaitingSSODesc": { "message": "Kontynuuj logowanie przy użyciu danych firmowych." @@ -3606,40 +3602,40 @@ "message": "Importuj z CSV" }, "lastPassTryAgainCheckEmail": { - "message": "Spróbuj ponownie lub poszukaj wiadomości e-mail od LastPass, aby zweryfikować, że to Ty." + "message": "Spróbuj ponownie lub poszukaj wiadomości od LastPass, aby zweryfikować logowanie." }, "collection": { "message": "Kolekcja" }, "lastPassYubikeyDesc": { - "message": "Włóż YubiKey powiązany z Twoim kontem LastPass do portu USB komputera, a następnie naciśnij jego przycisk." + "message": "Włóż klucz YubiKey powiązany z kontem LastPass do portu USB urządzenia, a następnie dotknij jego przycisku." }, "commonImportFormats": { "message": "Popularne formaty", "description": "Label indicating the most common import formats" }, "uriMatchDefaultStrategyHint": { - "message": "URI match detection is how Bitwarden identifies autofill suggestions.", + "message": "Wykrywanie dopasowania to sposób, w jaki Bitwarden identyfikuje sugestie autouzupełniania.", "description": "Explains to the user that URI match detection determines how Bitwarden suggests autofill options, and clarifies that this default strategy applies when no specific match detection is set for a login item." }, "regExAdvancedOptionWarning": { - "message": "\"Regular expression\" is an advanced option with increased risk of exposing credentials.", + "message": "„Wyrażenie regularne” jest zaawansowaną opcją zwiększającą ryzyko ujawnienia danych logowania.", "description": "Content for dialog which warns a user when selecting 'regular expression' matching strategy as a cipher match strategy" }, "startsWithAdvancedOptionWarning": { - "message": "\"Starts with\" is an advanced option with increased risk of exposing credentials.", + "message": "„Rozpoczyna się od” jest zaawansowaną opcją zwiększającą ryzyko ujawnienia danych logowania.", "description": "Content for dialog which warns a user when selecting 'starts with' matching strategy as a cipher match strategy" }, "uriMatchWarningDialogLink": { - "message": "More about match detection", + "message": "Dowiedz się więcej o wykrywaniu dopasowania", "description": "Link to match detection docs on warning dialog for advance match strategy" }, "uriAdvancedOption": { - "message": "Advanced options", + "message": "Opcje zaawansowane", "description": "Advanced option placeholder for uri option component" }, "warningCapitalized": { - "message": "Warning", + "message": "Ostrzeżenie", "description": "Warning (should maintain locale-relevant capitalization)" }, "success": { @@ -3720,20 +3716,20 @@ "description": "This will be used as part of a larger sentence, broken up to include the generator icon. The full sentence will read 'Use the generator [GENERATOR_ICON] to create a strong unique password'" }, "useGeneratorHelpTextPartTwo": { - "message": ", aby utworzyć mocne unikalne hasło", + "message": ", aby utworzyć silne i unikalne hasło", "description": "This will be used as part of a larger sentence, broken up to include the generator icon. The full sentence will read 'Use the generator [GENERATOR_ICON] to create a strong unique password'" }, "biometricsStatusHelptextUnlockNeeded": { - "message": "Odblokowanie odciskiem palca jest niedostępne, ponieważ najpierw wymagane jest odblokowanie kodem PIN lub hasłem." + "message": "Odblokowanie biometrią jest niedostępne, ponieważ najpierw wymagane jest odblokowanie kodem PIN lub hasłem." }, "biometricsStatusHelptextHardwareUnavailable": { - "message": "Odblokowanie biometryczne jest obecnie niedostępne." + "message": "Odblokowanie biometrią jest obecnie niedostępne." }, "biometricsStatusHelptextAutoSetupNeeded": { - "message": "Odblokowanie biometryczne jest niedostępne z powodu nieprawidłowej konfiguracji plików systemowych." + "message": "Odblokowanie biometrią jest niedostępne z powodu nieprawidłowej konfiguracji plików systemowych." }, "biometricsStatusHelptextManualSetupNeeded": { - "message": "Odblokowanie biometryczne jest niedostępne z powodu nieprawidłowej konfiguracji plików systemowych." + "message": "Odblokowanie biometrią jest niedostępne z powodu nieprawidłowej konfiguracji plików systemowych." }, "biometricsStatusHelptextNotEnabledLocally": { "message": "Odblokowanie biometryczne jest niedostępne, ponieważ nie jest włączone dla $EMAIL$ w aplikacji desktopowej Bitwarden.", @@ -3763,10 +3759,10 @@ "message": "Historia elementu" }, "lastEdited": { - "message": "Ostatnio edytowane" + "message": "Zaktualizowano" }, "upload": { - "message": "Wyślij" + "message": "Prześlij" }, "authorize": { "message": "Autoryzuj" @@ -3781,7 +3777,7 @@ "message": "Warning: Agent Forwarding" }, "agentForwardingWarningText": { - "message": "To żądanie pochodzi ze zdalnego urządzenia, do którego jesteś zalogowany" + "message": "Żądanie pochodzi ze zdalnego zalogowanego urządzenia" }, "sshkeyApprovalMessageInfix": { "message": "wnioskuje o dostęp do" @@ -3838,7 +3834,7 @@ "message": "Zmień zagrożone hasło" }, "cannotRemoveViewOnlyCollections": { - "message": "Nie można usunąć kolekcji z uprawnieniami tylko do przeglądania: $COLLECTIONS$", + "message": "Nie możesz usunąć następujących kolekcji z uprawnieniami tylko do odczytu: $COLLECTIONS$", "placeholders": { "collections": { "content": "$1", @@ -3856,31 +3852,31 @@ "message": "Nazwa folderu" }, "folderHintText": { - "message": "Zagnieżdżaj foldery dodając nazwę folderu nadrzędnego, a następnie “/”. Przykład: Społeczne/Fora" + "message": "Utwórz podfolder, dodając nazwę folderu nadrzędnego przed znakiem „/”. Przykład: Social/Forums" }, "sendsTitleNoItems": { - "message": "Wysyłaj bezpiecznie poufne informacje", + "message": "Wysyłaj poufne informacje w bezpieczny sposób", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendsBodyNoItems": { - "message": "Udostępniaj pliki i dane bezpiecznie każdemu, na każdej platformie. Twoje dane pozostaną zaszyfrowane end-to-end przy jednoczesnym ograniczeniu narażenia.", + "message": "Udostępniaj pliki i teksty każdemu na dowolnej platformie. Informacje będę szyfrowane end-to-end, zapewniając poufność.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "generatorNudgeTitle": { - "message": "Szybko twórz hasła" + "message": "Szybkie tworzenie haseł" }, "generatorNudgeBodyOne": { - "message": "Łatwo twórz silne i unikalne hasła, klikając na", + "message": "Twórz silne i unikalne hasła, klikając przycisk", "description": "Two part message", "example": "Easily create strong and unique passwords by clicking on {icon} to help you keep your logins secure." }, "generatorNudgeBodyTwo": { - "message": ", aby pomóc Ci zachować bezpieczeństwo Twoich danych logowania.", + "message": ", aby zapewnić bezpieczeństwo danych logowania.", "description": "Two part message", "example": "Easily create strong and unique passwords by clicking on {icon} to help you keep your logins secure." }, "generatorNudgeBodyAria": { - "message": "Łatwo twórz silne i unikalne hasła, klikając na Wygeneruj Hasło, aby pomóc Ci zachować bezpieczeństwo Twoich danych logowania.", + "message": "Twórz silne i unikalne hasła, klikając przycisk Wygeneruj hasło, aby zapewnić bezpieczeństwo danych logowania.", "description": "Aria label for the body content of the generator nudge" }, "newLoginNudgeTitle": { @@ -3892,12 +3888,12 @@ "example": "Include a Website so this login appears as an autofill suggestion." }, "newLoginNudgeBodyBold": { - "message": "Strona", + "message": "stronę internetową", "description": "This is in multiple parts to allow for bold text in the middle of the sentence.", "example": "Include a Website so this login appears as an autofill suggestion." }, "newLoginNudgeBodyTwo": { - "message": ", aby ten login pojawił się jako sugestia autouzupełniania.", + "message": ", aby dane logowania pojawiały się jako sugestia autouzupełniania.", "description": "This is in multiple parts to allow for bold text in the middle of the sentence.", "example": "Include a Website so this login appears as an autofill suggestion." }, @@ -3905,25 +3901,25 @@ "message": "Bezproblemowe zamówienia online" }, "newCardNudgeBody": { - "message": "Z kartami łatwe autouzupełnianie formularzy płatności w sposób bezpieczny i dokładny." + "message": "Dzięki kartom możesz łatwo i bezpiecznie uzupełniać formularze płatności." }, "newIdentityNudgeTitle": { - "message": "Uprość tworzenie kont" + "message": "Łatwe tworzenie kont" }, "newIdentityNudgeBody": { - "message": "Z tożsamościami, szybko autouzupełnij długie formularze rejestracyjne lub kontaktowe." + "message": "Dzięki tożsamościom możesz szybko uzupełniać długie formularze rejestracyjne i kontaktowe." }, "newNoteNudgeTitle": { - "message": "Zachowaj bezpieczeństwo wrażliwych danych" + "message": "Chroń wrażliwe dane" }, "newNoteNudgeBody": { - "message": "Z notatkami bezpiecznie przechowuj dane szczególnie chronione, takie jak dane bankowe lub ubezpieczeniowe." + "message": "Dzięki notatkom możesz bezpiecznie przechowywać poufne dane, takie jak bankowe lub ubezpieczeniowe." }, "newSshNudgeTitle": { - "message": "Przyjazny dla deweloperów dostęp SSH" + "message": "Dostęp SSH przyjazny dla programistów" }, "newSshNudgeBodyOne": { - "message": "Przechowuj swoje klucze i połącz się z agentem SSH dla szybkiego, szyfrowanego uwierzytelniania.", + "message": "Przechowuj klucze i łącz się z agentem SSH w celu szybkiego, szyfrowanego uwierzytelniania.", "description": "Two part message", "example": "Store your keys and connect with the SSH agent for fast, encrypted authentication. Learn more about SSH agent" }, @@ -3933,25 +3929,25 @@ "example": "Store your keys and connect with the SSH agent for fast, encrypted authentication. Learn more about SSH agent" }, "assignToCollections": { - "message": "Assign to collections" + "message": "Przypisz do kolekcji" }, "assignToTheseCollections": { - "message": "Assign to these collections" + "message": "Przypisz do tych kolekcji" }, "bulkCollectionAssignmentDialogDescriptionSingular": { - "message": "Only organization members with access to these collections will be able to see the item." + "message": "Tylko członkowie organizacji z dostępem do tych kolekcji będą mogli zobaczyć ten element." }, "bulkCollectionAssignmentDialogDescriptionPlural": { - "message": "Only organization members with access to these collections will be able to see the items." + "message": "Tylko członkowie organizacji z dostępem do tych kolekcji będą mogli zobaczyć te elementy." }, "noCollectionsAssigned": { - "message": "No collections have been assigned" + "message": "Nie przypisano kolekcji" }, "assign": { - "message": "Assign" + "message": "Przypisz" }, "bulkCollectionAssignmentDialogDescription": { - "message": "Only organization members with access to these collections will be able to see the items." + "message": "Tylko członkowie organizacji z dostępem do tych kolekcji będą mogli zobaczyć te elementy." }, "bulkCollectionAssignmentWarning": { "message": "You have selected $TOTAL_COUNT$ items. You cannot update $READONLY_COUNT$ of the items because you do not have edit permissions.", @@ -3966,7 +3962,7 @@ } }, "selectCollectionsToAssign": { - "message": "Select collections to assign" + "message": "Wybierz kolekcje do przypisania" }, "personalItemsTransferWarning": { "message": "$PERSONAL_ITEMS_COUNT$ will be permanently transferred to the selected organization. You will no longer own these items.", @@ -3991,10 +3987,10 @@ } }, "personalItemTransferWarningSingular": { - "message": "1 item will be permanently transferred to the selected organization. You will no longer own this item." + "message": "Element zostanie przeniesiony do organizacji. Nie będziesz już właścicielem elementu." }, "personalItemWithOrgTransferWarningSingular": { - "message": "1 item will be permanently transferred to $ORG$. You will no longer own this item.", + "message": "Element zostanie przeniesiony do organizacji $ORG$. Nie będziesz już właścicielem elementu.", "placeholders": { "org": { "content": "$1", @@ -4003,13 +3999,13 @@ } }, "successfullyAssignedCollections": { - "message": "Successfully assigned collections" + "message": "Przypisano kolekcje" }, "nothingSelected": { - "message": "You have not selected anything." + "message": "Nie zaznaczono żadnych elementów." }, "itemsMovedToOrg": { - "message": "Items moved to $ORGNAME$", + "message": "Elementy zostały przeniesione do organizacji $ORGNAME$", "placeholders": { "orgname": { "content": "$1", @@ -4018,7 +4014,7 @@ } }, "itemMovedToOrg": { - "message": "Item moved to $ORGNAME$", + "message": "Element został przeniesiony do organizacji $ORGNAME$", "placeholders": { "orgname": { "content": "$1", @@ -4027,7 +4023,7 @@ } }, "movedItemsToOrg": { - "message": "Selected items moved to $ORGNAME$", + "message": "Zaznaczone elementy zostały przeniesione do organizacji $ORGNAME$", "placeholders": { "orgname": { "content": "$1", @@ -4067,15 +4063,19 @@ } }, "showMore": { - "message": "Show more" + "message": "Pokaż więcej" }, "showLess": { - "message": "Show less" + "message": "Pokaż mniej" }, "enableAutotype": { "message": "Enable Autotype" }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "Więcej nawigacji", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/pt_BR/messages.json b/apps/desktop/src/locales/pt_BR/messages.json index 84236796650..321a940152c 100644 --- a/apps/desktop/src/locales/pt_BR/messages.json +++ b/apps/desktop/src/locales/pt_BR/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Selecione uma coleção" }, - "importTargetHint": { - "message": "Selecione esta opção se você quer o conteúdo do arquivo importado movido para $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Arquivo contém itens não atribuídos." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden não valida localizações de entrada, tenha certeza de estar na janela e campo corretos antes de utilizar o atalho." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/pt_PT/messages.json b/apps/desktop/src/locales/pt_PT/messages.json index 3f1fb3e5039..87b39fe75fe 100644 --- a/apps/desktop/src/locales/pt_PT/messages.json +++ b/apps/desktop/src/locales/pt_PT/messages.json @@ -608,14 +608,14 @@ "description": "deprecated. Use numbersLabel instead." }, "specialCharacters": { - "message": "Carateres especiais (!@#$%^&*)" + "message": "Caracteres especiais (!@#$%^&*)" }, "include": { "message": "Incluir", "description": "Card header for password generator include block" }, "uppercaseDescription": { - "message": "Incluir carateres em maiúsculas", + "message": "Incluir caracteres em maiúsculas", "description": "Tooltip for the password generator uppercase character checkbox" }, "uppercaseLabel": { @@ -623,7 +623,7 @@ "description": "Label for the password generator uppercase character checkbox" }, "lowercaseDescription": { - "message": "Incluir carateres em minúsculas", + "message": "Incluir caracteres em minúsculas", "description": "Full description for the password generator lowercase character checkbox" }, "lowercaseLabel": { @@ -639,7 +639,7 @@ "description": "Label for the password generator numbers checkbox" }, "specialCharactersDescription": { - "message": "Incluir carateres especiais", + "message": "Incluir caracteres especiais", "description": "Full description for the password generator special characters checkbox" }, "numWords": { @@ -662,15 +662,15 @@ "message": "Mínimo de números" }, "minSpecial": { - "message": "Mínimo de carateres especiais", + "message": "Mínimo de caracteres especiais", "description": "Minimum Special Characters" }, "ambiguous": { - "message": "Evitar carateres ambíguos", + "message": "Evitar caracteres ambíguos", "description": "deprecated. Use avoidAmbiguous instead." }, "avoidAmbiguous": { - "message": "Evitar carateres ambíguos", + "message": "Evitar caracteres ambíguos", "description": "Label for the avoid ambiguous characters checkbox." }, "generatorPolicyInEffect": { @@ -784,7 +784,7 @@ "message": "Dica da palavra-passe mestra (opcional)" }, "masterPassHintText": { - "message": "Se se esquecer da sua palavra-passe, a dica da palavra-passe pode ser enviada para o seu e-mail. Máximo de $CURRENT$/$MAXIMUM$ carateres.", + "message": "Se se esquecer da sua palavra-passe, a dica da palavra-passe pode ser enviada para o seu e-mail. Máximo de $CURRENT$/$MAXIMUM$ caracteres.", "placeholders": { "current": { "content": "$1", @@ -863,7 +863,7 @@ "message": "É necessário reescrever a palavra-passe mestra." }, "masterPasswordMinlength": { - "message": "A palavra-passe mestra deve ter pelo menos $VALUE$ carateres.", + "message": "A palavra-passe mestra deve ter pelo menos $VALUE$ caracteres.", "description": "The Master Password must be at least a specific number of characters long.", "placeholders": { "value": { @@ -2070,16 +2070,16 @@ } }, "policyInEffectUppercase": { - "message": "Contém um ou mais carateres em maiúsculas" + "message": "Contém um ou mais caracteres em maiúsculas" }, "policyInEffectLowercase": { - "message": "Contém um ou mais carateres em minúsculas" + "message": "Contém um ou mais caracteres em minúsculas" }, "policyInEffectNumbers": { "message": "Contém um ou mais números" }, "policyInEffectSpecial": { - "message": "Contém um ou mais dos seguintes carateres especiais $CHARS$", + "message": "Contém um ou mais dos seguintes caracteres especiais $CHARS$", "placeholders": { "chars": { "content": "$1", @@ -2724,7 +2724,7 @@ } }, "passwordLengthRecommendationHint": { - "message": " Utilize $RECOMMENDED$ carateres ou mais para gerar uma palavra-passe forte.", + "message": " Utilize $RECOMMENDED$ caracteres ou mais para gerar uma palavra-passe forte.", "description": "Appended to `spinboxBoundariesHint` to recommend a length to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -3024,7 +3024,7 @@ "message": "Reenviar notificação" }, "toggleCharacterCount": { - "message": "Mostrar/ocultar contagem de carateres", + "message": "Mostrar/ocultar contagem de caracteres", "description": "'Character count' describes a feature that displays a number next to each character of the password." }, "accessAttemptBy": { @@ -3183,7 +3183,7 @@ "message": "A sua palavra-passe mestra não pode ser recuperada se a esquecer!" }, "characterMinimum": { - "message": "$LENGTH$ carateres no mínimo", + "message": "$LENGTH$ caracteres no mínimo", "placeholders": { "length": { "content": "$1", @@ -3301,7 +3301,7 @@ "message": "Procurar" }, "inputMinLength": { - "message": "O campo deve ter pelo menos $COUNT$ carateres.", + "message": "O campo deve ter pelo menos $COUNT$ caracteres.", "placeholders": { "count": { "content": "$1", @@ -3310,7 +3310,7 @@ } }, "inputMaxLength": { - "message": "O campo não pode exceder os $COUNT$ carateres de comprimento.", + "message": "O campo não pode exceder os $COUNT$ caracteres de comprimento.", "placeholders": { "count": { "content": "$1", @@ -3319,7 +3319,7 @@ } }, "inputForbiddenCharacters": { - "message": "Não são permitidos os seguintes carateres: $CHARACTERS$", + "message": "Não são permitidos os seguintes caracteres: $CHARACTERS$", "placeholders": { "characters": { "content": "$1", @@ -3328,7 +3328,7 @@ } }, "inputMinValue": { - "message": "O valor do campo tem de ser, pelo menos, $MIN$ carateres.", + "message": "O valor do campo tem de ser, pelo menos, $MIN$ caracteres.", "placeholders": { "min": { "content": "$1", @@ -3337,7 +3337,7 @@ } }, "inputMaxValue": { - "message": "O valor do campo não pode exceder os $MAX$ carateres.", + "message": "O valor do campo não pode exceder os $MAX$ caracteres.", "placeholders": { "max": { "content": "$1", @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Selecionar uma coleção" }, - "importTargetHint": { - "message": "Selecione esta opção se pretender que o conteúdo do ficheiro importado seja transferido para $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Selecione esta opção se pretender que o conteúdo do ficheiro importado seja transferido para uma coleção" + }, + "importTargetHintFolder": { + "message": "Selecione esta opção se pretender que o conteúdo do ficheiro importado seja transferido para uma pasta" }, "importUnassignedItemsError": { "message": "O ficheiro contém itens não atribuídos." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "O Bitwarden não valida a introdução de localizações. Certifique-se de que está na janela e no campo corretos antes de utilizar o atalho." + }, + "moreBreadcrumbs": { + "message": "Mais da navegação estrutural", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/ro/messages.json b/apps/desktop/src/locales/ro/messages.json index 03064f271d4..34d13a1a06b 100644 --- a/apps/desktop/src/locales/ro/messages.json +++ b/apps/desktop/src/locales/ro/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/ru/messages.json b/apps/desktop/src/locales/ru/messages.json index cd8179edc64..865c25fcd36 100644 --- a/apps/desktop/src/locales/ru/messages.json +++ b/apps/desktop/src/locales/ru/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Выберите коллекцию" }, - "importTargetHint": { - "message": "Выберите эту опцию, если хотите, чтобы содержимое импортированного файла было перемещено в $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Выберите эту опцию, если хотите, чтобы содержимое импортированного файла было перемещено в коллекцию" + }, + "importTargetHintFolder": { + "message": "Выберите эту опцию, если хотите, чтобы содержимое импортированного файла было перемещено в папку" }, "importUnassignedItemsError": { "message": "Файл содержит неназначенные элементы." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden не проверяет местоположение ввода, поэтому, прежде чем использовать ярлык, убедитесь, что вы находитесь в нужном окне и поле." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/si/messages.json b/apps/desktop/src/locales/si/messages.json index 6c8dfd84d0f..8adedf0e6ed 100644 --- a/apps/desktop/src/locales/si/messages.json +++ b/apps/desktop/src/locales/si/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/sk/messages.json b/apps/desktop/src/locales/sk/messages.json index ea1f291ca3e..3e9ec97fa38 100644 --- a/apps/desktop/src/locales/sk/messages.json +++ b/apps/desktop/src/locales/sk/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Vyberte zbierku" }, - "importTargetHint": { - "message": "Zvoľte túto možnosť, ak chcete obsah importovaného súboru presunúť do $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Zvoľte túto možnosť, ak chcete obsah importovaného súboru presunúť do zbierky" + }, + "importTargetHintFolder": { + "message": "Zvoľte túto možnosť, ak chcete obsah importovaného súboru presunúť do priečinka" }, "importUnassignedItemsError": { "message": "Súbor obsahuje nepriradené položky." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden neoveruje miesto stupu, pred použitím skratky sa uistite, že ste v správnom okne a poli." + }, + "moreBreadcrumbs": { + "message": "Viac", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/sl/messages.json b/apps/desktop/src/locales/sl/messages.json index c96874d50d2..c898ab2da73 100644 --- a/apps/desktop/src/locales/sl/messages.json +++ b/apps/desktop/src/locales/sl/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/sr/messages.json b/apps/desktop/src/locales/sr/messages.json index c8b07a79cc8..7d313b6f5a4 100644 --- a/apps/desktop/src/locales/sr/messages.json +++ b/apps/desktop/src/locales/sr/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Изабери колекцију" }, - "importTargetHint": { - "message": "Изаберите ову опцију ако желите да се садржај увезене датотеке премести у $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Датотека садржи недодељене ставке." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden не потврђује локације уноса, будите сигурни да сте у добром прозору и поље пре употребе пречице." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/sv/messages.json b/apps/desktop/src/locales/sv/messages.json index 0c20d8ba2b5..f8bf6cbb4bd 100644 --- a/apps/desktop/src/locales/sv/messages.json +++ b/apps/desktop/src/locales/sv/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Välj en samling" }, - "importTargetHint": { - "message": "Välj det här alternativet om du vill att innehållet i den importerade filen ska flyttas till en $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Filen innehåller otilldelade objekt." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden validerar inte inmatningsplatser, så se till att du är i rätt fönster och fält innan du använder genvägen." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/te/messages.json b/apps/desktop/src/locales/te/messages.json index 2e0d5b09f5c..028bc34f77e 100644 --- a/apps/desktop/src/locales/te/messages.json +++ b/apps/desktop/src/locales/te/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/th/messages.json b/apps/desktop/src/locales/th/messages.json index 4243cba8e42..27f6048a27d 100644 --- a/apps/desktop/src/locales/th/messages.json +++ b/apps/desktop/src/locales/th/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/tr/messages.json b/apps/desktop/src/locales/tr/messages.json index 7a81a0642fc..8d45329f18f 100644 --- a/apps/desktop/src/locales/tr/messages.json +++ b/apps/desktop/src/locales/tr/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Bir koleksiyon seçin" }, - "importTargetHint": { - "message": "İçe aktarılan dosya içeriklerinin $DESTINATION$ konumuna taşınmasını istiyorsanız bu seçeneği seçin", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "İçe aktarılan dosya içeriklerinin bir koleksiyona taşınmasını istiyorsanız bu seçeneği seçin" + }, + "importTargetHintFolder": { + "message": "İçe aktarılan dosya içeriklerinin bir klasöre taşınmasını istiyorsanız bu seçeneği seçin" }, "importUnassignedItemsError": { "message": "Dosya atanmamış öğeler içeriyor." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/uk/messages.json b/apps/desktop/src/locales/uk/messages.json index a577d9fe868..434680d8338 100644 --- a/apps/desktop/src/locales/uk/messages.json +++ b/apps/desktop/src/locales/uk/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Вибрати збірку" }, - "importTargetHint": { - "message": "Оберіть цю опцію, якщо ви хочете, щоб вміст імпортованого файлу було збережено в $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Файл містить непризначені записи." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden не перевіряє місця введення. Переконайтеся, що у вас відкрите правильне вікно і вибрано потрібне поле, перш ніж застосувати комбінацію клавіш." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/vi/messages.json b/apps/desktop/src/locales/vi/messages.json index e97db4388e5..45714b3e58b 100644 --- a/apps/desktop/src/locales/vi/messages.json +++ b/apps/desktop/src/locales/vi/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "Chọn bộ sưu tập" }, - "importTargetHint": { - "message": "Chọn tùy chọn này nếu bạn muốn nội dung của tệp đã nhập được di chuyển đến $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Tập tin chứa các mục không xác định." @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden không kiểm tra vị trí nhập liệu, hãy đảm bảo bạn đang ở trong đúng cửa sổ và trường nhập liệu trước khi dùng phím tắt." + }, + "moreBreadcrumbs": { + "message": "Thêm mục điều hướng", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/zh_CN/messages.json b/apps/desktop/src/locales/zh_CN/messages.json index 3dd11c5d106..f064b110b1f 100644 --- a/apps/desktop/src/locales/zh_CN/messages.json +++ b/apps/desktop/src/locales/zh_CN/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "选择一个集合" }, - "importTargetHint": { - "message": "如果您希望将导入的文件内容移动到某个 $DESTINATION$,请选择此选项", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "如果希望将导入的文件内容移动到集合中,请选择此选项" + }, + "importTargetHintFolder": { + "message": "如果希望将导入的文件内容移动到文件夹中,请选择此选项" }, "importUnassignedItemsError": { "message": "文件包含未分配项目。" @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden 不会验证输入位置,在使用快捷键之前,请确保您位于正确的窗口和字段中。" + }, + "moreBreadcrumbs": { + "message": "进一步的指引", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/zh_TW/messages.json b/apps/desktop/src/locales/zh_TW/messages.json index 96b37b1c8fd..641a27e5a34 100644 --- a/apps/desktop/src/locales/zh_TW/messages.json +++ b/apps/desktop/src/locales/zh_TW/messages.json @@ -3491,15 +3491,11 @@ "selectImportCollection": { "message": "選擇一個分類" }, - "importTargetHint": { - "message": "如果您要將匯入檔案的內容移動到 $DESTINATION$,請選擇此選項", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "檔案包含未指派項目。" @@ -4077,5 +4073,9 @@ }, "enableAutotypeDescription": { "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } From 60762b728c48cad05e92257abe2976df3d1f8c1d Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 10:58:42 +0000 Subject: [PATCH 031/167] Autosync the updated translations (#16117) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/browser/src/_locales/ar/messages.json | 18 ++-- apps/browser/src/_locales/az/messages.json | 18 ++-- apps/browser/src/_locales/be/messages.json | 18 ++-- apps/browser/src/_locales/bg/messages.json | 18 ++-- apps/browser/src/_locales/bn/messages.json | 18 ++-- apps/browser/src/_locales/bs/messages.json | 18 ++-- apps/browser/src/_locales/ca/messages.json | 18 ++-- apps/browser/src/_locales/cs/messages.json | 18 ++-- apps/browser/src/_locales/cy/messages.json | 18 ++-- apps/browser/src/_locales/da/messages.json | 18 ++-- apps/browser/src/_locales/de/messages.json | 18 ++-- apps/browser/src/_locales/el/messages.json | 18 ++-- apps/browser/src/_locales/en_GB/messages.json | 18 ++-- apps/browser/src/_locales/en_IN/messages.json | 18 ++-- apps/browser/src/_locales/es/messages.json | 18 ++-- apps/browser/src/_locales/et/messages.json | 36 +++---- apps/browser/src/_locales/eu/messages.json | 18 ++-- apps/browser/src/_locales/fa/messages.json | 18 ++-- apps/browser/src/_locales/fi/messages.json | 18 ++-- apps/browser/src/_locales/fil/messages.json | 18 ++-- apps/browser/src/_locales/fr/messages.json | 18 ++-- apps/browser/src/_locales/gl/messages.json | 18 ++-- apps/browser/src/_locales/he/messages.json | 18 ++-- apps/browser/src/_locales/hi/messages.json | 18 ++-- apps/browser/src/_locales/hr/messages.json | 18 ++-- apps/browser/src/_locales/hu/messages.json | 18 ++-- apps/browser/src/_locales/id/messages.json | 24 ++--- apps/browser/src/_locales/it/messages.json | 18 ++-- apps/browser/src/_locales/ja/messages.json | 18 ++-- apps/browser/src/_locales/ka/messages.json | 18 ++-- apps/browser/src/_locales/km/messages.json | 18 ++-- apps/browser/src/_locales/kn/messages.json | 18 ++-- apps/browser/src/_locales/ko/messages.json | 18 ++-- apps/browser/src/_locales/lt/messages.json | 94 +++++++++---------- apps/browser/src/_locales/lv/messages.json | 18 ++-- apps/browser/src/_locales/ml/messages.json | 18 ++-- apps/browser/src/_locales/mr/messages.json | 18 ++-- apps/browser/src/_locales/my/messages.json | 18 ++-- apps/browser/src/_locales/nb/messages.json | 18 ++-- apps/browser/src/_locales/ne/messages.json | 18 ++-- apps/browser/src/_locales/nl/messages.json | 20 ++-- apps/browser/src/_locales/nn/messages.json | 18 ++-- apps/browser/src/_locales/or/messages.json | 18 ++-- apps/browser/src/_locales/pl/messages.json | 48 +++++----- apps/browser/src/_locales/pt_BR/messages.json | 24 ++--- apps/browser/src/_locales/pt_PT/messages.json | 58 ++++++------ apps/browser/src/_locales/ro/messages.json | 18 ++-- apps/browser/src/_locales/ru/messages.json | 18 ++-- apps/browser/src/_locales/si/messages.json | 18 ++-- apps/browser/src/_locales/sk/messages.json | 18 ++-- apps/browser/src/_locales/sl/messages.json | 18 ++-- apps/browser/src/_locales/sr/messages.json | 18 ++-- apps/browser/src/_locales/sv/messages.json | 18 ++-- apps/browser/src/_locales/te/messages.json | 18 ++-- apps/browser/src/_locales/th/messages.json | 18 ++-- apps/browser/src/_locales/tr/messages.json | 18 ++-- apps/browser/src/_locales/uk/messages.json | 18 ++-- apps/browser/src/_locales/vi/messages.json | 20 ++-- apps/browser/src/_locales/zh_CN/messages.json | 18 ++-- apps/browser/src/_locales/zh_TW/messages.json | 18 ++-- 60 files changed, 630 insertions(+), 630 deletions(-) diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index ee723217f2a..9b0efbd8148 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "اختر مجموعة" }, - "importTargetHint": { - "message": "حدد هذا الخيار إذا كنت تريد نقل محتويات الملف المستورد إلى $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "الملف يحتوي على عناصر غير مسندة." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index 1d26f50bca6..8a3c5dcb3c6 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Bir kolleksiya seçin" }, - "importTargetHint": { - "message": "Daxilə köçürülən fayl məzmununun $DESTINATION$ yerinə daşınmasını istəyirsinizsə bu variantı seçin", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Daxilə köçürülən fayl məzmunlarının bir kolleksiyaya daşınmasını istəyirsinizsə bu variantı seçin" + }, + "importTargetHintFolder": { + "message": "Daxilə köçürülən fayl məzmunlarının bir qovluğa daşınmasını istəyirsinizsə bu variantı seçin" }, "importUnassignedItemsError": { "message": "Faylda təyin edilməmiş elementlər var." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Daha az göstər" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index d6090123878..ed6ac29ea1e 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Выбраць калекцыю" }, - "importTargetHint": { - "message": "Выберыце гэты параметр, калі вы хочаце, каб змесціва імпартаванага файла было перамешчанага ў $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Файл змяшчае непадпісаныя элементы." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index 3b411cd088c..97d8c1a3a43 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Изберете колекция" }, - "importTargetHint": { - "message": "Изберете тази опция, ако искате съдържанието на внесения файл да бъде преместено в $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Изберете тази опция, ако искате съдържанието на внесения файл да бъде преместено в колекция" + }, + "importTargetHintFolder": { + "message": "Изберете тази опция, ако искате съдържанието на внесения файл да бъде преместено в папка" }, "importUnassignedItemsError": { "message": "Файлът съдържа невъзложени елементи." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Показване на по-малко" + }, + "moreBreadcrumbs": { + "message": "Още елементи в пътечката", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json index 55baca0dad2..b816b274766 100644 --- a/apps/browser/src/_locales/bn/messages.json +++ b/apps/browser/src/_locales/bn/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json index 7ad375dabf0..347fc68924f 100644 --- a/apps/browser/src/_locales/bs/messages.json +++ b/apps/browser/src/_locales/bs/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index 3edfb98eba2..0a9500e3c03 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Selecciona una col·lecció" }, - "importTargetHint": { - "message": "Seleccioneu aquesta opció si voleu que el contingut del fitxer importat es desplace a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "El fitxer conté elements no assignats." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json index 916f765ea21..b31c18524cf 100644 --- a/apps/browser/src/_locales/cs/messages.json +++ b/apps/browser/src/_locales/cs/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Zvolte sbírku" }, - "importTargetHint": { - "message": "Pokud chcete obsah importovaného souboru přesunout do: \"$DESTINATION$\", vyberte tuto volbu", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Pokud chcete obsah importovaného souboru přesunout do sbírky, vyberte tuto volbu" + }, + "importTargetHintFolder": { + "message": "Pokud chcete obsah importovaného souboru přesunout do složky, vyberte tuto volbu" }, "importUnassignedItemsError": { "message": "Soubor obsahuje nepřiřazené položky." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Zobrazit méně" + }, + "moreBreadcrumbs": { + "message": "Více...", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/cy/messages.json b/apps/browser/src/_locales/cy/messages.json index 8307b994fe0..c1ea7f6036c 100644 --- a/apps/browser/src/_locales/cy/messages.json +++ b/apps/browser/src/_locales/cy/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index 0ff87e6e14f..52ca548a080 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Vælg en samling" }, - "importTargetHint": { - "message": "Vælg denne indstilling, hvis importeret filindhold skal flyttet til en $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Fil indeholder ikke-tildelte emner." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index ffaf490fbf8..16f572fea2e 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Sammlung auswählen" }, - "importTargetHint": { - "message": "Wähle diese Option, wenn der importierte Dateiinhalt in eine(n) $DESTINATION$ verschoben werden soll", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Die Datei enthält nicht zugewiesene Einträge." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Weniger anzeigen" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index 3d46b63ec45..6a34fbd4fd0 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Επιλέξτε μια συλλογή" }, - "importTargetHint": { - "message": "Επιλέξτε αυτή την επιλογή εάν θέλετε τα περιεχόμενα του εισαγόμενου αρχείου να μετακινηθούν στο $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Το αρχείο περιέχει μη συσχετισμένα στοιχεία." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json index 8acf75e2ee5..c74a39779a0 100644 --- a/apps/browser/src/_locales/en_GB/messages.json +++ b/apps/browser/src/_locales/en_GB/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json index 281caeac0d5..57f92159031 100644 --- a/apps/browser/src/_locales/en_IN/messages.json +++ b/apps/browser/src/_locales/en_IN/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index 0e1185148df..96885ea5e37 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Selecciona una colección" }, - "importTargetHint": { - "message": "Selecciona esta opción si deseas que el contenido del archivo importado se mueva a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "El archivo contiene elementos no asignados." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json index 09e77bd361f..4631cbfe018 100644 --- a/apps/browser/src/_locales/et/messages.json +++ b/apps/browser/src/_locales/et/messages.json @@ -111,13 +111,13 @@ "message": "Kaart" }, "vault": { - "message": "Seif" + "message": "Hoidla" }, "myVault": { - "message": "Minu seif" + "message": "Minu hoidla" }, "allVaults": { - "message": "Kõik seifid" + "message": "Kõik hoidlad" }, "tools": { "message": "Tööriistad" @@ -671,7 +671,7 @@ "message": "Hoidla on lukus. Jätkamiseks sisesta ülemparool." }, "yourVaultIsLockedV2": { - "message": "Your vault is locked" + "message": "Sinu hoidla on lukus" }, "yourAccountIsLocked": { "message": "Your account is locked" @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -4476,13 +4472,13 @@ "message": "Pääsuvõti on eemaldatud" }, "autofillSuggestions": { - "message": "Autofill suggestions" + "message": "Automaatse täitmise soovitused" }, "itemSuggestions": { "message": "Suggested items" }, "autofillSuggestionsTip": { - "message": "Save a login item for this site to autofill" + "message": "Automaatseks täitmiseks salvesta kirje selle saidi jaoks" }, "yourVaultIsEmpty": { "message": "Your vault is empty" @@ -4649,7 +4645,7 @@ } }, "new": { - "message": "New" + "message": "Uus" }, "removeItem": { "message": "Remove $NAME$", @@ -4690,7 +4686,7 @@ "message": "Item history" }, "lastEdited": { - "message": "Last edited" + "message": "Viimati muudetud" }, "ownerYou": { "message": "Owner: You" @@ -5490,7 +5486,7 @@ "message": "Import now" }, "hasItemsVaultNudgeTitle": { - "message": "Welcome to your vault!" + "message": "Tere tulemast sinu hoidlasse!" }, "hasItemsVaultNudgeBodyOne": { "message": "Autofill items for the current page" @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index 1cd1439e972..70ce920c7a6 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index cfae87fd1a5..e62839f1f31 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "انتخاب یک مجموعه" }, - "importTargetHint": { - "message": "اگر می‌خواهید محتوای پرونده درون ریزی شده به $DESTINATION$ منتقل شود، این گزینه را انتخاب کنید", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "پرونده حاوی موارد اختصاص نیافته است." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index ffd5caea1d3..6454e78dcdb 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Valitse kokoelma" }, - "importTargetHint": { - "message": "Valitse tämä, jos haluat tuoda tiedoston sisällön kohteeseen \"$DESTINATION$\".", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Tiedosto sisältää määrittämättömiä kohteita." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json index 1682d21aa7f..9ce7ee5d427 100644 --- a/apps/browser/src/_locales/fil/messages.json +++ b/apps/browser/src/_locales/fil/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json index 1a4f466a41c..42a11655ca1 100644 --- a/apps/browser/src/_locales/fr/messages.json +++ b/apps/browser/src/_locales/fr/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Sélectionner une collection" }, - "importTargetHint": { - "message": "Sélectionnez cette option si vous voulez que le contenu du fichier importé soit déplacé vers un(e) $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Sélectionnez cette option si vous voulez que le contenu du fichier importé soit déplacé vers une collection" + }, + "importTargetHintFolder": { + "message": "Sélectionnez cette option si vous voulez que le contenu du fichier importé soit déplacé vers un dossier" }, "importUnassignedItemsError": { "message": "Le fichier contient des éléments non assignés." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/gl/messages.json b/apps/browser/src/_locales/gl/messages.json index 0698191f53e..0b1b754a41e 100644 --- a/apps/browser/src/_locales/gl/messages.json +++ b/apps/browser/src/_locales/gl/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Seleccionar unha colección" }, - "importTargetHint": { - "message": "Selecciona esta opción se queres que o contido importado se mova a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "O arquivo contén entradas sen asignar." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json index 96dc5215051..28667c2b2a4 100644 --- a/apps/browser/src/_locales/he/messages.json +++ b/apps/browser/src/_locales/he/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "בחר אוסף" }, - "importTargetHint": { - "message": "בחר באפשרות זו אם ברצונך להעביר את תוכן הקובץ המיובא אל $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "קובץ מכיל פריטים לא מוקצים." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json index 35d7e8b2911..4aed6e60763 100644 --- a/apps/browser/src/_locales/hi/messages.json +++ b/apps/browser/src/_locales/hi/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json index d38461ab553..c1244477098 100644 --- a/apps/browser/src/_locales/hr/messages.json +++ b/apps/browser/src/_locales/hr/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Odaberi zbirku" }, - "importTargetHint": { - "message": "Odaberi ovu opciju ako sadržaj uvezene datoteke želiš spremiti u $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Datoteka sadrži nedodijeljene stavke." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Pokaži manje" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json index a0fc88e047a..87020472c53 100644 --- a/apps/browser/src/_locales/hu/messages.json +++ b/apps/browser/src/_locales/hu/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Gyűjtemény kiválasztása" }, - "importTargetHint": { - "message": "Válasszuk ezt a lehetőséget, ha azt akarjuk, hogy az importált fájl tartalma $DESTINATION$ helyre kerüljön", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Válasszuk ezt az opciót, ha azt akarjuk, hogy az importált fájl tartalma egy gyűjteménybe kerüljön." + }, + "importTargetHintFolder": { + "message": "Válasszuk ezt az opciót, ha azt akarjuk, hogy az importált fájl tartalma egy mappába kerüljön." }, "importUnassignedItemsError": { "message": "A fájl hozzá nem rendelt elemeket tartalmaz." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Kevesebb megjelenítése" + }, + "moreBreadcrumbs": { + "message": "További morzsamenük", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json index 297b2d458e1..5698286283c 100644 --- a/apps/browser/src/_locales/id/messages.json +++ b/apps/browser/src/_locales/id/messages.json @@ -3789,7 +3789,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendsBodyNoItems": { - "message": "Bagikan berkas-berkas dan data secara aman dengan siapa saja, pada platform apapun. Informasi Anda akan tetap terenkripsi dari ujung-ke-ujung sembari membatasi paparan.", + "message": "Bagikan berkas-berkas dan data secara aman dengan siapa saja, pada platform apa pun. Informasi Anda akan tetap terenkripsi dari ujung ke ujung sembari membatasi paparan.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "inputRequired": { @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Pilih koleksi" }, - "importTargetHint": { - "message": "Pilih pilihan ini jika Anda ingin isi dari berkas yang diimpor dipindah ke $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Berkas berisi benda-benda yang belum ditetapkan." @@ -5575,9 +5571,13 @@ "description": "'WebAssembly' is a technical term and should not be translated." }, "showMore": { - "message": "Show more" + "message": "Tampilkan lebih banyak" }, "showLess": { - "message": "Show less" + "message": "Tampilkan lebih sedikit" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index 4e1c1d63e50..4742b7c6433 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Seleziona una raccolta" }, - "importTargetHint": { - "message": "Seleziona questa opzione se vuoi che i contenuti del file di importazione siano spostati in una $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Seleziona questa opzione se vuoi che i contenuti dell'importazione siano salvati in una raccolta" + }, + "importTargetHintFolder": { + "message": "Seleziona questa opzione se vuoi che i contenuti dell'importazione siano salvati in una cartella" }, "importUnassignedItemsError": { "message": "Il file contiene elementi non assegnati." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Mostra di meno" + }, + "moreBreadcrumbs": { + "message": "Ulteriori segmenti", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index 9370a3ae6b1..174c13d64ce 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "コレクションを選択" }, - "importTargetHint": { - "message": "インポートしたファイルコンテンツを $DESTINATION$ に移動したい場合は、このオプションを選択してください。", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "割り当てられていないアイテムがファイルに含まれています。" @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json index 6bbdb6f67f3..a71f9a9d0e0 100644 --- a/apps/browser/src/_locales/ka/messages.json +++ b/apps/browser/src/_locales/ka/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "აირჩიეთ კოლექცია" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json index d076ef01ef2..9170fd20734 100644 --- a/apps/browser/src/_locales/km/messages.json +++ b/apps/browser/src/_locales/km/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json index f4ab488884a..279c5b28824 100644 --- a/apps/browser/src/_locales/kn/messages.json +++ b/apps/browser/src/_locales/kn/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index 50725e73064..d39f111101b 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "컬렉션 선택" }, - "importTargetHint": { - "message": "가져온 파일의 내용을 $DESTINATION$로 이동하려면 이 옵션을 선택하세요.", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "파일에 할당되지 않은 항목이 포함되어 있습니다." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json index fa53a42a4b7..913d442c88f 100644 --- a/apps/browser/src/_locales/lt/messages.json +++ b/apps/browser/src/_locales/lt/messages.json @@ -3,14 +3,14 @@ "message": "Bitwarden" }, "appLogoLabel": { - "message": "Bitwarden logotipas" + "message": "„Bitwarden“ logotipas" }, "extName": { "message": "„Bitwarden“ slaptažodžių tvarkyklė", "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "Namuose, darbe ar kelyje, Bitwarden apsaugo jūsų slaptažodžius, raktažodžius ir svarbią informaciją", + "message": "Namuose, darbe ar kelyje, „Bitwarden“ apsaugo jūsų slaptažodžius, raktažodžius ir svarbią informaciją", "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { @@ -23,13 +23,13 @@ "message": "Sukurti paskyrą" }, "newToBitwarden": { - "message": "Pirmą kartą Bitwarden?" + "message": "Pirmą kartą „Bitwarden“?" }, "logInWithPasskey": { "message": "Prisijungti naudojant prieigos raktą" }, "useSingleSignOn": { - "message": "Use single sign-on" + "message": "Naudoti vieningo prisijungimo sistemą" }, "welcomeBack": { "message": "Sveiki sugrįžę" @@ -38,7 +38,7 @@ "message": "Nustatyti stiprų slaptažodį" }, "finishCreatingYourAccountBySettingAPassword": { - "message": "Baigkite kurti paskyrą nustatydami slaptažodį" + "message": "Baikite kurti paskyrą nustatydami slaptažodį" }, "enterpriseSingleSignOn": { "message": "Vienkartinis įmonės prisijungimas" @@ -59,10 +59,10 @@ "message": "Pagrindinis slaptažodis" }, "masterPassDesc": { - "message": "Pagrindinis slaptažodis yra slaptažodis, kurį naudojate norėdami pasiekti savo saugyklą. Labai svarbu nepamiršti pagrindinio slaptažodžio. Nėra galimybių atkurti slaptažodį, jei jį pamiršite." + "message": "Pagrindinis slaptažodis yra slaptažodis, kurį naudojate norėdami pasiekti savo saugyklą. Labai svarbu nepamiršti pagrindinio slaptažodžio. Nėra galimybių atkurti slaptažodžio, jei jį pamiršite." }, "masterPassHintDesc": { - "message": "Pagrindinio slaptažodžio užuomina gali padėti Jums prisiminti slaptažodį, jei jį pamiršite." + "message": "Pagrindinio slaptažodžio užuomina gali padėti jums prisiminti slaptažodį, jei jį pamiršite." }, "masterPassHintText": { "message": "Jei pamiršote slaptažodį, slaptažodžio užuomina gali būti išsiųsta į jūsų el. paštą. $CURRENT$ / $MAXIMUM$ didžiausias simbolių skaičius.", @@ -105,7 +105,7 @@ } }, "finishJoiningThisOrganizationBySettingAMasterPassword": { - "message": "Baigėte prisijungimą prie organizacijos nustatant pagrindinį slaptažodį." + "message": "Užbaikite prisijungimą prie organizacijos nustatydami pagrindinį slaptažodį." }, "tab": { "message": "Skirtukas" @@ -132,7 +132,7 @@ "message": "Kopijuoti slaptažodį" }, "copyPassphrase": { - "message": "Kopijuoti slaptažodžio frazę" + "message": "Kopijuoti slaptą frazę" }, "copyNote": { "message": "Kopijuoti pastabą" @@ -156,13 +156,13 @@ "message": "Kopijuoti įmonę" }, "copySSN": { - "message": "Kopijuoti socialinės apsaugos numerį" + "message": "Kopijuoti asmens kodo numerį" }, "copyPassportNumber": { "message": "Kopijuoti paso numerį" }, "copyLicenseNumber": { - "message": "Kopijuoti licenzijos numerį" + "message": "Kopijuoti licencijos numerį" }, "copyPrivateKey": { "message": "Kopijuoti privatų raktą" @@ -193,7 +193,7 @@ "description": "Copy to clipboard" }, "fill": { - "message": "Fill", + "message": "Užpildyti", "description": "This string is used on the vault page to indicate autofilling. Horizontal space is limited in the interface here so try and keep translations as concise as possible." }, "autoFill": { @@ -209,10 +209,10 @@ "message": "Tapatybės automatinis užpildymas" }, "fillVerificationCode": { - "message": "Fill verification code" + "message": "Užpildyti patvirtinimo kodą" }, "fillVerificationCodeAria": { - "message": "Fill Verification Code", + "message": "Užpildyti patvirtinimo kodą", "description": "Aria label for the heading displayed the inline menu for totp code autofill" }, "generatePasswordCopied": { @@ -240,10 +240,10 @@ "message": "Pridėti tapatybę" }, "unlockVaultMenu": { - "message": "Atrakinti Jūsų saugyklą" + "message": "Atrakinti jūsų saugyklą" }, "loginToVaultMenu": { - "message": "Prisijungti prie Jūsų saugyklos" + "message": "Prisijungti prie jūsų saugyklos" }, "autoFillInfo": { "message": "Nėra galimų prisijungimų prie dabartinio naršyklės skirtuko." @@ -255,16 +255,16 @@ "message": "Pridėti elementą" }, "accountEmail": { - "message": "Account email" + "message": "Paskyros el. paštas" }, "requestHint": { - "message": "Request hint" + "message": "Duoti užuominą" }, "requestPasswordHint": { - "message": "Request password hint" + "message": "Duoti slaptažodžio užuominą" }, "enterYourAccountEmailAddressAndYourPasswordHintWillBeSentToYou": { - "message": "Enter your account email address and your password hint will be sent to you" + "message": "Įveskite savo paskyros el. pašą ir jūsų slaptažodžio užuomina bus atsiųsta jums" }, "getMasterPasswordHint": { "message": "Gauti pagrindinio slaptažodžio užuominą" @@ -291,25 +291,25 @@ "message": "Keisti pagrindinį slaptažodį" }, "continueToWebApp": { - "message": "Tęsti į žiniatinklio programėlę?" + "message": "Tęsti į žiniatinklio programą?" }, "continueToWebAppDesc": { - "message": "Atraskite daugiau savo Bitwarden paskyros funkcijų web programoje." + "message": "Atraskite daugiau savo „Bitwarden“ paskyros funkcijų žiniatinklio programoje." }, "continueToHelpCenter": { "message": "Eiti į pagalbos centrą?" }, "continueToHelpCenterDesc": { - "message": "Pagalbos Centre sužinokite daugiau kaip naudotis Bitwarden." + "message": "Pagalbos centre sužinokite daugiau, kaip naudotis „Bitwarden“." }, "continueToBrowserExtensionStore": { "message": "Eiti į naršyklės plėtinių svetainę?" }, "continueToBrowserExtensionStoreDesc": { - "message": "Padėkite kitiems sužinoti ar Bitwarden yra jiems tinkamas. Apsilankykite naršyklės plėtinių svetainėje ir įvertinkite Bitwarden." + "message": "Padėkite kitiems sužinoti ar B„itwarden“ yra jiems tinkamas. Apsilankykite naršyklės plėtinių svetainėje ir įvertinkite „Bitwarden“." }, "changeMasterPasswordOnWebConfirmation": { - "message": "Pagrindinį slaptažodį galite pakeisti „Bitwarden“ žiniatinklio programėlėje." + "message": "Pagrindinį slaptažodį galite pakeisti „Bitwarden“ žiniatinklio programoje." }, "fingerprintPhrase": { "message": "Pirštų atspaudų frazė", @@ -383,7 +383,7 @@ "message": "Redaguoti aplankalą" }, "editFolderWithName": { - "message": "Edit folder: $FOLDERNAME$", + "message": "Redaguoti aplanką: $FOLDERNAME$", "placeholders": { "foldername": { "content": "$1", @@ -392,10 +392,10 @@ } }, "newFolder": { - "message": "New folder" + "message": "Naujas aplankas" }, "folderName": { - "message": "Folder name" + "message": "Aplanko vardas" }, "folderHintText": { "message": "Nest a folder by adding the parent folder's name followed by a “/”. Example: Social/Forums" @@ -677,7 +677,7 @@ "message": "Your account is locked" }, "or": { - "message": "or" + "message": "arba" }, "unlock": { "message": "Atrakinti" @@ -702,7 +702,7 @@ "message": "Atsijungta nuo saugyklos" }, "vaultTimeout1": { - "message": "Timeout" + "message": "Skirtas laikas" }, "lockNow": { "message": "Užrakinti dabar" @@ -799,10 +799,10 @@ "message": "Jūsų paskyra sukurta! Galite prisijungti." }, "newAccountCreated2": { - "message": "Your new account has been created!" + "message": "Jūsų nauja paskyra buvo sukurta!" }, "youHaveBeenLoggedIn": { - "message": "You have been logged in!" + "message": "Jūs prisijungėte!" }, "youSuccessfullyLoggedIn": { "message": "Jūs sėkmingai prisijungėte" @@ -845,7 +845,7 @@ "message": "Nuskaitykite autentifikatoriaus QR kodą iš dabartinio tinklalapio" }, "totpHelperTitle": { - "message": "Make 2-step verification seamless" + "message": "Padaryti dviejų veiksnių patvirtinimą sklandų" }, "totpHelper": { "message": "Bitwarden can store and fill 2-step verification codes. Copy and paste the key into this field." @@ -872,19 +872,19 @@ "message": "Prisijungti" }, "logInToBitwarden": { - "message": "Log in to Bitwarden" + "message": "Prisijungti prie „Bitwarden“" }, "enterTheCodeSentToYourEmail": { - "message": "Enter the code sent to your email" + "message": "Įveskite kodą išsiųstą jums el. paštu" }, "enterTheCodeFromYourAuthenticatorApp": { - "message": "Enter the code from your authenticator app" + "message": "Įveskite kodą iš autentifikacijos programėlės" }, "pressYourYubiKeyToAuthenticate": { - "message": "Press your YubiKey to authenticate" + "message": "Palieskite savo „YubiKey“, kad autentifikuotumėtės" }, "duoTwoFactorRequiredPageSubtitle": { - "message": "Duo two-step login is required for your account. Follow the steps below to finish logging in." + "message": "„Duo“ dviejų veiksnių prisijungimas yra privalomas jūsų paskyrai. Sekite žingsnius žemiau, kad užbaigtumėte prisijungimą." }, "followTheStepsBelowToFinishLoggingIn": { "message": "Follow the steps below to finish logging in." @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Pasirinkti rinkinį" }, - "importTargetHint": { - "message": "Pasirinkite šį pasirinkimą, jei norite, jog importuoto failo turinys, būtų perkeltas į $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Faile yra nepriskirtų elementų." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index 68d5a0db2e3..14bf2293c41 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Atlasīt krājumu" }, - "importTargetHint": { - "message": "Šī iespēja jāatlasa, ja ir vēlēšanās ievietotās datnes saturu pārvietot uz $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Šī iespēja jāatlasa, ja ir vēlēšanās ievietotās datnes saturu ievietot krājumā" + }, + "importTargetHintFolder": { + "message": "Šī iespēja jāatlasa, ja ir vēlēšanās ievietotās datnes saturu ievietot mapē" }, "importUnassignedItemsError": { "message": "Datne satur nepiešķirtus vienumus." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Rādīt mazāk" + }, + "moreBreadcrumbs": { + "message": "Vairāk norāžu", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json index ca1bbc69297..55abe605aa7 100644 --- a/apps/browser/src/_locales/ml/messages.json +++ b/apps/browser/src/_locales/ml/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/mr/messages.json b/apps/browser/src/_locales/mr/messages.json index 70059b1552e..0c2336ab264 100644 --- a/apps/browser/src/_locales/mr/messages.json +++ b/apps/browser/src/_locales/mr/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/my/messages.json b/apps/browser/src/_locales/my/messages.json index d076ef01ef2..9170fd20734 100644 --- a/apps/browser/src/_locales/my/messages.json +++ b/apps/browser/src/_locales/my/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json index 9e617957dc8..b27422f36a1 100644 --- a/apps/browser/src/_locales/nb/messages.json +++ b/apps/browser/src/_locales/nb/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Velg en samling" }, - "importTargetHint": { - "message": "Velg dette alternativet hvis du vil flytte den importerte filens innhold til en $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Filen inneholder utildelte elementer." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ne/messages.json b/apps/browser/src/_locales/ne/messages.json index d076ef01ef2..9170fd20734 100644 --- a/apps/browser/src/_locales/ne/messages.json +++ b/apps/browser/src/_locales/ne/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json index 4b38d8491aa..c01d1edf217 100644 --- a/apps/browser/src/_locales/nl/messages.json +++ b/apps/browser/src/_locales/nl/messages.json @@ -1022,7 +1022,7 @@ "message": "Opslaan in kluisopties" }, "addLoginNotificationDesc": { - "message": "\"Melding bij nieuwe login\" vraagt automatisch om nieuwe sites in de kluis op te slaan wanneer je ergens voor de eerste keer inlogt." + "message": "Vraag om een item toe te voegen als deze niet in je kluis is gevonden." }, "addLoginNotificationDescAlt": { "message": "Vraag om een item toe te voegen als het niet is gevonden is je kluis. Dit geld voor alle ingelogde accounts." @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Collectie selecteren" }, - "importTargetHint": { - "message": "Kies deze optie als je de geïmporteerde bestandsinhoud wilt verplaatsen naar een $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Kies deze optie als je de geïmporteerde bestandsinhoud naar een collectie wilt verplaatsen" + }, + "importTargetHintFolder": { + "message": "Kies deze optie als je de geïmporteerde bestandsinhoud naar een map wilt verplaatsen" }, "importUnassignedItemsError": { "message": "Bestand bevat niet-toegewezen items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Minder weergeven" + }, + "moreBreadcrumbs": { + "message": "Meer broodkruimels", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json index d076ef01ef2..9170fd20734 100644 --- a/apps/browser/src/_locales/nn/messages.json +++ b/apps/browser/src/_locales/nn/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/or/messages.json b/apps/browser/src/_locales/or/messages.json index d076ef01ef2..9170fd20734 100644 --- a/apps/browser/src/_locales/or/messages.json +++ b/apps/browser/src/_locales/or/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index 97875409529..71e07ceb352 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -270,7 +270,7 @@ "message": "Uzyskaj podpowiedź do hasła głównego" }, "continue": { - "message": "Kontynuuj" + "message": "Przejdź" }, "sendVerificationCode": { "message": "Wyślij kod weryfikacyjny na adres e-mail" @@ -1022,10 +1022,10 @@ "message": "Opcje zapisywania w sejfie" }, "addLoginNotificationDesc": { - "message": "Proponuj dodanie elementu, jeśli nie ma go w sejfie." + "message": "Proponuj zapisywanie danych logowania, jeśli nie ma ich w sejfie." }, "addLoginNotificationDescAlt": { - "message": "Proponuj dodanie elementu, jeśli nie ma go w sejfie. Dotyczy wszystkich zalogowanych kont." + "message": "Proponuj zapisywanie danych logowania, jeśli nie ma ich w sejfie. Dotyczy wszystkich zalogowanych kont." }, "showCardsInVaultViewV2": { "message": "Zawsze pokazuj karty w sugestiach autouzupełniania" @@ -1405,7 +1405,7 @@ "message": "Specjalne opcje logowania dwustopniowego, takie jak YubiKey i Duo." }, "ppremiumSignUpReports": { - "message": "Raporty bezpieczeństwa haseł, stanu konta i raporty wycieków danych, aby Twoje dane były bezpieczne." + "message": "Raporty bezpieczeństwa haseł, konta i wycieków danych, aby Twoje dane były bezpieczne." }, "ppremiumSignUpTotp": { "message": "Generator kodów weryfikacyjnych TOTP dla danych logowania w sejfie." @@ -1684,7 +1684,7 @@ "message": "Możesz wyłączyć autouzupełnianie po załadowaniu strony dla poszczególnych elementów w opcjach konkretnych elementów." }, "itemAutoFillOnPageLoad": { - "message": "Automatycznie uzupełniaj po załadowaniu strony (jeśli włączono w opcjach)" + "message": "Uzupełniaj po załadowaniu strony (jeśli włączono w opcjach)" }, "autoFillOnPageLoadUseDefault": { "message": "Użyj domyślnego ustawienia" @@ -1758,7 +1758,7 @@ "message": "Kliknięcie poza okno, w celu sprawdzenia wiadomość z kodem weryfikacyjnym spowoduje, że zostanie ono zamknięte. Czy chcesz otworzyć nowe okno tak, aby się nie zamknęło?" }, "popupU2fCloseMessage": { - "message": "Ta przeglądarka nie może przetworzyć żądania U2F w wyskakującym oknie. Czy chcesz otworzyć nowe okno przeglądarki, aby zalogować się przy pomocy klucza U2F?" + "message": "Przeglądarka nie może przetworzyć żądań U2F. Czy chcesz otworzyć nowe okno, aby zalogować się za pomocą U2F?" }, "enableFavicon": { "message": "Pokaż ikony stron internetowych" @@ -3467,7 +3467,7 @@ "message": "Prośba została wysłana" }, "loginRequestApprovedForEmailOnDevice": { - "message": "Logowanie potwierdzone dla $EMAIL$ na $DEVICE$", + "message": "Potwierdzono logowanie $EMAIL$ ($DEVICE$)", "placeholders": { "email": { "content": "$1", @@ -3480,7 +3480,7 @@ } }, "youDeniedLoginAttemptFromAnotherDevice": { - "message": "Odrzucono próby logowania z innego urządzenia. Jeśli to naprawdę Ty, spróbuj ponownie zalogować się za pomocą urządzenia." + "message": "Odrzucono próbę logowania z innego urządzenia. Zaloguj się ponownie z tego urządzenia." }, "device": { "message": "Urządzenie" @@ -3773,7 +3773,7 @@ "message": "Organizacja nie jest zaufana" }, "emergencyAccessTrustWarning": { - "message": "Dla bezpieczeństwa Twojego konta potwierdź tylko, jeśli przyznano temu użytkownikowi dostęp awaryjny i jego odcisk palca pasuje do tego, co widnieje na jego koncie" + "message": "Potwierdź tylko wtedy, gdy chcesz przyznać użytkownikowi dostęp awaryjny i jego unikalny identyfikator konta jest prawidłowy." }, "orgTrustWarning": { "message": "Kontynuuj tylko wtedy, gdy jesteś członkiem organizacji, masz włączone odzyskiwanie konta, a unikalny identyfikator pasuje do organizacji." @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Wybierz kolekcję" }, - "importTargetHint": { - "message": "Wybierz tę opcję, jeśli chcesz przenieść dane do $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Wybierz tę opcję, jeśli chcesz przenieść dane do kolekcji" + }, + "importTargetHintFolder": { + "message": "Wybierz tę opcję, jeśli chcesz przenieść dane do folderu" }, "importUnassignedItemsError": { "message": "Plik zawiera nieprzypisane elementy." @@ -4185,7 +4181,7 @@ "message": "Klucz dostępu" }, "accessing": { - "message": "Logowanie na" + "message": "Serwer" }, "loggedInExclamation": { "message": "Zalogowano!" @@ -4197,7 +4193,7 @@ "message": "Klucz dostępu nie zostanie skopiowany do sklonowanego elementu. Czy chcesz kontynuować klonowanie elementu?" }, "passkeyFeatureIsNotImplementedForAccountsWithoutMasterPassword": { - "message": "Weryfikacja jest wymagana przez stronę inicjującą. Ta funkcja nie jest jeszcze zaimplementowana dla kont bez hasła głównego." + "message": "Weryfikacja jest wymagana przez stronę inicjującą. Ta funkcja nie jest jeszcze dostępna dla kont bez hasła głównego." }, "logInWithPasskeyQuestion": { "message": "Zalogować się kluczem dostępu?" @@ -4439,7 +4435,7 @@ "description": "Title for the dialog that appears when the user has not granted the extension permission to set privacy settings" }, "privacyPermissionAdditionNotGrantedDescription": { - "message": "Musisz przyznać Bitwarden uprawnienia do prywatności przeglądarki, aby ustawić go jako domyślnego menedżera haseł.", + "message": "Aby ustawić Bitwarden jako domyślny menedżer haseł, przyznaj rozszerzeniu uprawnienie do zmiany ustawień prywatności.", "description": "Description for the dialog that appears when the user has not granted the extension permission to set privacy settings" }, "makeDefault": { @@ -4990,7 +4986,7 @@ } }, "reorderToggleButton": { - "message": "Zmień kolejność pola $LABEL$. Użyj klawiszy ze strzałkami, aby przenieść element w górę lub w dół.", + "message": "Reorder $LABEL$. Use arrow key to move item up or down.", "placeholders": { "label": { "content": "$1", @@ -4999,7 +4995,7 @@ } }, "reorderWebsiteUriButton": { - "message": "Zmień kolejność URI stron internetowych. Użyj klawiszy ze strzałkami, aby przenieść element w górę lub w dół." + "message": "Zmień kolejność stron internetowych. Użyj klawiszy ze strzałkami, aby przenieść element w górę lub w dół." }, "reorderFieldUp": { "message": "Pole $LABEL$ zostało przeniesione w górę. Pozycja $INDEX$ z $LENGTH$", @@ -5427,7 +5423,7 @@ "message": "Klucz SSH został zaimportowany" }, "cannotRemoveViewOnlyCollections": { - "message": "Nie można usunąć kolekcji z uprawnieniami tylko do przeglądania: $COLLECTIONS$", + "message": "Nie możesz usunąć następujących kolekcji z uprawnieniami tylko do odczytu: $COLLECTIONS$", "placeholders": { "collections": { "content": "$1", @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Pokaż mniej" + }, + "moreBreadcrumbs": { + "message": "Więcej nawigacji", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index ac5afdc9fce..ef13c22f3dc 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -1037,7 +1037,7 @@ "message": "Exibir itens de cartão em páginas com abas para simplificar o preenchimento automático" }, "showIdentitiesInVaultViewV2": { - "message": "Sempre mostrar identidades como sugestões de preenchimento automático na Tela do Cofre" + "message": "Sempre mostrar identidades como sugestões de preenchimento automático na tela do Cofre" }, "showIdentitiesCurrentTab": { "message": "Exibir Identidades na Aba Atual" @@ -3785,11 +3785,11 @@ "message": "Trust user" }, "sendsTitleNoItems": { - "message": "Envie informações sensíveis com segurança", + "message": "Envie informações confidencias, com segurança", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendsBodyNoItems": { - "message": "Compartilhe arquivos e dados com segurança, com qualquer pessoa e em qualquer plataforma. Suas informações ficarão sempre criptografadas de ponta a ponta, garantindo exposição mínima.", + "message": "Compartilhe arquivos e dados de forma segura com qualquer pessoa, em qualquer plataforma. Suas informações permanecerão criptografadas de ponta a ponta enquanto limitam a exposição.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "inputRequired": { @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Selecione uma coleção" }, - "importTargetHint": { - "message": "Selecione esta opção se você quer o conteúdo do arquivo importado movido para $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Arquivo contém itens não atribuídos." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json index d3ce5ec3e48..5ab801b268f 100644 --- a/apps/browser/src/_locales/pt_PT/messages.json +++ b/apps/browser/src/_locales/pt_PT/messages.json @@ -65,7 +65,7 @@ "message": "Uma dica da palavra-passe mestra pode ajudá-lo a lembrar-se da sua palavra-passe, caso se esqueça dela." }, "masterPassHintText": { - "message": "Se se esquecer da sua palavra-passe, a dica da palavra-passe pode ser enviada para o seu e-mail. Máximo de $CURRENT$/$MAXIMUM$ carateres.", + "message": "Se se esquecer da sua palavra-passe, a dica da palavra-passe pode ser enviada para o seu e-mail. Máximo de $CURRENT$/$MAXIMUM$ caracteres.", "placeholders": { "current": { "content": "$1", @@ -490,7 +490,7 @@ "description": "Card header for password generator include block" }, "uppercaseDescription": { - "message": "Incluir carateres em maiúsculas", + "message": "Incluir caracteres em maiúsculas", "description": "Tooltip for the password generator uppercase character checkbox" }, "uppercaseLabel": { @@ -498,7 +498,7 @@ "description": "Label for the password generator uppercase character checkbox" }, "lowercaseDescription": { - "message": "Incluir carateres em minúsculas", + "message": "Incluir caracteres em minúsculas", "description": "Full description for the password generator lowercase character checkbox" }, "lowercaseLabel": { @@ -514,7 +514,7 @@ "description": "Label for the password generator numbers checkbox" }, "specialCharactersDescription": { - "message": "Incluir carateres especiais", + "message": "Incluir caracteres especiais", "description": "Full description for the password generator special characters checkbox" }, "numWords": { @@ -534,10 +534,10 @@ "message": "Mínimo de números" }, "minSpecial": { - "message": "Mínimo de carateres especiais" + "message": "Mínimo de caracteres especiais" }, "avoidAmbiguous": { - "message": "Evitar carateres ambíguos", + "message": "Evitar caracteres ambíguos", "description": "Label for the avoid ambiguous characters checkbox." }, "generatorPolicyInEffect": { @@ -783,7 +783,7 @@ "message": "É necessário reescrever a palavra-passe mestra." }, "masterPasswordMinlength": { - "message": "A palavra-passe mestra deve ter pelo menos $VALUE$ carateres.", + "message": "A palavra-passe mestra deve ter pelo menos $VALUE$ caracteres.", "description": "The Master Password must be at least a specific number of characters long.", "placeholders": { "value": { @@ -2344,16 +2344,16 @@ } }, "policyInEffectUppercase": { - "message": "Contém um ou mais carateres em maiúsculas" + "message": "Contém um ou mais caracteres em maiúsculas" }, "policyInEffectLowercase": { - "message": "Contém um ou mais carateres em minúsculas" + "message": "Contém um ou mais caracteres em minúsculas" }, "policyInEffectNumbers": { "message": "Contém um ou mais números" }, "policyInEffectSpecial": { - "message": "Contém um ou mais dos seguintes carateres especiais $CHARS$", + "message": "Contém um ou mais dos seguintes caracteres especiais $CHARS$", "placeholders": { "chars": { "content": "$1", @@ -3097,7 +3097,7 @@ "message": "Saiu da organização." }, "toggleCharacterCount": { - "message": "Mostrar/ocultar contagem de carateres" + "message": "Mostrar/ocultar contagem de caracteres" }, "sessionTimeout": { "message": "A sua sessão expirou. Por favor, volte atrás e tente iniciar sessão novamente." @@ -3173,7 +3173,7 @@ } }, "passwordLengthRecommendationHint": { - "message": " Utilize $RECOMMENDED$ carateres ou mais para gerar uma palavra-passe forte.", + "message": " Utilize $RECOMMENDED$ caracteres ou mais para gerar uma palavra-passe forte.", "description": "Appended to `spinboxBoundariesHint` to recommend a length to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -3513,7 +3513,7 @@ "message": "A sua palavra-passe mestra não pode ser recuperada se a esquecer!" }, "characterMinimum": { - "message": "$LENGTH$ carateres no mínimo", + "message": "$LENGTH$ caracteres no mínimo", "placeholders": { "length": { "content": "$1", @@ -3802,7 +3802,7 @@ "message": "Procurar" }, "inputMinLength": { - "message": "O campo deve ter pelo menos $COUNT$ carateres.", + "message": "O campo deve ter pelo menos $COUNT$ caracteres.", "placeholders": { "count": { "content": "$1", @@ -3811,7 +3811,7 @@ } }, "inputMaxLength": { - "message": "O campo não pode exceder os $COUNT$ carateres de comprimento.", + "message": "O campo não pode exceder os $COUNT$ caracteres de comprimento.", "placeholders": { "count": { "content": "$1", @@ -3820,7 +3820,7 @@ } }, "inputForbiddenCharacters": { - "message": "Não são permitidos os seguintes carateres: $CHARACTERS$", + "message": "Não são permitidos os seguintes caracteres: $CHARACTERS$", "placeholders": { "characters": { "content": "$1", @@ -3829,7 +3829,7 @@ } }, "inputMinValue": { - "message": "O valor do campo tem de ser, pelo menos, $MIN$ carateres.", + "message": "O valor do campo tem de ser, pelo menos, $MIN$ caracteres.", "placeholders": { "min": { "content": "$1", @@ -3838,7 +3838,7 @@ } }, "inputMaxValue": { - "message": "O valor do campo não pode exceder os $MAX$ carateres.", + "message": "O valor do campo não pode exceder os $MAX$ caracteres.", "placeholders": { "max": { "content": "$1", @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Selecionar uma coleção" }, - "importTargetHint": { - "message": "Selecione esta opção se pretender que o conteúdo do ficheiro importado seja transferido para $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Selecione esta opção se pretender que o conteúdo do ficheiro importado seja transferido para uma coleção" + }, + "importTargetHintFolder": { + "message": "Selecione esta opção se pretender que o conteúdo do ficheiro importado seja transferido para uma pasta" }, "importUnassignedItemsError": { "message": "O ficheiro contém itens não atribuídos." @@ -5163,10 +5159,10 @@ "message": "Ficheiro guardado no dispositivo. Gira-o a partir das transferências do seu dispositivo." }, "showCharacterCount": { - "message": "Mostrar contagem de carateres" + "message": "Mostrar contagem de caracteres" }, "hideCharacterCount": { - "message": "Ocultar contagem de carateres" + "message": "Ocultar contagem de caracteres" }, "itemsInTrash": { "message": "Itens no lixo" @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Mostrar menos" + }, + "moreBreadcrumbs": { + "message": "Mais da navegação estrutural", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json index 741b491da13..d2769583bcb 100644 --- a/apps/browser/src/_locales/ro/messages.json +++ b/apps/browser/src/_locales/ro/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json index 88fa89ac73e..d18cf24eb9b 100644 --- a/apps/browser/src/_locales/ru/messages.json +++ b/apps/browser/src/_locales/ru/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Выберите коллекцию" }, - "importTargetHint": { - "message": "Выберите эту опцию, если хотите, чтобы содержимое импортированного файла было перемещено в $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Выберите эту опцию, если хотите, чтобы содержимое импортированного файла было перемещено в коллекцию" + }, + "importTargetHintFolder": { + "message": "Выберите эту опцию, если хотите, чтобы содержимое импортированного файла было перемещено в папку" }, "importUnassignedItemsError": { "message": "Файл содержит неназначенные элементы." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Меньше" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json index dd2df6f309c..0e4a60b8261 100644 --- a/apps/browser/src/_locales/si/messages.json +++ b/apps/browser/src/_locales/si/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json index e12a0c97ac4..98babaff777 100644 --- a/apps/browser/src/_locales/sk/messages.json +++ b/apps/browser/src/_locales/sk/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Vyberte zbierku" }, - "importTargetHint": { - "message": "Zvoľte túto možnosť, ak chcete obsah importovaného súboru presunúť do $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Zvoľte túto možnosť, ak chcete obsah importovaného súboru presunúť do zbierky" + }, + "importTargetHintFolder": { + "message": "Zvoľte túto možnosť, ak chcete obsah importovaného súboru presunúť do priečinka" }, "importUnassignedItemsError": { "message": "Súbor obsahuje nepriradené položky." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Zobraziť menej" + }, + "moreBreadcrumbs": { + "message": "Viac", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index 3af24b85889..0a7387ee831 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index 12d0c5b015e..e058a805533 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Изабери колекцију" }, - "importTargetHint": { - "message": "Изаберите ову опцију ако желите да се садржај увезене датотеке премести у $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Датотека садржи недодељене ставке." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index 1174b6ac077..d6a0b691572 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Välj en samling" }, - "importTargetHint": { - "message": "Välj det här alternativet om du vill att innehållet i den importerade filen ska flyttas till en $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Välj detta alternativ om du vill att innehållet i den importerade filen ska flyttas till en samling" + }, + "importTargetHintFolder": { + "message": "Välj detta alternativ om du vill att innehållet i den importerade filen ska flyttas till en mapp" }, "importUnassignedItemsError": { "message": "Filen innehåller otilldelade objekt." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Visa mindre" + }, + "moreBreadcrumbs": { + "message": "Fler länkstigar", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/te/messages.json b/apps/browser/src/_locales/te/messages.json index d076ef01ef2..9170fd20734 100644 --- a/apps/browser/src/_locales/te/messages.json +++ b/apps/browser/src/_locales/te/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json index 2cea91a424e..02eb0664472 100644 --- a/apps/browser/src/_locales/th/messages.json +++ b/apps/browser/src/_locales/th/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index 22a083959a9..4ed2fa9ef11 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Bir koleksiyon seçin" }, - "importTargetHint": { - "message": "İçe aktarılan dosya içeriklerinin $DESTINATION$ konumuna taşınmasını istiyorsanız bu seçeneği seçin", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "İçe aktarılan dosya içeriklerinin bir koleksiyona taşınmasını istiyorsanız bu seçeneği seçin" + }, + "importTargetHintFolder": { + "message": "İçe aktarılan dosya içeriklerinin bir klasöre taşınmasını istiyorsanız bu seçeneği seçin" }, "importUnassignedItemsError": { "message": "Dosya atanmamış öğeler içeriyor." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Daha az göster" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json index 537a9bfd5cf..79353e6af91 100644 --- a/apps/browser/src/_locales/uk/messages.json +++ b/apps/browser/src/_locales/uk/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Вибрати збірку" }, - "importTargetHint": { - "message": "Оберіть цю опцію, якщо ви хочете, щоб вміст імпортованого файлу було збережено в $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Файл містить непризначені записи." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Згорнути" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json index 7a596d7c23d..ed717455620 100644 --- a/apps/browser/src/_locales/vi/messages.json +++ b/apps/browser/src/_locales/vi/messages.json @@ -216,7 +216,7 @@ "description": "Aria label for the heading displayed the inline menu for totp code autofill" }, "generatePasswordCopied": { - "message": "Tạo mật khẩu (đã sao chép)" + "message": "Tạo mật khẩu (cũng sao chép)" }, "copyElementIdentifier": { "message": "Sao chép tên trường tùy chỉnh" @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "Chọn bộ sưu tập" }, - "importTargetHint": { - "message": "Chọn tùy chọn này nếu bạn muốn nội dung của tệp đã nhập được di chuyển đến $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Tập tin chứa các mục không xác định." @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Thu gọn" + }, + "moreBreadcrumbs": { + "message": "Thêm mục điều hướng", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index fff87a949ce..2d2591b403a 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "选择一个集合" }, - "importTargetHint": { - "message": "如果您希望将导入的文件内容移动到某个 $DESTINATION$,请选择此选项", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "如果希望将导入的文件内容移动到集合中,请选择此选项" + }, + "importTargetHintFolder": { + "message": "如果希望将导入的文件内容移动到文件夹中,请选择此选项" }, "importUnassignedItemsError": { "message": "文件包含未分配项目。" @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "显示更少" + }, + "moreBreadcrumbs": { + "message": "进一步的指引", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json index e8873d74e92..97ef68eb6c2 100644 --- a/apps/browser/src/_locales/zh_TW/messages.json +++ b/apps/browser/src/_locales/zh_TW/messages.json @@ -4131,15 +4131,11 @@ "selectImportCollection": { "message": "選擇一個分類" }, - "importTargetHint": { - "message": "如果您要將匯入檔案的內容移動到 $DESTINATION$,請選擇此選項", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "檔案包含未指派項目。" @@ -5579,5 +5575,9 @@ }, "showLess": { "message": "Show less" + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } From 825a9b2ccc7c73834755b5dba9cec42dacaf33b1 Mon Sep 17 00:00:00 2001 From: Github Actions Date: Mon, 25 Aug 2025 11:02:35 +0000 Subject: [PATCH 032/167] Bumped client version(s) --- apps/web/package.json | 2 +- package-lock.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 73e79d4f513..115a508aff9 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/web-vault", - "version": "2025.8.0", + "version": "2025.8.1", "scripts": { "build:oss": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" webpack", "build:bit": "cross-env NODE_OPTIONS=\"--max-old-space-size=8192\" webpack -c ../../bitwarden_license/bit-web/webpack.config.js", diff --git a/package-lock.json b/package-lock.json index 956bb34f873..de84620d5ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -291,7 +291,7 @@ }, "apps/web": { "name": "@bitwarden/web-vault", - "version": "2025.8.0" + "version": "2025.8.1" }, "libs/admin-console": { "name": "@bitwarden/admin-console", From dfcfe52d1eced9d345e5ff01052c8089227cabad Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 11:17:27 +0000 Subject: [PATCH 033/167] Autosync the updated translations (#16141) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/desktop/src/locales/af/messages.json | 12 +-- apps/desktop/src/locales/ar/messages.json | 12 +-- apps/desktop/src/locales/az/messages.json | 16 +-- apps/desktop/src/locales/be/messages.json | 12 +-- apps/desktop/src/locales/bg/messages.json | 12 +-- apps/desktop/src/locales/bn/messages.json | 12 +-- apps/desktop/src/locales/bs/messages.json | 28 ++--- apps/desktop/src/locales/ca/messages.json | 12 +-- apps/desktop/src/locales/cs/messages.json | 12 +-- apps/desktop/src/locales/cy/messages.json | 12 +-- apps/desktop/src/locales/da/messages.json | 12 +-- apps/desktop/src/locales/de/messages.json | 12 +-- apps/desktop/src/locales/el/messages.json | 12 +-- apps/desktop/src/locales/en_GB/messages.json | 12 +-- apps/desktop/src/locales/en_IN/messages.json | 12 +-- apps/desktop/src/locales/eo/messages.json | 12 +-- apps/desktop/src/locales/es/messages.json | 12 +-- apps/desktop/src/locales/et/messages.json | 12 +-- apps/desktop/src/locales/eu/messages.json | 12 +-- apps/desktop/src/locales/fa/messages.json | 12 +-- apps/desktop/src/locales/fi/messages.json | 12 +-- apps/desktop/src/locales/fil/messages.json | 12 +-- apps/desktop/src/locales/fr/messages.json | 12 +-- apps/desktop/src/locales/gl/messages.json | 12 +-- apps/desktop/src/locales/he/messages.json | 108 +++++++++---------- apps/desktop/src/locales/hi/messages.json | 12 +-- apps/desktop/src/locales/hr/messages.json | 12 +-- apps/desktop/src/locales/hu/messages.json | 12 +-- apps/desktop/src/locales/id/messages.json | 12 +-- apps/desktop/src/locales/it/messages.json | 18 ++-- apps/desktop/src/locales/ja/messages.json | 12 +-- apps/desktop/src/locales/ka/messages.json | 12 +-- apps/desktop/src/locales/km/messages.json | 12 +-- apps/desktop/src/locales/kn/messages.json | 12 +-- apps/desktop/src/locales/ko/messages.json | 12 +-- apps/desktop/src/locales/lt/messages.json | 12 +-- apps/desktop/src/locales/lv/messages.json | 18 ++-- apps/desktop/src/locales/me/messages.json | 12 +-- apps/desktop/src/locales/ml/messages.json | 12 +-- apps/desktop/src/locales/mr/messages.json | 12 +-- apps/desktop/src/locales/my/messages.json | 12 +-- apps/desktop/src/locales/nb/messages.json | 12 +-- apps/desktop/src/locales/ne/messages.json | 12 +-- apps/desktop/src/locales/nl/messages.json | 12 +-- apps/desktop/src/locales/nn/messages.json | 12 +-- apps/desktop/src/locales/or/messages.json | 12 +-- apps/desktop/src/locales/pl/messages.json | 34 +++--- apps/desktop/src/locales/pt_BR/messages.json | 12 +-- apps/desktop/src/locales/pt_PT/messages.json | 12 +-- apps/desktop/src/locales/ro/messages.json | 12 +-- apps/desktop/src/locales/ru/messages.json | 12 +-- apps/desktop/src/locales/si/messages.json | 12 +-- apps/desktop/src/locales/sk/messages.json | 12 +-- apps/desktop/src/locales/sl/messages.json | 12 +-- apps/desktop/src/locales/sr/messages.json | 12 +-- apps/desktop/src/locales/sv/messages.json | 18 ++-- apps/desktop/src/locales/te/messages.json | 12 +-- apps/desktop/src/locales/th/messages.json | 12 +-- apps/desktop/src/locales/tr/messages.json | 12 +-- apps/desktop/src/locales/uk/messages.json | 12 +-- apps/desktop/src/locales/vi/messages.json | 12 +-- apps/desktop/src/locales/zh_CN/messages.json | 16 +-- apps/desktop/src/locales/zh_TW/messages.json | 12 +-- 63 files changed, 458 insertions(+), 458 deletions(-) diff --git a/apps/desktop/src/locales/af/messages.json b/apps/desktop/src/locales/af/messages.json index aac699b6003..cce27510be0 100644 --- a/apps/desktop/src/locales/af/messages.json +++ b/apps/desktop/src/locales/af/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Aanhegsel is bewaar" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Lêer" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Vra vir Touch ID by lansering" }, - "requirePasswordOnStart": { - "message": "Vereis wagwoord of PIN wanneer toep geopen word" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/ar/messages.json b/apps/desktop/src/locales/ar/messages.json index 2692c061373..54277fdffa4 100644 --- a/apps/desktop/src/locales/ar/messages.json +++ b/apps/desktop/src/locales/ar/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "تم حفظ المرفق." }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "ملف" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "اطلب معرف اللمس عند التشغيل" }, - "requirePasswordOnStart": { - "message": "يتطلب كلمة مرور أو رقم التعريف الشخصي عند بدء التطبيق" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "قفل مع كلمة المرور الرئيسية عند إعادة تشغيل" }, diff --git a/apps/desktop/src/locales/az/messages.json b/apps/desktop/src/locales/az/messages.json index 9995bc3cbb3..d7793c28dd3 100644 --- a/apps/desktop/src/locales/az/messages.json +++ b/apps/desktop/src/locales/az/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Qoşma saxlanıldı." }, + "addAttachment": { + "message": "Qoşma əlavə et" + }, + "maxFileSizeSansPunctuation": { + "message": "Maksimal fayl həcmi 500 MB-dır" + }, "file": { "message": "Fayl" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Açılışda Touch ID-ni soruşun" }, - "requirePasswordOnStart": { - "message": "Tətbiq başladılanda parolu və ya PIN-i tələb et" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Tətbiq başladılanda parolu tələb et" - }, "lockWithMasterPassOnRestart1": { "message": "Yenidən başladılanda ana parol ilə kilidlə" }, @@ -3492,10 +3492,10 @@ "message": "Bir kolleksiya seçin" }, "importTargetHintCollection": { - "message": "Select this option if you want the imported file contents moved to a collection" + "message": "Daxilə köçürülən fayl məzmunlarının bir kolleksiyaya daşınmasını istəyirsinizsə bu variantı seçin" }, "importTargetHintFolder": { - "message": "Select this option if you want the imported file contents moved to a folder" + "message": "Daxilə köçürülən fayl məzmunlarının bir qovluğa daşınmasını istəyirsinizsə bu variantı seçin" }, "importUnassignedItemsError": { "message": "Faylda təyin edilməmiş elementlər var." diff --git a/apps/desktop/src/locales/be/messages.json b/apps/desktop/src/locales/be/messages.json index fbe6b098d8b..e4cd522aefa 100644 --- a/apps/desktop/src/locales/be/messages.json +++ b/apps/desktop/src/locales/be/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Далучэнне захавана." }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Файл" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Пытацца пра Touch ID пры запуску" }, - "requirePasswordOnStart": { - "message": "Патрабаваць пароль або PIN пры запуску праграмы" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/bg/messages.json b/apps/desktop/src/locales/bg/messages.json index 99434e6c992..e0590fcb0bb 100644 --- a/apps/desktop/src/locales/bg/messages.json +++ b/apps/desktop/src/locales/bg/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Прикаченият файл е запазен." }, + "addAttachment": { + "message": "Добавяне на прикачен файл" + }, + "maxFileSizeSansPunctuation": { + "message": "Максималният размер на файла е 500 MB" + }, "file": { "message": "Файл" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Питане за Touch ID при пускане" }, - "requirePasswordOnStart": { - "message": "Изискване на парола или ПИН при стартиране на приложението" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Изискване на парола при стартиране на приложението" - }, "lockWithMasterPassOnRestart1": { "message": "Заключване с главната парола при повторно пускане" }, diff --git a/apps/desktop/src/locales/bn/messages.json b/apps/desktop/src/locales/bn/messages.json index 36db3a37cce..b0ea7f40bb8 100644 --- a/apps/desktop/src/locales/bn/messages.json +++ b/apps/desktop/src/locales/bn/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "সংযুক্তিটি সংরক্ষণ করা হয়েছে।" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "ফাইল" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/bs/messages.json b/apps/desktop/src/locales/bs/messages.json index c745a150698..8163f9be864 100644 --- a/apps/desktop/src/locales/bs/messages.json +++ b/apps/desktop/src/locales/bs/messages.json @@ -24,13 +24,13 @@ "message": "Identitet" }, "typeNote": { - "message": "Note" + "message": "Napomena" }, "typeSecureNote": { "message": "Sigurna bilješka" }, "typeSshKey": { - "message": "SSH key" + "message": "SSH ključ" }, "folders": { "message": "Folderi" @@ -343,7 +343,7 @@ "message": "Mx" }, "dr": { - "message": "dr." + "message": "dr" }, "expirationMonth": { "message": "Mjesec isteka" @@ -700,13 +700,19 @@ "message": "Da li ste sigurni da želite obrisati priloženu datoteku?" }, "attachmentSaved": { - "message": "Priložena datoteka je spremljena." + "message": "Priložena datoteka je spremljena" + }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" }, "file": { "message": "Datoteka" }, "selectFile": { - "message": "Odaberite datoteku." + "message": "Odaberite datoteku" }, "maxFileSize": { "message": "Maksimalna veličina datoteke je 500 MB." @@ -997,7 +1003,7 @@ "message": "Koristi bilo koji WebAuthn omogućeni sigurnosni ključ za pristup svojem računu." }, "emailTitle": { - "message": "E-Mail " + "message": "E-Mail" }, "emailDescV2": { "message": "Enter a code sent to your email." @@ -1061,7 +1067,7 @@ "message": "URL adresa servera ikona" }, "environmentSaved": { - "message": "URL adrese okruženja su spremljene." + "message": "URL adrese okruženja su spremljene" }, "ok": { "message": "Uredu" @@ -1390,7 +1396,7 @@ "description": "Copy to clipboard" }, "checkForUpdates": { - "message": "Provjeri ima li ažuriranja" + "message": "Provjeri ima li ažuriranja…" }, "version": { "message": "Verzija $VERSION_NUM$", @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/ca/messages.json b/apps/desktop/src/locales/ca/messages.json index 0c03f554d33..e71ce2d1a26 100644 --- a/apps/desktop/src/locales/ca/messages.json +++ b/apps/desktop/src/locales/ca/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "S'ha guardat el fitxer adjunt." }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Fitxer" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Sol·liciteu Touch ID en iniciar" }, - "requirePasswordOnStart": { - "message": "Requereix contrasenya o PIN a l'inici de l'aplicació" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Bloqueja amb la contrasenya mestra en reiniciar" }, diff --git a/apps/desktop/src/locales/cs/messages.json b/apps/desktop/src/locales/cs/messages.json index 31952bc3812..279f1b2e698 100644 --- a/apps/desktop/src/locales/cs/messages.json +++ b/apps/desktop/src/locales/cs/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Příloha byla uložena" }, + "addAttachment": { + "message": "Přidat přílohu" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximální velikost souboru je 500 MB" + }, "file": { "message": "Soubor" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Požádat o Touch ID při spuštění aplikace" }, - "requirePasswordOnStart": { - "message": "Vyžadovat heslo nebo PIN při spuštění aplikace" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Vyžadovat heslo při spuštění aplikace" - }, "lockWithMasterPassOnRestart1": { "message": "Zamknout trezor při restartu pomocí hlavního hesla" }, diff --git a/apps/desktop/src/locales/cy/messages.json b/apps/desktop/src/locales/cy/messages.json index aa4c7c519a8..5509981bc14 100644 --- a/apps/desktop/src/locales/cy/messages.json +++ b/apps/desktop/src/locales/cy/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Attachment saved" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "File" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/da/messages.json b/apps/desktop/src/locales/da/messages.json index 43f1287ee3c..680f29a05d0 100644 --- a/apps/desktop/src/locales/da/messages.json +++ b/apps/desktop/src/locales/da/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Vedhæftning gemt" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Fil" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Anmod om Touch ID ved app-start" }, - "requirePasswordOnStart": { - "message": "Kræv adgangskode eller PIN-kode ved app-start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lås med hovedadgangskode ved genstart" }, diff --git a/apps/desktop/src/locales/de/messages.json b/apps/desktop/src/locales/de/messages.json index 94dd43c3499..c976db9c2ba 100644 --- a/apps/desktop/src/locales/de/messages.json +++ b/apps/desktop/src/locales/de/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Anhang gespeichert" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Datei" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Beim Start nach Touch ID fragen" }, - "requirePasswordOnStart": { - "message": "Passwort oder PIN beim Start der App verlangen" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Ein Passwort beim Starten der App verlangen" - }, "lockWithMasterPassOnRestart1": { "message": "Beim Neustart mit Master-Passwort sperren" }, diff --git a/apps/desktop/src/locales/el/messages.json b/apps/desktop/src/locales/el/messages.json index 6c93205d6eb..8bd66e22ac5 100644 --- a/apps/desktop/src/locales/el/messages.json +++ b/apps/desktop/src/locales/el/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Το συνημμένο αποθηκεύτηκε" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Αρχείο" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ερώτηση για το Touch ID κατά την εκκίνηση" }, - "requirePasswordOnStart": { - "message": "Να απαιτείται κωδικός πρόσβασης ή PIN κατά την εκκίνηση της εφαρμογής" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Κλείδωμα με τον κύριο κωδικό πρόσβασης κατά την επανεκκίνηση" }, diff --git a/apps/desktop/src/locales/en_GB/messages.json b/apps/desktop/src/locales/en_GB/messages.json index f82c493a646..8094de67ce9 100644 --- a/apps/desktop/src/locales/en_GB/messages.json +++ b/apps/desktop/src/locales/en_GB/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Attachment saved" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "File" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on launch" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/en_IN/messages.json b/apps/desktop/src/locales/en_IN/messages.json index 85e486e5cef..311afd9e0ee 100644 --- a/apps/desktop/src/locales/en_IN/messages.json +++ b/apps/desktop/src/locales/en_IN/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "The attachment has been saved." }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "File" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on launch" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/eo/messages.json b/apps/desktop/src/locales/eo/messages.json index 17ac511b174..95b35d0ab80 100644 --- a/apps/desktop/src/locales/eo/messages.json +++ b/apps/desktop/src/locales/eo/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Aldonaĵo konserviĝis" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Dosiero" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Ŝlosi per la ĉefa pasvorto ĉe relanĉo" }, diff --git a/apps/desktop/src/locales/es/messages.json b/apps/desktop/src/locales/es/messages.json index 2282fca50d1..737d3b3aa68 100644 --- a/apps/desktop/src/locales/es/messages.json +++ b/apps/desktop/src/locales/es/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "El adjunto se ha guardado." }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Archivo" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Solicitar Touch ID al iniciar" }, - "requirePasswordOnStart": { - "message": "Solicitar contraseña o PIN al iniciar la aplicación" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Solicitar contraseña al iniciar la aplicación" - }, "lockWithMasterPassOnRestart1": { "message": "Bloquear con contraseña maestra al reiniciar" }, diff --git a/apps/desktop/src/locales/et/messages.json b/apps/desktop/src/locales/et/messages.json index 374f9afb265..5291e175152 100644 --- a/apps/desktop/src/locales/et/messages.json +++ b/apps/desktop/src/locales/et/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Manus on salvestatud." }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Fail" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Küsi avamisel Touch ID tuvastust" }, - "requirePasswordOnStart": { - "message": "Nõua parooli või PINi rakenduse kävitumisel" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Nõua parooli rakenduse käivitamisel" - }, "lockWithMasterPassOnRestart1": { "message": "Lukusta ülemparooliga, kui rakendus taaskäivitatakse" }, diff --git a/apps/desktop/src/locales/eu/messages.json b/apps/desktop/src/locales/eu/messages.json index 54bffefada1..2917854d587 100644 --- a/apps/desktop/src/locales/eu/messages.json +++ b/apps/desktop/src/locales/eu/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Eranskina gorde da." }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Fitxategia" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Eskatu Touch ID abiaraztean" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/fa/messages.json b/apps/desktop/src/locales/fa/messages.json index 50480b329c8..c0182dca2d5 100644 --- a/apps/desktop/src/locales/fa/messages.json +++ b/apps/desktop/src/locales/fa/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "پیوست ذخیره شد" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "پرونده" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "درخواست Touch ID در هنگام راه‌اندازی" }, - "requirePasswordOnStart": { - "message": "هنگام شروع برنامه، کلمه عبور یا کد پین مورد نیاز است" - }, - "requirePasswordWithoutPinOnStart": { - "message": "هنگام شروع برنامه، کلمه عبور مورد نیاز است" - }, "lockWithMasterPassOnRestart1": { "message": "در زمان شروع مجدد، با کلمه عبور اصلی قفل کن" }, diff --git a/apps/desktop/src/locales/fi/messages.json b/apps/desktop/src/locales/fi/messages.json index 8eeebcd48fb..78e43c68308 100644 --- a/apps/desktop/src/locales/fi/messages.json +++ b/apps/desktop/src/locales/fi/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Tiedostoliite tallennettiin" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Tiedosto" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Pyydä Touch ID -todennusta käynnistettäessä" }, - "requirePasswordOnStart": { - "message": "Pyydä salasana tai PIN-koodi sovelluksen käynnistyessä" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Vaadi salasana sovelluksen käynnistyessä" - }, "lockWithMasterPassOnRestart1": { "message": "Lukitse pääsalasanalla uudelleenkäynnistyksen yhteydessä" }, diff --git a/apps/desktop/src/locales/fil/messages.json b/apps/desktop/src/locales/fil/messages.json index cca4ebfc0f4..19ef8f4ead6 100644 --- a/apps/desktop/src/locales/fil/messages.json +++ b/apps/desktop/src/locales/fil/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Nailigtas ang attachment" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Mag-file" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Humingi ng Touch ID sa paglulunsad" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/fr/messages.json b/apps/desktop/src/locales/fr/messages.json index fd402e2c447..0076c2b81e5 100644 --- a/apps/desktop/src/locales/fr/messages.json +++ b/apps/desktop/src/locales/fr/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Pièce jointe enregistrée" }, + "addAttachment": { + "message": "Ajouter une pièce jointe" + }, + "maxFileSizeSansPunctuation": { + "message": "La taille maximale des fichiers est de 500 Mo" + }, "file": { "message": "Fichier" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Demander Touch ID au démarrage de l'application" }, - "requirePasswordOnStart": { - "message": "Exiger un mot de passe ou un code PIN au démarrage de Bitwarden" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Exiger un mot de passe au démarrage de l'application" - }, "lockWithMasterPassOnRestart1": { "message": "Verrouiller avec le mot de passe principal au redémarrage" }, diff --git a/apps/desktop/src/locales/gl/messages.json b/apps/desktop/src/locales/gl/messages.json index 028bc34f77e..07de313e63d 100644 --- a/apps/desktop/src/locales/gl/messages.json +++ b/apps/desktop/src/locales/gl/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Attachment saved" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "File" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/he/messages.json b/apps/desktop/src/locales/he/messages.json index e9cc7541921..7f9cb69ce00 100644 --- a/apps/desktop/src/locales/he/messages.json +++ b/apps/desktop/src/locales/he/messages.json @@ -24,7 +24,7 @@ "message": "זהות" }, "typeNote": { - "message": "Note" + "message": "הערה" }, "typeSecureNote": { "message": "פתק מאובטח" @@ -42,7 +42,7 @@ "message": "חיפוש בכספת" }, "resetSearch": { - "message": "Reset search" + "message": "אפס חיפוש" }, "addItem": { "message": "הוסף פריט" @@ -253,10 +253,10 @@ "message": "Remember SSH authorizations" }, "sshAgentPromptBehaviorAlways": { - "message": "Always" + "message": "תמיד" }, "sshAgentPromptBehaviorNever": { - "message": "Never" + "message": "אף פעם" }, "sshAgentPromptBehaviorRememberUntilLock": { "message": "Remember until vault is locked" @@ -412,16 +412,16 @@ "message": "מפתח אימות (TOTP)" }, "authenticatorKey": { - "message": "Authenticator key" + "message": "מפתח מאמת" }, "autofillOptions": { - "message": "Autofill options" + "message": "אפשרויות מילוי אוטומטי" }, "websiteUri": { - "message": "Website (URI)" + "message": "אתר אינטרנט (URI)" }, "websiteUriCount": { - "message": "Website (URI) $COUNT$", + "message": "אתר אינטרנט (URI) $COUNT$", "description": "Label for an input field that contains a website URI. The input field is part of a list of fields, and the count indicates the position of the field in the list.", "placeholders": { "count": { @@ -431,49 +431,49 @@ } }, "websiteAdded": { - "message": "Website added" + "message": "אתר האינטרנט נוסף" }, "addWebsite": { - "message": "Add website" + "message": "הוסף אתר אינטרנט" }, "deleteWebsite": { - "message": "Delete website" + "message": "מחק אתר אינטרנט" }, "owner": { - "message": "Owner" + "message": "בעלים" }, "addField": { - "message": "Add field" + "message": "הוסף שדה" }, "editField": { - "message": "Edit field" + "message": "ערוך שדה" }, "permanentlyDeleteAttachmentConfirmation": { - "message": "Are you sure you want to permanently delete this attachment?" + "message": "האם אתה בטוח שברצונך למחוק לצמיתות צרופה זו?" }, "fieldType": { - "message": "Field type" + "message": "סוג שדה" }, "fieldLabel": { - "message": "Field label" + "message": "תווית שדה" }, "add": { - "message": "Add" + "message": "הוסף" }, "textHelpText": { - "message": "Use text fields for data like security questions" + "message": "השתמש בשדות טקסט עבור נתונים כמו שאלות אבטחה" }, "hiddenHelpText": { - "message": "Use hidden fields for sensitive data like a password" + "message": "השתמש בשדות נסתרים עבור מידע רגיש כמו סיסמה" }, "checkBoxHelpText": { - "message": "Use checkboxes if you'd like to autofill a form's checkbox, like a remember email" + "message": "השתמש בתיבות סימון אם תרצה למלא אוטומטית תיבת סימון של טופס, כמו זכור דוא\"ל" }, "linkedHelpText": { - "message": "Use a linked field when you are experiencing autofill issues for a specific website." + "message": "השתמש בשדה מקושר כאשר אתה חווה בעיות מילוי אוטומטי עם אתר מסוים." }, "linkedLabelHelpText": { - "message": "Enter the the field's html id, name, aria-label, or placeholder." + "message": "הזן את מזהה ה־html, שם, תווית aria או מציין מיקום." }, "folder": { "message": "תיקייה" @@ -501,7 +501,7 @@ "description": "This describes a field that is 'linked' (related) to another field." }, "cfTypeCheckbox": { - "message": "Checkbox" + "message": "תיבת סימון" }, "linkedValue": { "message": "ערך מקושר", @@ -576,7 +576,7 @@ "message": "העתקת קוד אימות (TOTP)" }, "copyFieldCipherName": { - "message": "Copy $FIELD$, $CIPHERNAME$", + "message": "העתק $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "הקובץ המצורף נשמר" }, + "addAttachment": { + "message": "צרף קובץ" + }, + "maxFileSizeSansPunctuation": { + "message": "גודל הקובץ המרבי הוא 500 מגהבייט" + }, "file": { "message": "קובץ" }, @@ -1226,7 +1232,7 @@ "message": "אימות דו שלבי להתחברות" }, "vaultTimeoutHeader": { - "message": "Vault timeout" + "message": "פסק זמן לכספת" }, "vaultTimeout": { "message": "סגירת כספת אוטומטית" @@ -1235,7 +1241,7 @@ "message": "פסק זמן" }, "vaultTimeoutAction1": { - "message": "Timeout action" + "message": "פעולת פסק זמן" }, "vaultTimeoutDesc": { "message": "בחר כמה זמן יעבור כדי שהכספת תסגר לאחר חוסר פעילות ותבצע את הפעולה שנבחרה." @@ -1449,7 +1455,7 @@ "description": "Copy credit card security code (CVV)" }, "cardNumber": { - "message": "card number" + "message": "מספר כרטיס" }, "premiumMembership": { "message": "חברות פרימיום" @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "הצג בקשה של Touch ID בפתיחת האפליקציה" }, - "requirePasswordOnStart": { - "message": "דרוש סיסמה או PIN בפתיחת היישום" - }, - "requirePasswordWithoutPinOnStart": { - "message": "דרוש סיסמה בפתיחת היישום" - }, "lockWithMasterPassOnRestart1": { "message": "נעל בעזרת הסיסמה הראשית בהפעלה מחדש" }, @@ -1984,10 +1984,10 @@ } }, "cardDetails": { - "message": "Card details" + "message": "פרטי כרטיס" }, "cardBrandDetails": { - "message": "$BRAND$ details", + "message": "פרטי $BRAND$", "placeholders": { "brand": { "content": "$1", @@ -1996,32 +1996,32 @@ } }, "learnMoreAboutAuthenticators": { - "message": "Learn more about authenticators" + "message": "למד עוד על מאמתים" }, "copyTOTP": { - "message": "Copy Authenticator key (TOTP)" + "message": "העתק קוד מאמת (TOTP)" }, "totpHelperTitle": { - "message": "Make 2-step verification seamless" + "message": "הפוך את האימות הדו־שלבי לחלק" }, "totpHelper": { - "message": "Bitwarden can store and fill 2-step verification codes. Copy and paste the key into this field." + "message": "Bitwarden יכול לאחסון ולמלא קודים של אימות דו־שלבי. העתק והדבק את המפתח לשדה זה." }, "totpHelperWithCapture": { - "message": "Bitwarden can store and fill 2-step verification codes. Select the camera icon to take a screenshot of this website's authenticator QR code, or copy and paste the key into this field." + "message": "Bitwarden יכול לאחסון ולמלא קודים של אימות דו־שלבי. בחר את סמל המצלמה כדי לצלם את הקוד QR המאמת של אתר זה, או העתק והדבק את המפתח לתוך שדה זה." }, "premium": { - "message": "Premium", + "message": "פרימיום", "description": "Premium membership" }, "freeOrgsCannotUseAttachments": { - "message": "Free organizations cannot use attachments" + "message": "ארגונים חיניים לא יכולים להשתמש בקבצים מצורפים" }, "singleFieldNeedsAttention": { - "message": "1 field needs your attention." + "message": "שדה 1 צריך את תשומת לבך." }, "multipleFieldsNeedAttention": { - "message": "$COUNT$ fields need your attention.", + "message": "$COUNT$ שדות צריכים את תשומת לבך.", "placeholders": { "count": { "content": "$1", @@ -2030,10 +2030,10 @@ } }, "cardExpiredTitle": { - "message": "Expired card" + "message": "כרטיס פג תוקף" }, "cardExpiredMessage": { - "message": "If you've renewed it, update the card's information" + "message": "אם חידשת אותו, עדכן את פרטי הכרטיס" }, "verificationRequired": { "message": "נדרש אימות", @@ -2193,7 +2193,7 @@ "message": "בשל מדיניות ארגונית, אתה מוגבל מלשמור פריטים לכספת האישית שלך. שנה את אפשרות הבעלות לארגון ובחר מאוספים זמינים." }, "yourNewPasswordCannotBeTheSameAsYourCurrentPassword": { - "message": "Your new password cannot be the same as your current password." + "message": "הסיסמה החדשה שלך לא יכולה להיות זהה לסיסמה הנוכחית שלך." }, "hintEqualsPassword": { "message": "רמז הסיסמה שלך לא יכול להיות אותו הדבר כמו הסיסמה שלך." @@ -2205,13 +2205,13 @@ "message": "מדיניות ארגון חסמה ייבוא פריטים אל תוך הכספת האישית שלך." }, "personalDetails": { - "message": "Personal details" + "message": "פרטים אישיים" }, "identification": { - "message": "Identification" + "message": "הזדהות" }, "contactInfo": { - "message": "Contact information" + "message": "פרטי איש קשר" }, "allSends": { "message": "כל הסֵנְדים", @@ -2407,7 +2407,7 @@ "message": "פעולה זו מוגנת. כדי להמשיך, הזן מחדש את הסיסמה הראשית שלך כדי לאמת את זהותך." }, "masterPasswordSuccessfullySet": { - "message": "Master password successfully set" + "message": "סיסמה ראשית הוגדרה בהצלחה" }, "updatedMasterPassword": { "message": "סיסמה ראשית עודכנה" @@ -2518,10 +2518,10 @@ "message": "פסק הזמן לכספת שלך חורג מהמגבלות שנקבעו על ידי הארגון שלך." }, "vaultTimeoutPolicyAffectingOptions": { - "message": "Enterprise policy requirements have been applied to your timeout options" + "message": "דרישות מדיניות ארגונית הוחלו על אפשרויות פסק הזמן שלך" }, "vaultTimeoutPolicyInEffect": { - "message": "Your organization policies have set your maximum allowed vault timeout to $HOURS$ hour(s) and $MINUTES$ minute(s).", + "message": "פוליסות הארגון שלך הגדירו את פסק הזמן לכספת המרבי שלך ל־$HOURS$ שעות ו־$MINUTES$ דקות.", "placeholders": { "hours": { "content": "$1", diff --git a/apps/desktop/src/locales/hi/messages.json b/apps/desktop/src/locales/hi/messages.json index 3c9bbd4d497..0a451e6e238 100644 --- a/apps/desktop/src/locales/hi/messages.json +++ b/apps/desktop/src/locales/hi/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Attachment saved" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "File" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/hr/messages.json b/apps/desktop/src/locales/hr/messages.json index 31f01655fde..29680a25198 100644 --- a/apps/desktop/src/locales/hr/messages.json +++ b/apps/desktop/src/locales/hr/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Privitak spremljen" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Datoteka" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Zahtijevaj Touch ID pri pokretanju" }, - "requirePasswordOnStart": { - "message": "Zahtijevaj lozinku ili PIN pri pokretanju" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Zahtijevaj lozinku pri pokretanju" - }, "lockWithMasterPassOnRestart1": { "message": "Zaključaj glavnom lozinkom kod svakog pokretanja" }, diff --git a/apps/desktop/src/locales/hu/messages.json b/apps/desktop/src/locales/hu/messages.json index cee3549bc50..87468eb3622 100644 --- a/apps/desktop/src/locales/hu/messages.json +++ b/apps/desktop/src/locales/hu/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "A melléklet mentésre került." }, + "addAttachment": { + "message": "Melléklet hozzáadása" + }, + "maxFileSizeSansPunctuation": { + "message": "A maximális fájlméret 500 MB." + }, "file": { "message": "Fájl" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Érintés AZ kérése indításkor" }, - "requirePasswordOnStart": { - "message": "Jelszó vagy PIN kód szükséges az alkalmazás indításakor" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Jelszó szükséges az alkalmazás indításakor" - }, "lockWithMasterPassOnRestart1": { "message": "Lezárás mesterjelszóval újraindításkor" }, diff --git a/apps/desktop/src/locales/id/messages.json b/apps/desktop/src/locales/id/messages.json index fa11c2e5f88..3c6fb0bf8fc 100644 --- a/apps/desktop/src/locales/id/messages.json +++ b/apps/desktop/src/locales/id/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Lampiran telah disimpan." }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Berkas" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Minta Touch ID saat diluncurkan" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/it/messages.json b/apps/desktop/src/locales/it/messages.json index 3f70f226665..85033e30341 100644 --- a/apps/desktop/src/locales/it/messages.json +++ b/apps/desktop/src/locales/it/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Allegato salvato" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "File" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Richiedi Touch ID all'avvio" }, - "requirePasswordOnStart": { - "message": "Richiedi password o PIN all'avvio dell'app" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Richiedi parola d'accesso all'avvio dell'app" - }, "lockWithMasterPassOnRestart1": { "message": "Blocca con password principale al riavvio" }, @@ -3492,10 +3492,10 @@ "message": "Seleziona una raccolta" }, "importTargetHintCollection": { - "message": "Select this option if you want the imported file contents moved to a collection" + "message": "Seleziona questa opzione se vuoi che i contenuti dell'importazione siano salvati in una raccolta" }, "importTargetHintFolder": { - "message": "Select this option if you want the imported file contents moved to a folder" + "message": "Seleziona questa opzione se vuoi che i contenuti dell'importazione siano salvati in una raccolta" }, "importUnassignedItemsError": { "message": "Il file contiene elementi non assegnati." @@ -4075,7 +4075,7 @@ "message": "Bitwarden non convalida i campi di input: assicurati di essere nella finestra e nel campo di testo corretti prima di usare la scorciatoia." }, "moreBreadcrumbs": { - "message": "More breadcrumbs", + "message": "Ulteriori segmenti", "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/ja/messages.json b/apps/desktop/src/locales/ja/messages.json index 7fe98d746fc..64ec2e4a0ec 100644 --- a/apps/desktop/src/locales/ja/messages.json +++ b/apps/desktop/src/locales/ja/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "添付ファイルを保存しました。" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "ファイル" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "起動時に Touch ID を要求する" }, - "requirePasswordOnStart": { - "message": "アプリ起動時にパスワードまたは PIN を要求" - }, - "requirePasswordWithoutPinOnStart": { - "message": "アプリ起動時にパスワードを要求" - }, "lockWithMasterPassOnRestart1": { "message": "再起動時にマスターパスワードでロック" }, diff --git a/apps/desktop/src/locales/ka/messages.json b/apps/desktop/src/locales/ka/messages.json index 5ab87271c2e..c2a474dfdfa 100644 --- a/apps/desktop/src/locales/ka/messages.json +++ b/apps/desktop/src/locales/ka/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Attachment saved" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "ფაილი" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/km/messages.json b/apps/desktop/src/locales/km/messages.json index 028bc34f77e..07de313e63d 100644 --- a/apps/desktop/src/locales/km/messages.json +++ b/apps/desktop/src/locales/km/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Attachment saved" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "File" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/kn/messages.json b/apps/desktop/src/locales/kn/messages.json index 9f8c871285b..31eb6dd4b1e 100644 --- a/apps/desktop/src/locales/kn/messages.json +++ b/apps/desktop/src/locales/kn/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "ಲಗತ್ತನ್ನು ಉಳಿಸಲಾಗಿದೆ." }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "ಫೈಲ್" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/ko/messages.json b/apps/desktop/src/locales/ko/messages.json index 12f853079cb..50f723b406c 100644 --- a/apps/desktop/src/locales/ko/messages.json +++ b/apps/desktop/src/locales/ko/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "첨부 파일을 저장했습니다." }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "파일" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "실행 시 Touch ID 요구하기" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/lt/messages.json b/apps/desktop/src/locales/lt/messages.json index 7e2a4e286cc..5d2261c2029 100644 --- a/apps/desktop/src/locales/lt/messages.json +++ b/apps/desktop/src/locales/lt/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Priedas išsaugotas" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Failas" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Prašyti Touch ID paleidus programėlę" }, - "requirePasswordOnStart": { - "message": "Reikalauti slaptažodžio arba PIN paleidus programėlę" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/lv/messages.json b/apps/desktop/src/locales/lv/messages.json index 1f1a7a54834..ae0e19b743d 100644 --- a/apps/desktop/src/locales/lv/messages.json +++ b/apps/desktop/src/locales/lv/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Pielikums tika saglabāts." }, + "addAttachment": { + "message": "Pievienot pielikumu" + }, + "maxFileSizeSansPunctuation": { + "message": "Lielākais pieļaujamais datnes izmērs ir 500 MB" + }, "file": { "message": "Datne" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Palaišanā vaicāt pēc Touch ID" }, - "requirePasswordOnStart": { - "message": "Pieprasīt paroli vai PIN pēc lietotnes palaišanas" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Pieprasīt paroli pēc lietotnes palaišanas" - }, "lockWithMasterPassOnRestart1": { "message": "Aizslēgt ar galveno paroli pēc pārsāknēšanas" }, @@ -3492,10 +3492,10 @@ "message": "Atlasīt krājumu" }, "importTargetHintCollection": { - "message": "Select this option if you want the imported file contents moved to a collection" + "message": "Šī iespēja jāatlasa, ja ir vēlēšanās ievietotās datnes saturu ievietot krājumā" }, "importTargetHintFolder": { - "message": "Select this option if you want the imported file contents moved to a folder" + "message": "Šī iespēja jāatlasa, ja ir vēlēšanās ievietotās datnes saturu ievietot mapē" }, "importUnassignedItemsError": { "message": "Datne satur nepiešķirtus vienumus." @@ -4075,7 +4075,7 @@ "message": "Bitwarden nepārbauda ievades atrašanās vietas, jāpārliecinās, ka atrodies pareizajā logā un laukā, pirms saīsnes izmantošanas." }, "moreBreadcrumbs": { - "message": "More breadcrumbs", + "message": "Vairāk norāžu", "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/me/messages.json b/apps/desktop/src/locales/me/messages.json index 139066cf9af..012b64e62bd 100644 --- a/apps/desktop/src/locales/me/messages.json +++ b/apps/desktop/src/locales/me/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Prilog je sačuvan." }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Datoteka" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/ml/messages.json b/apps/desktop/src/locales/ml/messages.json index 78dbed9fa6e..8a76d49d3b0 100644 --- a/apps/desktop/src/locales/ml/messages.json +++ b/apps/desktop/src/locales/ml/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "ഈ അറ്റാച്ചുമെന്റ് സംരക്ഷിച്ചു." }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "ഫയൽ" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/mr/messages.json b/apps/desktop/src/locales/mr/messages.json index 028bc34f77e..07de313e63d 100644 --- a/apps/desktop/src/locales/mr/messages.json +++ b/apps/desktop/src/locales/mr/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Attachment saved" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "File" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/my/messages.json b/apps/desktop/src/locales/my/messages.json index 6432e4f15a1..f277fcf61cf 100644 --- a/apps/desktop/src/locales/my/messages.json +++ b/apps/desktop/src/locales/my/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Attachment saved" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "File" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/nb/messages.json b/apps/desktop/src/locales/nb/messages.json index d778ba216e4..07f61c5fe79 100644 --- a/apps/desktop/src/locales/nb/messages.json +++ b/apps/desktop/src/locales/nb/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Vedlegget har blitt lagret." }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Fil" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Spør om Touch ID ved oppstart" }, - "requirePasswordOnStart": { - "message": "Krev passord eller PIN-kode når appen startes" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/ne/messages.json b/apps/desktop/src/locales/ne/messages.json index 6bd3afecd29..7f68ff13562 100644 --- a/apps/desktop/src/locales/ne/messages.json +++ b/apps/desktop/src/locales/ne/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Attachment saved" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "File" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/nl/messages.json b/apps/desktop/src/locales/nl/messages.json index 93acc51408d..82591230a83 100644 --- a/apps/desktop/src/locales/nl/messages.json +++ b/apps/desktop/src/locales/nl/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Bijlage opgeslagen" }, + "addAttachment": { + "message": "Bijlage toevoegen" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximale bestandsgrootte is 500 MB" + }, "file": { "message": "Bestand" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Vraag om Touch ID bij opstarten" }, - "requirePasswordOnStart": { - "message": "Wachtwoord of pincode vereisen bij starten van de app" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Wachtwoord vereisen bij starten van de app" - }, "lockWithMasterPassOnRestart1": { "message": "Bij herstart vergrendelen met hoofdwachtwoord" }, diff --git a/apps/desktop/src/locales/nn/messages.json b/apps/desktop/src/locales/nn/messages.json index 3764f9a6c0c..a6710d7fa37 100644 --- a/apps/desktop/src/locales/nn/messages.json +++ b/apps/desktop/src/locales/nn/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Vedlegg lagret" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Fil" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/or/messages.json b/apps/desktop/src/locales/or/messages.json index e8a7531235f..23efde7f42d 100644 --- a/apps/desktop/src/locales/or/messages.json +++ b/apps/desktop/src/locales/or/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Attachment saved" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "File" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/pl/messages.json b/apps/desktop/src/locales/pl/messages.json index af707665b86..91394e2be1f 100644 --- a/apps/desktop/src/locales/pl/messages.json +++ b/apps/desktop/src/locales/pl/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Załącznik został zapisany" }, + "addAttachment": { + "message": "Dodaj załącznik" + }, + "maxFileSizeSansPunctuation": { + "message": "Maksymalny rozmiar pliku to 500 MB" + }, "file": { "message": "Plik" }, @@ -930,7 +936,7 @@ "message": "Kod weryfikacyjny jest nieprawidłowy" }, "continue": { - "message": "Kontynuuj" + "message": "Przejdź" }, "verificationCodeEmailSent": { "message": "Wiadomość weryfikacyjna została wysłana na adres $EMAIL$.", @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Poproś o Touch ID przy uruchomieniu" }, - "requirePasswordOnStart": { - "message": "Wymagaj hasła lub PIN przy starcie aplikacji" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Wymagaj hasła przy starcie aplikacji" - }, "lockWithMasterPassOnRestart1": { "message": "Zablokuj hasłem głównym po uruchomieniu ponownym" }, @@ -2184,7 +2184,7 @@ "message": "Aby skonfigurować dane biometryczne w przeglądarce, włącz najpierw biometrię w aplikacji desktopowej." }, "biometricsManualSetupTitle": { - "message": "Automatyczna konfiguracja niedostępna" + "message": "Automatyczna konfiguracja jest niedostępna" }, "biometricsManualSetupDesc": { "message": "Ze względu na metodę instalacji, biometria nie może być automatycznie włączona. Czy chcesz otworzyć dokumentację dotyczącą tego, jak to zrobić ręcznie?" @@ -3018,7 +3018,7 @@ "message": "Zobacz wszystkie sposoby logowania" }, "viewAllLoginOptions": { - "message": "Zobacz wszystkie sposoby logowania" + "message": "Pokaż wszystkie metody logowania" }, "resendNotification": { "message": "Wyślij ponownie powiadomienie" @@ -3513,7 +3513,7 @@ "message": "Nie wybrano pliku" }, "orCopyPasteFileContents": { - "message": "lub skopiuj/wklej treść pliku" + "message": "lub wklej zawartość pliku" }, "instructionsFor": { "message": "Instrukcja dla $NAME$", @@ -3651,10 +3651,10 @@ "message": "Włącz akcelerację sprzętową i uruchom ponownie" }, "removePasskey": { - "message": "Usuń passkey" + "message": "Usuń klucz dostępu" }, "passkeyRemoved": { - "message": "Passkey został usunięty" + "message": "Klucz dostępu został usunięty" }, "errorAssigningTargetCollection": { "message": "Wystąpił błąd podczas przypisywania kolekcji." @@ -3683,7 +3683,7 @@ } }, "back": { - "message": "Powrót", + "message": "Wstecz", "description": "Button text to navigate back" }, "removeItem": { @@ -3792,7 +3792,7 @@ "message": "podpisania wiadomości" }, "sshActionGitSign": { - "message": "podpisania commita w giciem" + "message": "podpisania Git commit" }, "unknownApplication": { "message": "Aplikacja" @@ -3807,13 +3807,13 @@ "message": "Importuj klucz ze schowka" }, "sshKeyImported": { - "message": "Klucz SSH zaimportowano pomyślnie" + "message": "Klucz SSH został zaimportowany" }, "fileSavedToDevice": { "message": "Plik zapisany na urządzeniu. Zarządzaj plikiem na swoim urządzeniu." }, "allowScreenshots": { - "message": "Zezwól na przechwytywanie ekranu" + "message": "Zezwalaj na wykonywanie zrzutów ekranu" }, "allowScreenshotsDesc": { "message": "Zezwól aplikacji desktopowej Bitwarden na przechwytywanie w zrzutach ekranu i przeglądanie w sesjach zdalnego pulpitu. Wyłączenie tej opcji uniemożliwi dostęp na niektórych zewnętrznych wyświetlaczach." @@ -3825,7 +3825,7 @@ "message": "Potwierdź, że okno jest nadal widoczne." }, "updateBrowserOrDisableFingerprintDialogTitle": { - "message": "Wymagana aktualizacja rozszerzenia" + "message": "Aktualizacja rozszerzenia jest wymagana" }, "updateBrowserOrDisableFingerprintDialogMessage": { "message": "Rozszerzenie przeglądarki, którego używasz, jest nieaktualne. Zaktualizuj je lub wyłącz weryfikację odcisku palca integracji przeglądarki w ustawieniach aplikacji desktopowej." diff --git a/apps/desktop/src/locales/pt_BR/messages.json b/apps/desktop/src/locales/pt_BR/messages.json index 321a940152c..9db268ed9bc 100644 --- a/apps/desktop/src/locales/pt_BR/messages.json +++ b/apps/desktop/src/locales/pt_BR/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "O anexo foi salvo." }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Arquivo" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Pedir pelo Touch ID ao iniciar" }, - "requirePasswordOnStart": { - "message": "Exigir senha ou PIN ao iniciar o app" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Exigir senha ao iniciar o app" - }, "lockWithMasterPassOnRestart1": { "message": "Bloquear com senha mestra ao reiniciar" }, diff --git a/apps/desktop/src/locales/pt_PT/messages.json b/apps/desktop/src/locales/pt_PT/messages.json index 87b39fe75fe..5fd620a00ff 100644 --- a/apps/desktop/src/locales/pt_PT/messages.json +++ b/apps/desktop/src/locales/pt_PT/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Anexo guardado" }, + "addAttachment": { + "message": "Adicionar anexo" + }, + "maxFileSizeSansPunctuation": { + "message": "O tamanho máximo do ficheiro é de 500 MB" + }, "file": { "message": "Ficheiro" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Pedir o Touch ID ao iniciar a app" }, - "requirePasswordOnStart": { - "message": "Exigir palavra-passe ou PIN ao iniciar a app" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Exigir palavra-passe ao iniciar a app" - }, "lockWithMasterPassOnRestart1": { "message": "Bloquear com a palavra-passe mestra ao reiniciar" }, diff --git a/apps/desktop/src/locales/ro/messages.json b/apps/desktop/src/locales/ro/messages.json index 34d13a1a06b..7ebde796b70 100644 --- a/apps/desktop/src/locales/ro/messages.json +++ b/apps/desktop/src/locales/ro/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Atașament salvat" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Fișier" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Solicitați Touch ID la pornire" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/ru/messages.json b/apps/desktop/src/locales/ru/messages.json index 865c25fcd36..4cb36325d0e 100644 --- a/apps/desktop/src/locales/ru/messages.json +++ b/apps/desktop/src/locales/ru/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Вложение сохранено." }, + "addAttachment": { + "message": "Добавить вложение" + }, + "maxFileSizeSansPunctuation": { + "message": "Максимальный размер файла 500 МБ" + }, "file": { "message": "Файл" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Запрашивать Touch ID при запуске приложения" }, - "requirePasswordOnStart": { - "message": "Требовать пароль или PIN-код при запуске приложения" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Требовать пароль при запуске приложения" - }, "lockWithMasterPassOnRestart1": { "message": "Блокировать мастер-паролем при перезапуске" }, diff --git a/apps/desktop/src/locales/si/messages.json b/apps/desktop/src/locales/si/messages.json index 8adedf0e6ed..ade8bd70e52 100644 --- a/apps/desktop/src/locales/si/messages.json +++ b/apps/desktop/src/locales/si/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Attachment saved" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "File" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/sk/messages.json b/apps/desktop/src/locales/sk/messages.json index 3e9ec97fa38..634622d66d4 100644 --- a/apps/desktop/src/locales/sk/messages.json +++ b/apps/desktop/src/locales/sk/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Príloha bola uložená." }, + "addAttachment": { + "message": "Priložiť prílohu" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximálna veľkosť súboru je 500 MB" + }, "file": { "message": "Súbor" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Pri spustení požiadať o Touch ID" }, - "requirePasswordOnStart": { - "message": "Pri spustení aplikácie vyžadovať heslo alebo PIN" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Pri spustení aplikácie vyžadovať heslo" - }, "lockWithMasterPassOnRestart1": { "message": "Pri reštarte zamknúť hlavným heslom" }, diff --git a/apps/desktop/src/locales/sl/messages.json b/apps/desktop/src/locales/sl/messages.json index c898ab2da73..57811085362 100644 --- a/apps/desktop/src/locales/sl/messages.json +++ b/apps/desktop/src/locales/sl/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Priponka je bila shranjena." }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Datoteka" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Biometrično preverjanje ob zagonu aplikacije" }, - "requirePasswordOnStart": { - "message": "Ob zagonu zahteva geslo ali PIN" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/sr/messages.json b/apps/desktop/src/locales/sr/messages.json index 7d313b6f5a4..39f930dc6db 100644 --- a/apps/desktop/src/locales/sr/messages.json +++ b/apps/desktop/src/locales/sr/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Прилог је сачуван" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Датотека" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Захтевај Touch ID при покретању" }, - "requirePasswordOnStart": { - "message": "Захтевај лозинку или ПИН при покретању" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Захтевај лозинку при покретању" - }, "lockWithMasterPassOnRestart1": { "message": "Закључајте са главном лозинком при поновном покретању" }, diff --git a/apps/desktop/src/locales/sv/messages.json b/apps/desktop/src/locales/sv/messages.json index f8bf6cbb4bd..b6bb67ad595 100644 --- a/apps/desktop/src/locales/sv/messages.json +++ b/apps/desktop/src/locales/sv/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Bilaga sparad" }, + "addAttachment": { + "message": "Lägg till bilaga" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximal filstorlek är 500 MB" + }, "file": { "message": "Fil" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Be om Touch ID vid appstart" }, - "requirePasswordOnStart": { - "message": "Kräv lösenord eller PIN-kod vid appstart" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Kräv lösenord vid appstart" - }, "lockWithMasterPassOnRestart1": { "message": "Lås med huvudlösenord vid omstart" }, @@ -3492,10 +3492,10 @@ "message": "Välj en samling" }, "importTargetHintCollection": { - "message": "Select this option if you want the imported file contents moved to a collection" + "message": "Välj det här alternativet om du vill att innehållet i den importerade filen ska flyttas till en samling" }, "importTargetHintFolder": { - "message": "Select this option if you want the imported file contents moved to a folder" + "message": "Välj detta alternativ om du vill att innehållet i den importerade filen ska flyttas till en mapp" }, "importUnassignedItemsError": { "message": "Filen innehåller otilldelade objekt." @@ -4075,7 +4075,7 @@ "message": "Bitwarden validerar inte inmatningsplatser, så se till att du är i rätt fönster och fält innan du använder genvägen." }, "moreBreadcrumbs": { - "message": "More breadcrumbs", + "message": "Fler länkstigar", "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } diff --git a/apps/desktop/src/locales/te/messages.json b/apps/desktop/src/locales/te/messages.json index 028bc34f77e..07de313e63d 100644 --- a/apps/desktop/src/locales/te/messages.json +++ b/apps/desktop/src/locales/te/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Attachment saved" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "File" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/th/messages.json b/apps/desktop/src/locales/th/messages.json index 27f6048a27d..8f7f7494ce3 100644 --- a/apps/desktop/src/locales/th/messages.json +++ b/apps/desktop/src/locales/th/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "บันทึกไฟล์แนบแล้ว" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "ไฟล์" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, - "requirePasswordOnStart": { - "message": "Require password or PIN on app start" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Require password on app start" - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/tr/messages.json b/apps/desktop/src/locales/tr/messages.json index 8d45329f18f..f77d2bfd7b4 100644 --- a/apps/desktop/src/locales/tr/messages.json +++ b/apps/desktop/src/locales/tr/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Dosya kaydedildi" }, + "addAttachment": { + "message": "Dosya ekle" + }, + "maxFileSizeSansPunctuation": { + "message": "Maksimum dosya boyutu 500 MB'dir" + }, "file": { "message": "Dosya" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Uygulamayı başlatırken Touch ID iste" }, - "requirePasswordOnStart": { - "message": "Uygulamayı başlatırken parola veya PIN iste" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Uygulamayı başlatırken parola iste" - }, "lockWithMasterPassOnRestart1": { "message": "Yeniden başlatmada ana parola ile kilitle" }, diff --git a/apps/desktop/src/locales/uk/messages.json b/apps/desktop/src/locales/uk/messages.json index 434680d8338..aff1ea20739 100644 --- a/apps/desktop/src/locales/uk/messages.json +++ b/apps/desktop/src/locales/uk/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Вкладення збережено" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Файл" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Запитувати Touch ID під час запуску" }, - "requirePasswordOnStart": { - "message": "Вимагати пароль чи PIN під час запуску" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Вимагати пароль під час запуску" - }, "lockWithMasterPassOnRestart1": { "message": "Блокувати головним паролем при перезапуску" }, diff --git a/apps/desktop/src/locales/vi/messages.json b/apps/desktop/src/locales/vi/messages.json index 45714b3e58b..aeef74f5caa 100644 --- a/apps/desktop/src/locales/vi/messages.json +++ b/apps/desktop/src/locales/vi/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "Đã lưu tệp đính kèm" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "Tệp" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "Yêu cầu xác minh Touch ID khi mở ứng dụng" }, - "requirePasswordOnStart": { - "message": "Yêu cầu mật khẩu hoặc mã PIN khi mở ứng dụng" - }, - "requirePasswordWithoutPinOnStart": { - "message": "Yêu cầu mật khẩu khi khởi động ứng dụng" - }, "lockWithMasterPassOnRestart1": { "message": "Khóa bằng mật khẩu chính khi khởi động lại" }, diff --git a/apps/desktop/src/locales/zh_CN/messages.json b/apps/desktop/src/locales/zh_CN/messages.json index f064b110b1f..da82f06b39f 100644 --- a/apps/desktop/src/locales/zh_CN/messages.json +++ b/apps/desktop/src/locales/zh_CN/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "附件已保存" }, + "addAttachment": { + "message": "添加附件" + }, + "maxFileSizeSansPunctuation": { + "message": "文件最大为 500 MB" + }, "file": { "message": "文件" }, @@ -1226,7 +1232,7 @@ "message": "两步登录" }, "vaultTimeoutHeader": { - "message": "密码库超时" + "message": "密码库超时时间" }, "vaultTimeout": { "message": "密码库超时时间" @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "应用程序启动时提示触控 ID" }, - "requirePasswordOnStart": { - "message": "应用程序启动时要求密码或 PIN 码" - }, - "requirePasswordWithoutPinOnStart": { - "message": "应用程序启动时要求密码" - }, "lockWithMasterPassOnRestart1": { "message": "重启后使用主密码锁定" }, @@ -4069,7 +4069,7 @@ "message": "显示更少" }, "enableAutotype": { - "message": "启用自动类型" + "message": "启用自动填写" }, "enableAutotypeDescription": { "message": "Bitwarden 不会验证输入位置,在使用快捷键之前,请确保您位于正确的窗口和字段中。" diff --git a/apps/desktop/src/locales/zh_TW/messages.json b/apps/desktop/src/locales/zh_TW/messages.json index 641a27e5a34..026034e2dfc 100644 --- a/apps/desktop/src/locales/zh_TW/messages.json +++ b/apps/desktop/src/locales/zh_TW/messages.json @@ -702,6 +702,12 @@ "attachmentSaved": { "message": "附件已儲存" }, + "addAttachment": { + "message": "Add attachment" + }, + "maxFileSizeSansPunctuation": { + "message": "Maximum file size is 500 MB" + }, "file": { "message": "檔案" }, @@ -1840,12 +1846,6 @@ "autoPromptTouchId": { "message": "啟動應用程式時要求 Touch ID" }, - "requirePasswordOnStart": { - "message": "要求在啟動應用程式時輸入密碼或 PIN 碼" - }, - "requirePasswordWithoutPinOnStart": { - "message": "要求在啟動應用程式時輸入密碼" - }, "lockWithMasterPassOnRestart1": { "message": "重啟後使用主密碼鎖定" }, From 85dccf2a44d8e4a305c7c2dc5bd9cfb1d37998a7 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 25 Aug 2025 12:10:03 +0000 Subject: [PATCH 034/167] Autosync the updated translations (#16119) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/web/src/locales/af/messages.json | 152 ++++++++++++++++- apps/web/src/locales/ar/messages.json | 152 ++++++++++++++++- apps/web/src/locales/az/messages.json | 152 ++++++++++++++++- apps/web/src/locales/be/messages.json | 152 ++++++++++++++++- apps/web/src/locales/bg/messages.json | 152 ++++++++++++++++- apps/web/src/locales/bn/messages.json | 152 ++++++++++++++++- apps/web/src/locales/bs/messages.json | 152 ++++++++++++++++- apps/web/src/locales/ca/messages.json | 152 ++++++++++++++++- apps/web/src/locales/cs/messages.json | 160 ++++++++++++++++-- apps/web/src/locales/cy/messages.json | 152 ++++++++++++++++- apps/web/src/locales/da/messages.json | 152 ++++++++++++++++- apps/web/src/locales/de/messages.json | 152 ++++++++++++++++- apps/web/src/locales/el/messages.json | 152 ++++++++++++++++- apps/web/src/locales/en_GB/messages.json | 152 ++++++++++++++++- apps/web/src/locales/en_IN/messages.json | 152 ++++++++++++++++- apps/web/src/locales/eo/messages.json | 152 ++++++++++++++++- apps/web/src/locales/es/messages.json | 152 ++++++++++++++++- apps/web/src/locales/et/messages.json | 152 ++++++++++++++++- apps/web/src/locales/eu/messages.json | 152 ++++++++++++++++- apps/web/src/locales/fa/messages.json | 152 ++++++++++++++++- apps/web/src/locales/fi/messages.json | 152 ++++++++++++++++- apps/web/src/locales/fil/messages.json | 152 ++++++++++++++++- apps/web/src/locales/fr/messages.json | 152 ++++++++++++++++- apps/web/src/locales/gl/messages.json | 152 ++++++++++++++++- apps/web/src/locales/he/messages.json | 152 ++++++++++++++++- apps/web/src/locales/hi/messages.json | 152 ++++++++++++++++- apps/web/src/locales/hr/messages.json | 152 ++++++++++++++++- apps/web/src/locales/hu/messages.json | 152 ++++++++++++++++- apps/web/src/locales/id/messages.json | 152 ++++++++++++++++- apps/web/src/locales/it/messages.json | 152 ++++++++++++++++- apps/web/src/locales/ja/messages.json | 152 ++++++++++++++++- apps/web/src/locales/ka/messages.json | 152 ++++++++++++++++- apps/web/src/locales/km/messages.json | 152 ++++++++++++++++- apps/web/src/locales/kn/messages.json | 152 ++++++++++++++++- apps/web/src/locales/ko/messages.json | 152 ++++++++++++++++- apps/web/src/locales/lv/messages.json | 152 ++++++++++++++++- apps/web/src/locales/ml/messages.json | 152 ++++++++++++++++- apps/web/src/locales/mr/messages.json | 152 ++++++++++++++++- apps/web/src/locales/my/messages.json | 152 ++++++++++++++++- apps/web/src/locales/nb/messages.json | 152 ++++++++++++++++- apps/web/src/locales/ne/messages.json | 152 ++++++++++++++++- apps/web/src/locales/nl/messages.json | 152 ++++++++++++++++- apps/web/src/locales/nn/messages.json | 152 ++++++++++++++++- apps/web/src/locales/or/messages.json | 152 ++++++++++++++++- apps/web/src/locales/pl/messages.json | 152 ++++++++++++++++- apps/web/src/locales/pt_BR/messages.json | 156 +++++++++++++++-- apps/web/src/locales/pt_PT/messages.json | 206 +++++++++++++++++++---- apps/web/src/locales/ro/messages.json | 152 ++++++++++++++++- apps/web/src/locales/ru/messages.json | 152 ++++++++++++++++- apps/web/src/locales/si/messages.json | 152 ++++++++++++++++- apps/web/src/locales/sk/messages.json | 182 +++++++++++++++++--- apps/web/src/locales/sl/messages.json | 152 ++++++++++++++++- apps/web/src/locales/sr_CS/messages.json | 152 ++++++++++++++++- apps/web/src/locales/sr_CY/messages.json | 152 ++++++++++++++++- apps/web/src/locales/sv/messages.json | 152 ++++++++++++++++- apps/web/src/locales/te/messages.json | 152 ++++++++++++++++- apps/web/src/locales/th/messages.json | 152 ++++++++++++++++- apps/web/src/locales/tr/messages.json | 164 ++++++++++++++++-- apps/web/src/locales/uk/messages.json | 152 ++++++++++++++++- apps/web/src/locales/vi/messages.json | 194 +++++++++++++++++---- apps/web/src/locales/zh_CN/messages.json | 152 ++++++++++++++++- apps/web/src/locales/zh_TW/messages.json | 152 ++++++++++++++++- 62 files changed, 8941 insertions(+), 633 deletions(-) diff --git a/apps/web/src/locales/af/messages.json b/apps/web/src/locales/af/messages.json index 00c20238e92..83f8568478a 100644 --- a/apps/web/src/locales/af/messages.json +++ b/apps/web/src/locales/af/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Opsomming" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Onbekende item, u moet dalk toestemming versoek vir toegang tot hierdie item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "U kan nie delg vir die aktiewe rekening nie. Voer ’n ander e-posadres in." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/ar/messages.json b/apps/web/src/locales/ar/messages.json index 5a291482056..602e0827693 100644 --- a/apps/web/src/locales/ar/messages.json +++ b/apps/web/src/locales/ar/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "اختر مجموعة" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "الملخص" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/az/messages.json b/apps/web/src/locales/az/messages.json index 482db9201dd..0f1af044a4f 100644 --- a/apps/web/src/locales/az/messages.json +++ b/apps/web/src/locales/az/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Bir kolleksiya seçin" }, - "importTargetHint": { - "message": "Daxilə köçürülən fayl məzmununun $DESTINATION$ yerinə daşınmasını istəyirsinizsə bu variantı seçin", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Daxilə köçürülən fayl məzmunlarının bir kolleksiyaya daşınmasını istəyirsinizsə bu variantı seçin" + }, + "importTargetHintFolder": { + "message": "Daxilə köçürülən fayl məzmunlarının bir qovluğa daşınmasını istəyirsinizsə bu variantı seçin" }, "importUnassignedItemsError": { "message": "Faylda təyin edilməmiş elementlər var." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Qiymət icmalını göstər" + }, + "hidePricingSummary": { + "message": "Qiymət icmalını gizlət" + }, "summary": { "message": "İcmal" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Bilinməyən element, bu elementə erişmək üçün başqa bir hesabla giriş etməlisiniz." }, + "unknownSecret": { + "message": "Bilinməyən sirr, bu sirrə erişmək üçün icazə istəməli ola bilərsiniz." + }, + "unknownProject": { + "message": "Bilinməyən layihə, bu layihəyə erişmək üçün icazə istəməli ola bilərsiniz." + }, "cannotSponsorSelf": { "message": "Aktiv hesab üçün istifadə edə bilməzsiniz. Fərqli bir e-poçt daxil edin." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "$SECRET_ID$ identifikatoruna sahib bir sirr həmişəlik silindi", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "$SECRET_ID$ identifikatoruna sahib bir sirr bərpa edildi.", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "$SECRET_ID$ identifikatoruna sahib yeni bir sirr yaradıldı.", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "$PROJECT_ID$ kimliyinə sahib bir layihəyə erişildi.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "$PROJECT_ID$ kimliyinə sahib layihə silindi", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "$SECRET_ID$ kimliyinə sahib sirr silindi", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "$SECRET_ID$ identifikatoruna sahib bir layihəyə düzəliş edildi.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "$PROJECT_ID$ identifikatoruna sahib bir layihə silindi.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "$PROJECT_ID$ identifikatoruna sahib yeni bir layihə yaradıldı.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Bu event-lər sadəcə nümunədir və Bitwarden təşkilatınızdakı real event-ləri əks etdirmir." }, + "viewEvents": { + "message": "Tədbirlərə bax" + }, "cannotCreateCollection": { "message": "Ödənişsiz təşkilatların ən çox 2 kolleksiyası ola bilər. Daha çox kolleksiya əlavə etmək üçün ödənişli bir plana yüksəldin." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Daha az göstər" + }, + "missingTaxId": { + "message": "Əskik vergi kimliyi" + }, + "missingTaxIdWarning": { + "message": "Əməliyyat tələb olunur: Ödəniş detallarında Vergi kimlik nömrəsini buraxmısınız. Əgər əlavə edilməyəcəksə, fakturalarınıza əlavə vergi daxil ola bilər." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Vergi kimlik nömrəsini əlavə et" + }, + "missingTaxIdCalloutTitle": { + "message": "Əməliyyat tələb olunur: Əskik vergi kimliyi" + }, + "missingTaxIdCalloutDescription": { + "message": "Əgər əlavə edilməyəcəksə, fakturalarınıza əlavə vergi daxil ola bilər" + }, + "unverifiedTaxIdWarning": { + "message": "Əməliyyat tələb olunur: Vergi kimlik nömrəniz doğrulanmayıb. Əgər doğrulanmasa, fakturalarınıza əlavə vergi daxil ola bilər." + }, + "editTaxId": { + "message": "Vergi kimlik nömrəsinə düzəliş et" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Vergi kimlik nömrəsi doğrulanmayıb" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Doğru formatda yazıldığına və yazıda xəta olmadığına əmin olmaq üçün Vergi kimlik nömrənizi yoxlayın" + }, + "pendingVerification": { + "message": "Doğrulama gözlənilir" + }, + "checkInputFormat": { + "message": "Xəta üçün giriş formatını yoxlayın." + }, + "exampleTaxIdFormat": { + "message": "Nümunə $CODE$ formatı: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/be/messages.json b/apps/web/src/locales/be/messages.json index 08dabc8ba03..7afac8ce476 100644 --- a/apps/web/src/locales/be/messages.json +++ b/apps/web/src/locales/be/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Выбраць калекцыю" }, - "importTargetHint": { - "message": "Выберыце гэты параметр, калі вы хочаце, каб змесціва імпартаванага файла было перамешчанага ў $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Файл змяшчае непадпісаныя элементы." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Зводка" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Невядомы элемент. Магчыма, што вам неабходна запытаць дазвол на доступ да гэтага элемента." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Вы не можаце актываваць бягучы ўліковы запіс. Увядзіце іншы адрас электроннай пошты." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/bg/messages.json b/apps/web/src/locales/bg/messages.json index 73b854ef08b..0f00e9f4135 100644 --- a/apps/web/src/locales/bg/messages.json +++ b/apps/web/src/locales/bg/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Изберете колекция" }, - "importTargetHint": { - "message": "Изберете тази опция, ако искате съдържанието на внесения файл да бъде преместено в $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Изберете тази опция, ако искате съдържанието на внесения файл да бъде преместено в колекция" + }, + "importTargetHintFolder": { + "message": "Изберете тази опция, ако искате съдържанието на внесения файл да бъде преместено в папка" }, "importUnassignedItemsError": { "message": "Файлът съдържа невъзложени елементи." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Показване на резюме за цените" + }, + "hidePricingSummary": { + "message": "Скриване на резюмето за цените" + }, "summary": { "message": "Обобщено" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Непознат запис. Може да трябва да се впишете с друга регистрация, за да получите достъп до този запис." }, + "unknownSecret": { + "message": "Неизвестна тайна. Може да се нуждаете от правомощие за достъп до тази тайна." + }, + "unknownProject": { + "message": "Неизвестен проект. Може да се нуждаете от правомощие за достъп до този проект." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Изтрита е завинаги тайна с идентификатор: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Възстановена е тайна с идентификатор: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Създадена е нова тайна с идентификатор: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Осъществен е достъп до проект с идентификатор: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Идентификатор на изтрития проект: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Идентификатор на изтритата тайна: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Редактиран е проект с идентификатор: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Изтрит е проект с идентификатор: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Създаден е нов проект с идентификатор: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Тези събития са само за пример и не отразяват истинските събития във Вашата организация." }, + "viewEvents": { + "message": "Преглед на събитията" + }, "cannotCreateCollection": { "message": "Безплатните организации могат да имат не повече от 2 колекции. Надградете до платен план, ако искате да имате повече колекции." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Показване на по-малко" + }, + "missingTaxId": { + "message": "Липсва данъчен идентификатор" + }, + "missingTaxIdWarning": { + "message": "Нужно е действие: в данните за разплащането липсва данъчен идентификатор. Ако такъв не бъде добавен, фактурите може да включват допълнителен данък." + }, + "moreBreadcrumbs": { + "message": "Още елементи в пътечката", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Добавяне на данъчен идентификатор" + }, + "missingTaxIdCalloutTitle": { + "message": "Нужно е действие: липсва данъчен идентификатор" + }, + "missingTaxIdCalloutDescription": { + "message": "Ако не бъде добавен данъчен идентификатор, фактурите може да включват допълнителен данък." + }, + "unverifiedTaxIdWarning": { + "message": "Нужно е действие: данъчният идентификатор не е потвърден. Ако той не бъде потвърден, фактурите може да включват допълнителен данък." + }, + "editTaxId": { + "message": "Редактиране на данъчния идентификатор" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Данъчният идентификатор не е потвърден" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Проверете своя данъчен идентификатор, за да се уверите, че форматът му е правилен и в него няма грешки." + }, + "pendingVerification": { + "message": "Изчаква се потвърждение" + }, + "checkInputFormat": { + "message": "Проверете въведеното за грешки." + }, + "exampleTaxIdFormat": { + "message": "Примерен формат за $CODE$: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/bn/messages.json b/apps/web/src/locales/bn/messages.json index f91cce66382..de7dc0b1a75 100644 --- a/apps/web/src/locales/bn/messages.json +++ b/apps/web/src/locales/bn/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "সারাংশ" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/bs/messages.json b/apps/web/src/locales/bs/messages.json index 49827f99470..32b26cda3c3 100644 --- a/apps/web/src/locales/bs/messages.json +++ b/apps/web/src/locales/bs/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/ca/messages.json b/apps/web/src/locales/ca/messages.json index c87cc040ef1..9effbd0fd51 100644 --- a/apps/web/src/locales/ca/messages.json +++ b/apps/web/src/locales/ca/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Selecciona una col·lecció" }, - "importTargetHint": { - "message": "Seleccioneu aquesta opció si voleu que el contingut del fitxer importat es desplace a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "El fitxer conté elements no assignats." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Resum" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Element desconegut, és possible que hàgeu d'iniciar sessió amb un altre compte per accedir a aquest element." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "No podeu bescanviar pel compte actiu. Introduïu un correu electrònic diferent." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/cs/messages.json b/apps/web/src/locales/cs/messages.json index 5936caa601f..2dc90a26982 100644 --- a/apps/web/src/locales/cs/messages.json +++ b/apps/web/src/locales/cs/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Zvolte sbírku" }, - "importTargetHint": { - "message": "Pokud chcete obsah importovaného souboru přesunout do složky $DESTINATION$, vyberte tuto volbu", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Pokud chcete obsah importovaného souboru přesunout do sbírky, vyberte tuto volbu" + }, + "importTargetHintFolder": { + "message": "Pokud chcete obsah importovaného souboru přesunout do složky, vyberte tuto volbu" }, "importUnassignedItemsError": { "message": "Soubor obsahuje nepřiřazené položky." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Zobrazit přehled cen" + }, + "hidePricingSummary": { + "message": "Skrýt přehled cen" + }, "summary": { "message": "Souhrn" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Neznámá položka, možná budete muset požádat o oprávnění pro přístup k této položce." }, + "unknownSecret": { + "message": "Neznámý tajný klíč. Možná budete muset požádat o oprávnění pro přístup k tomuto tajnému klíči." + }, + "unknownProject": { + "message": "Neznámý projekt. Možná budete muset požádat o oprávnění pro přístup k tomuto projektu." + }, "cannotSponsorSelf": { "message": "Nemůžete uplatnit pro aktivní účet. Zadejte jiný e-mail." }, @@ -8314,7 +8322,7 @@ "message": "V průběhu pokusu o přečtení souboru s importem se vyskytla chyba" }, "accessedSecretWithId": { - "message": "Přístup k tajnému klíči s identifikátorem: $SECRET_ID$", + "message": "Přístup k tajnému klíči s ID: $SECRET_ID$", "placeholders": { "secret_id": { "content": "$1", @@ -8332,7 +8340,7 @@ } }, "editedSecretWithId": { - "message": "Úprava tajného klíče s identifikátorem: $SECRET_ID$", + "message": "Úprava tajného klíče s ID: $SECRET_ID$", "placeholders": { "secret_id": { "content": "$1", @@ -8341,7 +8349,25 @@ } }, "deletedSecretWithId": { - "message": "Smazání tajného klíče s identifikátorem: $SECRET_ID$", + "message": "Smazání tajného klíče s ID: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "permanentlyDeletedSecretWithId": { + "message": "Trvalé smazání tajného klíče s ID: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Obnovení tajného klíče s ID: $SECRET_ID$", "placeholders": { "secret_id": { "content": "$1", @@ -8350,7 +8376,7 @@ } }, "createdSecretWithId": { - "message": "Vytvoření nového tajného klíče s identifikátorem: $SECRET_ID$", + "message": "Vytvoření nového tajného klíče s ID: $SECRET_ID$", "placeholders": { "secret_id": { "content": "$1", @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Přístup k projektu s ID: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Smazání projektu s ID: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Smazání tajného klíče s ID: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Úprava projektu s ID: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Smazání projektu s ID: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Vytvoření nového projektu s ID: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Tyto události jsou jen příklady a neodrážejí skutečné události v rámci Vaší organizace Bitwarden." }, + "viewEvents": { + "message": "Zobrazit události" + }, "cannotCreateCollection": { "message": "Bezplatné organizace mohou mít až 2 sbírky. Chcete-li přidat více sbírek, přejděte na placený tarif." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Zobrazit méně" + }, + "missingTaxId": { + "message": "Chybí DIČ" + }, + "missingTaxIdWarning": { + "message": "Požadovaná akce: V platebních údajích chybí DIČ. Pokud DIČ není uvedeno, mohou být Vaše faktury zatíženy dodatečnou daní." + }, + "moreBreadcrumbs": { + "message": "Více...", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Přidat DIČ" + }, + "missingTaxIdCalloutTitle": { + "message": "Požadovaná akce: Chybí DIČ" + }, + "missingTaxIdCalloutDescription": { + "message": "Pokud není přidáno DIČ, Vaše faktury mohou obsahovat další daň." + }, + "unverifiedTaxIdWarning": { + "message": "Požadovaná akce: Vaše DIČ není ověřeno. Pokud není DIČ ověřeno, Vaše faktury mohou obsahovat další daň." + }, + "editTaxId": { + "message": "Upravit Vaše DIČ" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "DIČ neověřeno" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Zkontrolujte své DIČ pro ověření správného formátu a zda neexistují žádné překlepy." + }, + "pendingVerification": { + "message": "Čeká se na ověření" + }, + "checkInputFormat": { + "message": "Zkontrolujte vstupní formát, zda neobsahuje překlepy." + }, + "exampleTaxIdFormat": { + "message": "Příklad formátu $CODE$: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/cy/messages.json b/apps/web/src/locales/cy/messages.json index 162152a0046..b55f46829c9 100644 --- a/apps/web/src/locales/cy/messages.json +++ b/apps/web/src/locales/cy/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/da/messages.json b/apps/web/src/locales/da/messages.json index cd6b96ff5fd..e25e3135eec 100644 --- a/apps/web/src/locales/da/messages.json +++ b/apps/web/src/locales/da/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Vælg en samling" }, - "importTargetHint": { - "message": "Vælg denne indstilling, hvis importeret filindhold skal flyttet til en $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Filen indeholder ikke-tildelte emner." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Resumé" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Ukendt emne. Du skal muligvis anmode om tilladelse til at tilgå emnet." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Du kan ikke indløse for den aktive konto. Angiv en anden e-mail." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/de/messages.json b/apps/web/src/locales/de/messages.json index da2babf80dc..9a39650f6dd 100644 --- a/apps/web/src/locales/de/messages.json +++ b/apps/web/src/locales/de/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Sammlung auswählen" }, - "importTargetHint": { - "message": "Wähle diese Option, wenn der importierte Dateiinhalt in eine(n) $DESTINATION$ verschoben werden soll", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Die Datei enthält nicht zugewiesene Einträge." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Zusammenfassung" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unbekannter Eintrag. Du musst möglicherweise eine Berechtigung anfordern, um auf diesen Eintrag zuzugreifen." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Du kannst nicht für das aktive Konto einlösen. Gib eine andere E-Mail ein." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Ein neues Geheimnis erstellt mit Kennung: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Diese Ereignisse sind nur Beispiele und spiegeln keine realen Ereignisse in deiner Bitwarden-Organisation wider." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Kostenlose Organisationen können bis zu 2 Sammlungen haben. Upgrade auf ein kostenpflichtiges Abo, um mehr Sammlungen hinzuzufügen." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Weniger anzeigen" + }, + "missingTaxId": { + "message": "Fehlende Steuernummer" + }, + "missingTaxIdWarning": { + "message": "Maßnahme erforderlich: In den Zahlungsdetails fehlt eine Steueridentifikationsnummer. Wenn keine Steuernummer hinzugefügt wird, können deine Rechnungen zusätzliche Steuern enthalten." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Steuernummer hinzufügen" + }, + "missingTaxIdCalloutTitle": { + "message": "Maßnahme erforderlich: Fehlende Steuernummer" + }, + "missingTaxIdCalloutDescription": { + "message": "Wenn keine Steuernummer hinzugefügt wird, können deine Rechnungen zusätzliche Steuern enthalten." + }, + "unverifiedTaxIdWarning": { + "message": "Maßnahme erforderlich: Deine Steueridentifikationsnummer ist nicht verifiziert. Wenn deine Steuernummer nicht verifiziert wurde, können deine Rechnungen zusätzliche Steuern enthalten." + }, + "editTaxId": { + "message": "Bearbeite deine Steuernummer" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Steuernummer nicht verifiziert" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Überprüfe deine Steuernummer, um sicherzustellen, dass das Format korrekt ist und keine Tippfehler enthalten sind." + }, + "pendingVerification": { + "message": "Ausstehende Verifizierung" + }, + "checkInputFormat": { + "message": "Überprüfe das Eingabeformat auf Tippfehler." + }, + "exampleTaxIdFormat": { + "message": "Beispiel $CODE$-Format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/el/messages.json b/apps/web/src/locales/el/messages.json index a5db5245d80..9f98f63c1dd 100644 --- a/apps/web/src/locales/el/messages.json +++ b/apps/web/src/locales/el/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Επιλέξτε μια συλλογή" }, - "importTargetHint": { - "message": "Επιλέξτε αυτή την επιλογή εάν θέλετε τα περιεχόμενα του εισαγόμενου αρχείου να μετακινηθούν σε $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Το αρχείο περιέχει μη εκχωρημένα στοιχεία." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Σύνοψη" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Άγνωστο στοιχείο, ίσως χρειαστεί να ζητήσετε άδεια για να αποκτήσετε πρόσβαση σε αυτό το στοιχείο." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Δεν μπορείτε να κάνετε εξαργύρωση για τον ενεργό λογαριασμό. Εισαγάγετε ένα άλλο email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/en_GB/messages.json b/apps/web/src/locales/en_GB/messages.json index d7a2783acd3..75c952a14ba 100644 --- a/apps/web/src/locales/en_GB/messages.json +++ b/apps/web/src/locales/en_GB/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organisation." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organisations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/en_IN/messages.json b/apps/web/src/locales/en_IN/messages.json index dec3387ca7c..7bdcf445615 100644 --- a/apps/web/src/locales/en_IN/messages.json +++ b/apps/web/src/locales/en_IN/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organisation." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organisations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing TIN" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a TIN number in payment details. If a TIN is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a TIN" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing TIN" + }, + "missingTaxIdCalloutDescription": { + "message": "If a TIN is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your TIN number is unverified. If your TIN is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your TIN" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "TIN unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your TIN to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/eo/messages.json b/apps/web/src/locales/eo/messages.json index abfc97f163c..6340519efe0 100644 --- a/apps/web/src/locales/eo/messages.json +++ b/apps/web/src/locales/eo/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Resumo" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/es/messages.json b/apps/web/src/locales/es/messages.json index 3b0ae219cc6..a8de64b622b 100644 --- a/apps/web/src/locales/es/messages.json +++ b/apps/web/src/locales/es/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Seleccione una colección" }, - "importTargetHint": { - "message": "Seleccione esta opción si desea que el contenido del archivo importado se traslade a un $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "El archivo contiene elementos no asignados." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Resumen" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Elemento desconocido, puede que necesite solicitar permiso para acceder a este elemento." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "No se puede canjear para la cuenta activa. Escriba un correo diferente." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/et/messages.json b/apps/web/src/locales/et/messages.json index 5e863163ffc..9b94e38bdec 100644 --- a/apps/web/src/locales/et/messages.json +++ b/apps/web/src/locales/et/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Vali kogumik" }, - "importTargetHint": { - "message": "Tee siin valik, kui soovid, et imporditud faili sisu liigutatakse asukohta $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Fail sisaldab määramata kirjeid." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Kokkuvõte" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/eu/messages.json b/apps/web/src/locales/eu/messages.json index 4e490572690..f8ef2fece95 100644 --- a/apps/web/src/locales/eu/messages.json +++ b/apps/web/src/locales/eu/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Laburpena" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Elementu ezezaguna, baliteke elementu hau eskuratzeko baimena eskatu behar izatea." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Ezin da kontu aktiboarekin trukatu. Sartu beste email bat." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/fa/messages.json b/apps/web/src/locales/fa/messages.json index 137767261ea..a24f0c3976e 100644 --- a/apps/web/src/locales/fa/messages.json +++ b/apps/web/src/locales/fa/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "انتخاب یک مجموعه" }, - "importTargetHint": { - "message": "اگر می‌خواهید محتوای فایل وارد شده به $DESTINATION$ منتقل شود، این گزینه را انتخاب کنید", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "فایل حاوی موارد اختصاص نیافته است." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "خلاصه" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "مورد ناشناس، ممکن است برای دسترسی به این مورد نیاز به درخواست مجوز داشته باشید." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "شما نمی‌توانید برای حساب فعال استفاده کنید. ایمیل دیگری وارد کنید." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "یک راز با شناسه‌ی $SECRET_ID$ دسترسی ساخته شد", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "این رویدادها تنها مثال هستند و رویدادهای واقعی درون سازمان Bitwarden شما را نشان نمی‌دهند." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "سازمان‌های رایگان می‌توانند حداکثر تا ۲ مجموعه داشته باشند. برای اضافه کردن مجموعه‌های بیشتر، به طرح پولی ارتقا دهید." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/fi/messages.json b/apps/web/src/locales/fi/messages.json index 990619f63ac..6304d4135e9 100644 --- a/apps/web/src/locales/fi/messages.json +++ b/apps/web/src/locales/fi/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Valitse kokoelma" }, - "importTargetHint": { - "message": "Valitse tämä, jos haluat tuoda tiedoston sisällön kohteeseen \"$DESTINATION$\".", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Tiedosto sisältää määrittämättömiä kohteita." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Yhteenveto" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Tuntematon kohde, jonka käyttöön joudut mahdollisesti pyytämään lupaa." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Et voi lunastaa aktiiviselle tilille. Syötä eri sähköpostiosoite." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/fil/messages.json b/apps/web/src/locales/fil/messages.json index ee6fab860af..765e39af077 100644 --- a/apps/web/src/locales/fil/messages.json +++ b/apps/web/src/locales/fil/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Buod" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Hindi kilalang item, maaaring kailanganin mong humiling ng pahintulot upang ma access ang item na ito." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Hindi ka maaaring tubusin para sa aktibong account. Magpasok ng ibang email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/fr/messages.json b/apps/web/src/locales/fr/messages.json index c2232ce0971..4a64b44549d 100644 --- a/apps/web/src/locales/fr/messages.json +++ b/apps/web/src/locales/fr/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Sélectionnez une collection" }, - "importTargetHint": { - "message": "Sélectionnez cette option si vous voulez que le contenu du fichier importé soit déplacé vers un(e) $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Sélectionnez cette option si vous voulez que le contenu du fichier importé soit déplacé vers une collection" + }, + "importTargetHintFolder": { + "message": "Sélectionnez cette option si vous voulez que le contenu du fichier importé soit déplacé vers un dossier" }, "importUnassignedItemsError": { "message": "Le fichier contient des éléments non assignés." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Afficher le résumé des prix" + }, + "hidePricingSummary": { + "message": "Cacher le résumé des prix" + }, "summary": { "message": "Récapitulatif" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Élément inconnu, vous devrez peut-être demander l'autorisation d'accéder à cet élément." }, + "unknownSecret": { + "message": "Secret inconnu, vous devrez peut-être demander l'autorisation d'accéder à ce secret." + }, + "unknownProject": { + "message": "Projet inconnu, vous devrez peut-être demander l'autorisation d'accéder à ce projet." + }, "cannotSponsorSelf": { "message": "Vous ne pouvez pas réclamer pour le compte actif. Saisissez un courriel différent." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "A supprimé définitivement un secret avec l'identifiant : $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "A récupéré un secret avec l'identifiant : $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "A créé un secret avec identifiant : $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "A accédé à un projet avec l'identifiant : $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Identifiant du projet supprimé : $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Identifiant secret supprimé : $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "A modifié un projet avec l'identifiant : $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "A supprimé un projet avec l'identifiant : $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "A créé un projet avec l'identifiant : $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Ces événements sont des exemples et ne reflètent pas les événements réels au sein de votre organisation Bitwarden." }, + "viewEvents": { + "message": "Afficher les événements" + }, "cannotCreateCollection": { "message": "Les organisations gratuites peuvent avoir jusqu'à 2 collections. Passez à une offre payante pour ajouter plus de collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Afficher moins" + }, + "missingTaxId": { + "message": "ID de Taxes manquant" + }, + "missingTaxIdWarning": { + "message": "Action requise : Il vous manque un ID de Taxes dans les détails du paiement. Si un ID de Taxes n'est pas ajouté, vos factures peuvent inclure des taxes supplémentaires." + }, + "moreBreadcrumbs": { + "message": "Plus de fil d'Ariane", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Ajouter un ID de Taxes" + }, + "missingTaxIdCalloutTitle": { + "message": "Action requise : ID de Taxes manquant" + }, + "missingTaxIdCalloutDescription": { + "message": "Si un ID de Taxes n'est pas ajouté, vos factures peuvent inclure des taxes supplémentaires." + }, + "unverifiedTaxIdWarning": { + "message": "Action requise : Votre ID de Taxes n'est pas vérifié. Si votre ID de Taxes n'est pas vérifié, vos factures peuvent inclure des taxes supplémentaires." + }, + "editTaxId": { + "message": "Modifier votre ID de Taxes" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "ID de Taxes non vérifié" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Vérifiez votre ID de Taxes pour vérifier que le format est correct et qu'il n'y a pas de fautes de frappe." + }, + "pendingVerification": { + "message": "Vérification en attente" + }, + "checkInputFormat": { + "message": "Vérifier le format d'entrée pour les fautes de frappe." + }, + "exampleTaxIdFormat": { + "message": "Exemple de format $CODE$ : $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/gl/messages.json b/apps/web/src/locales/gl/messages.json index 28de0043888..b74bd25864d 100644 --- a/apps/web/src/locales/gl/messages.json +++ b/apps/web/src/locales/gl/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/he/messages.json b/apps/web/src/locales/he/messages.json index 2958e0d133d..5e72a211b86 100644 --- a/apps/web/src/locales/he/messages.json +++ b/apps/web/src/locales/he/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "בחר אוסף" }, - "importTargetHint": { - "message": "בחר באפשרות זו אם ברצונך להעביר את תוכן הקובץ המיובא אל $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "קובץ מכיל פריטים לא מוקצים." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "סיכום" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "פריט לא ידוע, ייתכן שאתה צריך לבקש הרשאה כדי לגשת אל פריט זה." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "אינך יכול לממש עבור החשבון הפעיל. הזן דוא\"ל אחר." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "האירועים האלה הם דוגמאות בלבד ולא משקפים אירועים אמיתיים בתוך ארגון ה־Bitwarden שלך." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "לארגונים חינמיים יכולים להיות עד 2 אוספים. שדרג לתוכנית בתשלום כדי להוסיף עוד אוספים." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/hi/messages.json b/apps/web/src/locales/hi/messages.json index bed267c7d0a..0ecc0608258 100644 --- a/apps/web/src/locales/hi/messages.json +++ b/apps/web/src/locales/hi/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/hr/messages.json b/apps/web/src/locales/hr/messages.json index 9c8580d8da1..724f028c5d7 100644 --- a/apps/web/src/locales/hr/messages.json +++ b/apps/web/src/locales/hr/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Odaberi zbirku" }, - "importTargetHint": { - "message": "Odaberi ovu opciju ako sadržaj uvezene datoteke želiš spremiti u $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Datoteka sadrži nedodijeljene stavke." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Sažetak" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Nepoznata stavka. Možda trebaš tražiti dozvolu za pristup ovoj stavci." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Ne možeš iskorisiti za aktivi račun. Unesi drugu adresu e-pošte." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Stvorena nova tajna s identifikatorom: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Ovi događaji su samo primjeri i ne odražavaju stvarne događaje unutar tvoje Bitwarden organizacije." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Besplatne organizacije mogu imati do 2 zbirke. Nadogradi na plaćeni plan za dodavanje više zbirki." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Pokaži manje" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/hu/messages.json b/apps/web/src/locales/hu/messages.json index e829c27a2ee..e79902e23b2 100644 --- a/apps/web/src/locales/hu/messages.json +++ b/apps/web/src/locales/hu/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Gyűjtemény kiválasztása" }, - "importTargetHint": { - "message": "Válasszuk ezt a lehetőséget, ha azt akarjuk, hogy az importált fájl tartalma $DESTINATION$ helyre kerüljön", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Válasszuk ezt az opciót, ha azt akarjuk, hogy az importált fájl tartalma egy gyűjteménybe kerüljön." + }, + "importTargetHintFolder": { + "message": "Válasszuk ezt az opciót, ha azt akarjuk, hogy az importált fájl tartalma egy mappába kerüljön." }, "importUnassignedItemsError": { "message": "A fájl hozzá nem rendelt elemeket tartalmaz." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Árösszegzés megjelenítése" + }, + "hidePricingSummary": { + "message": "Árösszegzés elrejtése" + }, "summary": { "message": "Összegzés" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Ismeretlen elem, lehet hogy egy másik fiókkal bejelentkezni az elem eléréséhez." }, + "unknownSecret": { + "message": "Ismeretlen a titkos kód, előfordulhat, hogy engedélyt kell kérni a titkos kód eléréséhez." + }, + "unknownProject": { + "message": "Ismeretlen a projekt, előfordulhat, hogy engedélyt kell kérni a projekt eléréséhez." + }, "cannotSponsorSelf": { "message": "Az aktív számlára nem váltható be. Másik email címet kell megadni." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "A titkos kód törlése megtörtént egy azonosítóval: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Ey titkkos kód visszaállításra került egy azonosítóval: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Új titkos adat létrehozása történt egy azonosítóval: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Egy projekt hozzáférésre került egy azonosítóval: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Törölt projek tazonosító: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Törölt titkos kód azonosító: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Egy projekt szerkesztése megtörtént egy azonosítóval: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Egy projekt törlése megtörtént egy azonosítóval: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Egy új projekt létrehozásra került egy azonosítóval: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Ezek az események csak példák és nem tükröznek valós eseményeket a Bitwarden szervezetén belül." }, + "viewEvents": { + "message": "Események megtekintése" + }, "cannotCreateCollection": { "message": "Az ingyenes szervezeteknek legfeljebb 2 gyűjteményük lehet. Térjünk át egy fizetett csomagra további gyűjtemények hozzáadásához." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Kevesebb megjelenítése" + }, + "missingTaxId": { + "message": "Hiányzik az adó azonosító." + }, + "missingTaxIdWarning": { + "message": "Intézkedés szükséges: Hiányzik egy adó azonosító szám a fizetési adatokból. Ha nincs hozzáadva adó azonosító, a számlák további adót is tartalmazhatnak." + }, + "moreBreadcrumbs": { + "message": "További morzsamenük", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Adó azonosító hozzáadása" + }, + "missingTaxIdCalloutTitle": { + "message": "Intézkedés szükséges: Hiányzik az adó azonosító." + }, + "missingTaxIdCalloutDescription": { + "message": "Ha nincs hozzáadva adó azonosító, a számlák további adót is tartalmazhatnak." + }, + "unverifiedTaxIdWarning": { + "message": "Intézkedés szükséges: Az adó azonosító száma nem ellenőrzött. Ha az adó azonosító nincs ellenőrizve, a számlák további adót is tartalmazhatnak." + }, + "editTaxId": { + "message": "Adó azonosító szerkesztése" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Az adó azonosító nem ellenőrzött." + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Ellenőrizzük az adó azonosítót, hogy ellenőrizzük a formátum helyességét és hogy nincs-e elírás." + }, + "pendingVerification": { + "message": "Függőben lévő ellenőrzés" + }, + "checkInputFormat": { + "message": "ükEllenőrizze a beviteli formátumot az elírásokkal kapcsolatban." + }, + "exampleTaxIdFormat": { + "message": "Például $CODE$ formátuma: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/id/messages.json b/apps/web/src/locales/id/messages.json index 1fa1a4336f5..dda41bbb9d9 100644 --- a/apps/web/src/locales/id/messages.json +++ b/apps/web/src/locales/id/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Pilih koleksi" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Ringkasan" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/it/messages.json b/apps/web/src/locales/it/messages.json index d972b577dba..8978d3475b8 100644 --- a/apps/web/src/locales/it/messages.json +++ b/apps/web/src/locales/it/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Seleziona una raccolta" }, - "importTargetHint": { - "message": "Seleziona questa opzione se vuoi che i contenuti del file di importazione siano spostati in una $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Seleziona questa opzione se vuoi che i contenuti dell'importazione siano salvati in una raccolta" + }, + "importTargetHintFolder": { + "message": "Seleziona questa opzione se vuoi che i contenuti dell'importazione siano salvati in una cartella" }, "importUnassignedItemsError": { "message": "Il file contiene elementi non assegnati." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Mostra riepilogo prezzi" + }, + "hidePricingSummary": { + "message": "Nascondi riepilogo prezzi" + }, "summary": { "message": "Riepilogo" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Elemento sconosciuto, potrebbe essere necessario richiedere autorizzazione per accedere a questo elemento." }, + "unknownSecret": { + "message": "Segreto sconosciuto, potrebbe essere necessario richiedere l'autorizzazione per l'accesso." + }, + "unknownProject": { + "message": "Progetto sconosciuto, potrebbe essere necessario richiedere l'autorizzazione per l'accesso." + }, "cannotSponsorSelf": { "message": "Non puoi riscattare per l'account attivo. Inserisci un'email diversa." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Segreto con identificatore $SECRET_ID$ eliminato in modo permanente", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Segreto con identificatore $SECRET_ID$ ripristinato", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Creato un segreto con identificatore $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accesso al progetto con identificatore $PROJECT_ID$ riuscito.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Progetto con identificatore $PROJECT_ID$ eliminato in modo permanente", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "ID segreto $SECRET_ID$ eliminato", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Progetto con identificatore $PROJECT_ID$ modificato", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Progetto con identificatore $PROJECT_ID$ eliminato", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Creato nuovo progetto con identificatore $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Questi eventi sono solo esempi e non riflettono eventi reali all'interno della tua organizzazione Bitwarden." }, + "viewEvents": { + "message": "Visualizza eventi" + }, "cannotCreateCollection": { "message": "Le organizzazioni gratuite possono avere fino a 2 raccolte. Aggiorna ad un piano a pagamento per crearne di più." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Mostra di meno" + }, + "missingTaxId": { + "message": "Identificatore fiscale mancante" + }, + "missingTaxIdWarning": { + "message": "Azione richiesta: i dettagli del pagamento non includono un identificatore fiscale. Se non lo aggiungi, le tue fatture potrebbero includere imposte aggiuntive." + }, + "moreBreadcrumbs": { + "message": "Ulteriori segmenti", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Aggiungi identificatore fiscale" + }, + "missingTaxIdCalloutTitle": { + "message": "Azione richiesta: identificatore fiscale mancante" + }, + "missingTaxIdCalloutDescription": { + "message": "Se non aggiungi un identificatore fiscale, le tue fatture potrebbero includere imposte aggiuntive." + }, + "unverifiedTaxIdWarning": { + "message": "Azione richiesta: il tuo identificatore fiscale non è verificato. Se non lo verifichi, le tue fatture potrebbero includere imposte aggiuntive." + }, + "editTaxId": { + "message": "Modifica il tuo identificatore fiscale" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Identificatore fiscale non verificato" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Verifica che il formato del tuo identificatore fiscale sia corretto e che non ci siano errori di battitura." + }, + "pendingVerification": { + "message": "In attesa di verifica" + }, + "checkInputFormat": { + "message": "Controlla che non ci siano errori di battitura." + }, + "exampleTaxIdFormat": { + "message": "Esempio formato $CODE$: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/ja/messages.json b/apps/web/src/locales/ja/messages.json index c0420cf47b9..1c97befe579 100644 --- a/apps/web/src/locales/ja/messages.json +++ b/apps/web/src/locales/ja/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "コレクションを選択" }, - "importTargetHint": { - "message": "インポートしたファイルコンテンツを $DESTINATION$ に移動したい場合は、このオプションを選択してください。", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "割り当てられていないアイテムがファイルに含まれています。" @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "概要" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "不明なアイテムです。このアイテムにアクセスするには別のアカウントでログインする必要があります。" }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "有効なアカウントと引き換えることはできません。別のメールアドレスを入力してください。" }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "無料版の組織ではコレクションは 2 つまでです。さらにコレクションを追加するには有料プランにアップグレードしてください。" }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/ka/messages.json b/apps/web/src/locales/ka/messages.json index ebe13e807c1..b183e58498e 100644 --- a/apps/web/src/locales/ka/messages.json +++ b/apps/web/src/locales/ka/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/km/messages.json b/apps/web/src/locales/km/messages.json index 42148397f33..6ab1431d5a4 100644 --- a/apps/web/src/locales/km/messages.json +++ b/apps/web/src/locales/km/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/kn/messages.json b/apps/web/src/locales/kn/messages.json index 446f5cdc6c4..e264b4dcce0 100644 --- a/apps/web/src/locales/kn/messages.json +++ b/apps/web/src/locales/kn/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "ಸಾರಾಂಶ" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/ko/messages.json b/apps/web/src/locales/ko/messages.json index 365dac41865..02febd78c06 100644 --- a/apps/web/src/locales/ko/messages.json +++ b/apps/web/src/locales/ko/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "컬렉션 선택" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "요약" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/lv/messages.json b/apps/web/src/locales/lv/messages.json index bcfc63a63d5..475ef6228b1 100644 --- a/apps/web/src/locales/lv/messages.json +++ b/apps/web/src/locales/lv/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Atlasīt krājumu" }, - "importTargetHint": { - "message": "Šī iespēja jāatlasa, ja ir vēlēšanās ievietotās datnes saturu pārvietot uz $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Šī iespēja jāatlasa, ja ir vēlēšanās ievietotās datnes saturu ievietot krājumā" + }, + "importTargetHintFolder": { + "message": "Šī iespēja jāatlasa, ja ir vēlēšanās ievietotās datnes saturu ievietot mapē" }, "importUnassignedItemsError": { "message": "Datne satur nepiešķirtus vienumus." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Parādīt cenu apkopojumu" + }, + "hidePricingSummary": { + "message": "Paslēpt cenu apkopojumu" + }, "summary": { "message": "Kopsavilkums" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Nezināms vienums, var būt nepieciešams pierakstīties ar citu kontu, lai tam piekļūtu." }, + "unknownSecret": { + "message": "Nezināms noslēpums, var būt nepieciešams pieprasīt atļauju piekļūt tam." + }, + "unknownProject": { + "message": "Nezināms projekts, var būt nepieciešams pieprasīt atļauju piekļūt tam." + }, "cannotSponsorSelf": { "message": "Nevar pielietot izmantotam kontam. Jānorāda cita e-pasta adrese." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Neatgriezeniski identifikatoruzdzēsa noslēpumu ar identifikatoru: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Atjaunoja noslēpumu ar identifikatoru: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Izveidoja noslēpumu ar identifikatoru: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Piekļuva projektam ar Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Izdzēsa projektu ar Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Izdzēsa noslēpumu ar Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Laboja projektu ar identifikatoru: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Izdzēsa projektu ar identifikatoru: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Izveidoja jaunu projektu ar identifikatoru: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "Izstrādātāja rīkkopa", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Šie notikumu ir tikai piemēri, un tie neatspoguļo īstus notikumus Bitwarden apvienībā." }, + "viewEvents": { + "message": "Apskatīt notikumus" + }, "cannotCreateCollection": { "message": "Apvienībās, kuras izmanto Bitwarden bez maksas, var būt līdz 2 krājumiem. Jāpāriet uz maksas plānu, lai pievienotu vairāk krājumu." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Rādīt mazāk" + }, + "missingTaxId": { + "message": "Trūkst nodokļu Id" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "Vairāk norāžu", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Pievienot nodokļu Id" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Labot savu nodokļu Id" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/ml/messages.json b/apps/web/src/locales/ml/messages.json index 92f054f165a..5d44873fbfa 100644 --- a/apps/web/src/locales/ml/messages.json +++ b/apps/web/src/locales/ml/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/mr/messages.json b/apps/web/src/locales/mr/messages.json index d5a250988f3..48e1de061a5 100644 --- a/apps/web/src/locales/mr/messages.json +++ b/apps/web/src/locales/mr/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/my/messages.json b/apps/web/src/locales/my/messages.json index 42148397f33..6ab1431d5a4 100644 --- a/apps/web/src/locales/my/messages.json +++ b/apps/web/src/locales/my/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/nb/messages.json b/apps/web/src/locales/nb/messages.json index 89c19d6f2c1..3909e7ad2c8 100644 --- a/apps/web/src/locales/nb/messages.json +++ b/apps/web/src/locales/nb/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Velg en samling" }, - "importTargetHint": { - "message": "Velg dette alternativet hvis du vil flytte den importerte filens innhold til en $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Filen inneholder utildelte elementer." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Sammendrag" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Ukjent element, du må kanskje logge inn med en annen konto for å få tilgang til dette elementet." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Du kan ikke innløse for den aktive kontoen. Skriv inn en annen e-post." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/ne/messages.json b/apps/web/src/locales/ne/messages.json index 2e2a8eb697d..7ea48fde42f 100644 --- a/apps/web/src/locales/ne/messages.json +++ b/apps/web/src/locales/ne/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/nl/messages.json b/apps/web/src/locales/nl/messages.json index 74f71009b7e..71223d4e880 100644 --- a/apps/web/src/locales/nl/messages.json +++ b/apps/web/src/locales/nl/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Collectie selecteren" }, - "importTargetHint": { - "message": "Kies deze optie als je de geïmporteerde bestandsinhoud wilt verplaatsen naar een $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Kies deze optie als je de geïmporteerde bestandsinhoud naar een collectie wilt verplaatsen" + }, + "importTargetHintFolder": { + "message": "Kies deze optie als je de geïmporteerde bestandsinhoud naar een map wilt verplaatsen" }, "importUnassignedItemsError": { "message": "Bestand bevat niet-toegewezen items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Overzicht prijzen weergeven" + }, + "hidePricingSummary": { + "message": "Overzicht prijzen verbergen" + }, "summary": { "message": "Samenvatting" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Onbekend item, je moet misschien inloggen met een andere account om dit item te kunnen opvragen." }, + "unknownSecret": { + "message": "Onbekend secret, je moet misschien toegang vragen om dit secret te benaderen." + }, + "unknownProject": { + "message": "Onbekend project, je moet misschien toegang vragen om dit project te benaderen." + }, "cannotSponsorSelf": { "message": "Je kunt niet inwisselen voor het actieve account. Voor een ander e-mailadres in." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Secret definitief verwijderd met identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Secret hersteld met identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Nieuw geheim aangemaakt met identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Project gekoppeld met Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Project Id verwijderd: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Secret Id verwijderd: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Project bewerkt met identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Project verwijderd met identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Nieuw project aangemaakt met identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Deze evenementen zijn alleen voorbeelden en weerspiegelen geen echte evenementen binnen je Bitwarden organisatie." }, + "viewEvents": { + "message": "Gebeurtenissen bekijken" + }, "cannotCreateCollection": { "message": "Gratis organisaties kunnen maximaal twee collecties hebben. Upgrade naar een betaald abonnement voor het toevoegen van meer collecties." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Minder weergeven" + }, + "missingTaxId": { + "message": "Btw-nummer ontbreekt" + }, + "missingTaxIdWarning": { + "message": "Actie vereist: je mist een Btw-nummer in de betalingsgegevens. Als je geen btw-nummer toegevoegt, kan het zijn dat je facturen facturen aanvullende belasting bevatten." + }, + "moreBreadcrumbs": { + "message": "Meer broodkruimels", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Btw-nummer toevoegen" + }, + "missingTaxIdCalloutTitle": { + "message": "Actie vereist: btw-nummer ontbreekt" + }, + "missingTaxIdCalloutDescription": { + "message": "Als je geen btw-nummer toegevoegt, kan het zijn dat je facturen facturen aanvullende belasting bevatten." + }, + "unverifiedTaxIdWarning": { + "message": "Actie vereist: je btw-nummer is niet geverifieerd. Als je Btw-nummer niet geverifieerd blijft, kan het zijn dat je facturen facturen aanvullende belasting bevatten." + }, + "editTaxId": { + "message": "Je btw-nummer bewerken" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Btw-nummer niet geverifieerd" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Controleer je btw-nummer om te controleren of het formaat correct is er geen typefouten zijn." + }, + "pendingVerification": { + "message": "In afwachting van verificatie" + }, + "checkInputFormat": { + "message": "Controleer het invoerformaat op typefouten." + }, + "exampleTaxIdFormat": { + "message": "Voorbeeld $CODE$ formaat: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/nn/messages.json b/apps/web/src/locales/nn/messages.json index 05ff9c62561..484a110c2ab 100644 --- a/apps/web/src/locales/nn/messages.json +++ b/apps/web/src/locales/nn/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/or/messages.json b/apps/web/src/locales/or/messages.json index 42148397f33..6ab1431d5a4 100644 --- a/apps/web/src/locales/or/messages.json +++ b/apps/web/src/locales/or/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/pl/messages.json b/apps/web/src/locales/pl/messages.json index 0421a1dbb1c..df24c334031 100644 --- a/apps/web/src/locales/pl/messages.json +++ b/apps/web/src/locales/pl/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Wybierz kolekcję" }, - "importTargetHint": { - "message": "Wybierz tę opcję, jeśli chcesz, aby zawartość zaimportowanego pliku została przeniesiona do $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Plik zawiera nieprzypisane elementy." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Podsumowanie" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Nieznany element, być może będziesz musiał zalogować się na inne konto, aby uzyskać dostęp do tego elementu." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Nie możesz zrealizować dla aktywnego konta. Wprowadź inny adres e-mail." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Utworzono nowy sekret z identyfikatorem: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Te wydarzenia są tylko przykładami i nie odzwierciedlają rzeczywistych wydarzeń w Twojej organizacji Bitwarden." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Darmowe organizacje mogą posiadać maksymalnie 2 kolekcje. Aby dodać więcej kolekcji, przejdź na plan płatny." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/pt_BR/messages.json b/apps/web/src/locales/pt_BR/messages.json index fc77261296b..8e49cfc1a03 100644 --- a/apps/web/src/locales/pt_BR/messages.json +++ b/apps/web/src/locales/pt_BR/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Selecione uma coleção" }, - "importTargetHint": { - "message": "Selecione esta opção se você quer o conteúdo do arquivo importado movido para $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Arquivo contém itens não atribuídos." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Resumo" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Item desconhecido, talvez você precise fazer login com outra conta para acessar este item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Você não pode resgatar a conta ativa. Digite um e-mail diferente." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Esses eventos são apenas exemplos e não refletem eventos reais na sua organização do Bitwarden." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Organizações gratuitas podem ter até duas coleções. Faça o upgrade para um plano pago para adicionar mais coleções." }, @@ -11005,9 +11088,60 @@ "message": "To resubscribe, contact Bitwarden Customer Support." }, "showMore": { - "message": "Show more" + "message": "Mostrar mais" }, "showLess": { - "message": "Show less" + "message": "Mostrar menos" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/pt_PT/messages.json b/apps/web/src/locales/pt_PT/messages.json index 58cac178a0c..6d85c096e5f 100644 --- a/apps/web/src/locales/pt_PT/messages.json +++ b/apps/web/src/locales/pt_PT/messages.json @@ -1279,7 +1279,7 @@ "message": "Dica da palavra-passe mestra" }, "masterPassHintText": { - "message": "Se se esquecer da sua palavra-passe, a dica da palavra-passe pode ser enviada para o seu e-mail. Máximo de $CURRENT$/$MAXIMUM$ carateres.", + "message": "Se se esquecer da sua palavra-passe, a dica da palavra-passe pode ser enviada para o seu e-mail. Máximo de $CURRENT$/$MAXIMUM$ caracteres.", "placeholders": { "current": { "content": "$1", @@ -1322,7 +1322,7 @@ "message": "É necessário reescrever a palavra-passe mestra." }, "masterPasswordMinlength": { - "message": "A palavra-passe mestra deve ter pelo menos $VALUE$ carateres.", + "message": "A palavra-passe mestra deve ter pelo menos $VALUE$ caracteres.", "description": "The Master Password must be at least a specific number of characters long.", "placeholders": { "value": { @@ -1703,15 +1703,15 @@ "message": "Mínimo de números" }, "minSpecial": { - "message": "Mínimo de carateres especiais", + "message": "Mínimo de caracteres especiais", "description": "Minimum special characters" }, "ambiguous": { - "message": "Evitar carateres ambíguos", + "message": "Evitar caracteres ambíguos", "description": "deprecated. Use avoidAmbiguous instead." }, "avoidAmbiguous": { - "message": "Evitar carateres ambíguos", + "message": "Evitar caracteres ambíguos", "description": "Label for the avoid ambiguous characters checkbox." }, "length": { @@ -1733,7 +1733,7 @@ "description": "deprecated. Use numbersLabel instead." }, "specialCharacters": { - "message": "Carateres especiais (!@#$%^&*)" + "message": "Caracteres especiais (!@#$%^&*)" }, "numWords": { "message": "Número de palavras" @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Selecionar uma coleção" }, - "importTargetHint": { - "message": "Selecione esta opção se pretender que o conteúdo do ficheiro importado seja transferido para $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Selecione esta opção se pretender que o conteúdo do ficheiro importado seja transferido para uma coleção" + }, + "importTargetHintFolder": { + "message": "Selecione esta opção se pretender que o conteúdo do ficheiro importado seja transferido para uma pasta" }, "importUnassignedItemsError": { "message": "O ficheiro contém itens não atribuídos." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Mostrar resumo de preços" + }, + "hidePricingSummary": { + "message": "Ocultar resumo de preços" + }, "summary": { "message": "Resumo" }, @@ -4882,16 +4884,16 @@ } }, "policyInEffectUppercase": { - "message": "Contém um ou mais carateres em maiúsculas" + "message": "Contém um ou mais caracteres em maiúsculas" }, "policyInEffectLowercase": { - "message": "Contém um ou mais carateres em minúsculas" + "message": "Contém um ou mais caracteres em minúsculas" }, "policyInEffectNumbers": { "message": "Contém um ou mais números" }, "policyInEffectSpecial": { - "message": "Contém um ou mais dos seguintes carateres especiais $CHARS$", + "message": "Contém um ou mais dos seguintes caracteres especiais $CHARS$", "placeholders": { "chars": { "content": "$1", @@ -6803,7 +6805,7 @@ "message": "obrigatório" }, "charactersCurrentAndMaximum": { - "message": "$CURRENT$/$MAX$ máximo de carateres", + "message": "$CURRENT$/$MAX$ máximo de caracteres", "placeholders": { "current": { "content": "$1", @@ -6816,7 +6818,7 @@ } }, "characterMaximum": { - "message": "Máximo de $MAX$ carateres", + "message": "Máximo de $MAX$ caracteres", "placeholders": { "max": { "content": "$1", @@ -6955,7 +6957,7 @@ } }, "passwordLengthRecommendationHint": { - "message": " Utilize $RECOMMENDED$ carateres ou mais para gerar uma palavra-passe forte.", + "message": " Utilize $RECOMMENDED$ caracteres ou mais para gerar uma palavra-passe forte.", "description": "Appended to `spinboxBoundariesHint` to recommend a length to the user. This must include any language-specific 'sentence' separator characters (e.g. a space in english).", "placeholders": { "recommended": { @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Item desconhecido, poderá ser necessário pedir autorização para aceder a este item." }, + "unknownSecret": { + "message": "Segredo desconhecido, poderá ser necessário pedir autorização para aceder a este segredo." + }, + "unknownProject": { + "message": "Projeto desconhecido, poderá ser necessário pedir autorização para aceder a este projeto." + }, "cannotSponsorSelf": { "message": "Não é possível resgatar da conta ativa. Introduza um e-mail diferente." }, @@ -7309,7 +7317,7 @@ "message": "O campo não é um endereço de e-mail." }, "inputMinLength": { - "message": "O campo deve ter pelo menos $COUNT$ carateres.", + "message": "O campo deve ter pelo menos $COUNT$ caracteres.", "placeholders": { "count": { "content": "$1", @@ -7318,7 +7326,7 @@ } }, "inputMaxLength": { - "message": "O campo não pode exceder os $COUNT$ carateres de comprimento.", + "message": "O campo não pode exceder os $COUNT$ caracteres de comprimento.", "placeholders": { "count": { "content": "$1", @@ -7327,7 +7335,7 @@ } }, "inputForbiddenCharacters": { - "message": "Não são permitidos os seguintes carateres: $CHARACTERS$", + "message": "Não são permitidos os seguintes caracteres: $CHARACTERS$", "placeholders": { "characters": { "content": "$1", @@ -7336,7 +7344,7 @@ } }, "inputMinValue": { - "message": "O valor do campo tem de ser, pelo menos, $MIN$ carateres.", + "message": "O valor do campo tem de ser, pelo menos, $MIN$ caracteres.", "placeholders": { "min": { "content": "$1", @@ -7345,7 +7353,7 @@ } }, "inputMaxValue": { - "message": "O valor do campo não pode exceder os $MAX$ carateres.", + "message": "O valor do campo não pode exceder os $MAX$ caracteres.", "placeholders": { "max": { "content": "$1", @@ -7477,11 +7485,11 @@ "message": "Limpar tudo" }, "toggleCharacterCount": { - "message": "Mostrar/ocultar contagem de carateres", + "message": "Mostrar/ocultar contagem de caracteres", "description": "'Character count' describes a feature that displays a number next to each character of the password." }, "passwordCharacterCount": { - "message": "Contagem de carateres da palavra-passe", + "message": "Contagem de caracteres da palavra-passe", "description": "'Character count' describes a feature that displays a number next to each character of the password." }, "hide": { @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Eliminou permanentemente um segredo com o identificador: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restaurou um segredo com o identificador: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Criou um novo segredo com o identificador: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Acedeu a um projeto com o ID: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "ID do projeto eliminado: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "ID do segredo eliminado: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Editou um projeto com o identificador: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Eliminou um projeto com o identificador: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Criou um novo projeto com o identificador: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -8458,7 +8538,7 @@ "message": "Palavra-passe fraca identificada e encontrada numa violação de dados. Utilize uma palavra-passe forte e única para proteger a sua conta. Tem a certeza de que pretende utilizar esta palavra-passe?" }, "characterMinimum": { - "message": "$LENGTH$ carateres no mínimo", + "message": "$LENGTH$ caracteres no mínimo", "placeholders": { "length": { "content": "$1", @@ -8467,7 +8547,7 @@ } }, "masterPasswordMinimumlength": { - "message": "A palavra-passe mestra deve ter pelo menos $LENGTH$ carateres.", + "message": "A palavra-passe mestra deve ter pelo menos $LENGTH$ caracteres.", "placeholders": { "length": { "content": "$1", @@ -10223,10 +10303,10 @@ "description": "The text, 'API', is an acronym and should not be translated." }, "showCharacterCount": { - "message": "Mostrar contagem de carateres" + "message": "Mostrar contagem de caracteres" }, "hideCharacterCount": { - "message": "Ocultar contagem de carateres" + "message": "Ocultar contagem de caracteres" }, "editAccess": { "message": "Editar acesso" @@ -10247,7 +10327,7 @@ "message": "Introduza o ID do HTML, o nome, a aria-label ou o placeholder do campo." }, "uppercaseDescription": { - "message": "Incluir carateres em maiúsculas", + "message": "Incluir caracteres em maiúsculas", "description": "Tooltip for the password generator uppercase character checkbox" }, "uppercaseLabel": { @@ -10255,7 +10335,7 @@ "description": "Label for the password generator uppercase character checkbox" }, "lowercaseDescription": { - "message": "Incluir carateres em minúsculas", + "message": "Incluir caracteres em minúsculas", "description": "Full description for the password generator lowercase character checkbox" }, "lowercaseLabel": { @@ -10271,7 +10351,7 @@ "description": "Label for the password generator numbers checkbox" }, "specialCharactersDescription": { - "message": "Incluir carateres especiais", + "message": "Incluir caracteres especiais", "description": "Full description for the password generator special characters checkbox" }, "addAttachment": { @@ -10496,7 +10576,7 @@ "message": "Domínio reivindicado" }, "organizationNameMaxLength": { - "message": "O nome da organização não pode exceder 50 carateres." + "message": "O nome da organização não pode exceder 50 caracteres." }, "rotationCompletedTitle": { "message": "Rotação de chaves bem-sucedida" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Estes eventos são apenas exemplos e não refletem eventos reais na sua organização Bitwarden." }, + "viewEvents": { + "message": "Ver eventos" + }, "cannotCreateCollection": { "message": "As organizações gratuitas podem ter até 2 coleções. Atualize para um plano pago para adicionar mais coleções." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Mostrar menos" + }, + "missingTaxId": { + "message": "NIF em falta" + }, + "missingTaxIdWarning": { + "message": "Ação necessária: Está a faltar um NIF nos detalhes de pagamento. Se um número de identificação fiscal não for adicionado, as suas faturas podem incluir impostos adicionais." + }, + "moreBreadcrumbs": { + "message": "Mais da navegação estrutural", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Adicionar um NIF" + }, + "missingTaxIdCalloutTitle": { + "message": "Ação necessária: NIF em falta" + }, + "missingTaxIdCalloutDescription": { + "message": "Se não for adicionado um NIF, as suas faturas podem incluir impostos adicionais." + }, + "unverifiedTaxIdWarning": { + "message": "Ação necessária: O seu NIF não foi verificado. Se o seu número de identificação fiscal não for verificado, as suas faturas podem incluir impostos adicionais." + }, + "editTaxId": { + "message": "Edite o seu NIF" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "NIF não verificado" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Verifique o seu NIF para verificar se o formato está correto e se não existem erros de digitação." + }, + "pendingVerification": { + "message": "Verificação pendente" + }, + "checkInputFormat": { + "message": "Verifique se existem erros de digitação no formato de entrada." + }, + "exampleTaxIdFormat": { + "message": "Exemplo de formato de $CODE$: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/ro/messages.json b/apps/web/src/locales/ro/messages.json index 7a97124efff..36bbbb6f830 100644 --- a/apps/web/src/locales/ro/messages.json +++ b/apps/web/src/locales/ro/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Rezumat" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Articol necunoscut, ar putea fi necesară solicitarea permisiunii de a accesa acest articol." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Nu puteți revendica pentru contul activ. Introduceți un alt e-mail." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/ru/messages.json b/apps/web/src/locales/ru/messages.json index 5cdd746d6c7..76e1e2a09fc 100644 --- a/apps/web/src/locales/ru/messages.json +++ b/apps/web/src/locales/ru/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Выберите коллекцию" }, - "importTargetHint": { - "message": "Выберите эту опцию, если хотите, чтобы содержимое импортированного файла было перемещено в $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Выберите эту опцию, если хотите, чтобы содержимое импортированного файла было перемещено в коллекцию" + }, + "importTargetHintFolder": { + "message": "Выберите эту опцию, если хотите, чтобы содержимое импортированного файла было перемещено в папку" }, "importUnassignedItemsError": { "message": "Файл содержит неназначенные элементы." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Итого" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Неизвестный элемент. Вам может потребоваться запросить разрешение на доступ к этому элементу." }, + "unknownSecret": { + "message": "Неизвестный секрет. Вам может потребоваться запросить разрешение на доступ к этому секрету." + }, + "unknownProject": { + "message": "Неизвестный проект. Вам может потребоваться запросить разрешение на доступ к этому проекту." + }, "cannotSponsorSelf": { "message": "Вы не можете активировать существующий аккаунт. Введите другой адрес электронной почты." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Безвозвратно удален секрет с идентификатором: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Восстановлен секрет с идентификатором: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Создан новый секрет с идентификатором: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Получен доступ к проекту с ID: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Удален проект с ID: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Удален секрет с ID: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Изменен проект с идентификатором: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Удален проект с идентификатором: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Создан новый проект с идентификатором: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Эти события являются лишь примерами и не отражают текущих событий вашей организации Bitwarden." }, + "viewEvents": { + "message": "Просмотр событий" + }, "cannotCreateCollection": { "message": "В бесплатных организациях может быть до 2 коллекций. Перейдите на платный план, чтобы добавить больше коллекций." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Меньше" + }, + "missingTaxId": { + "message": "Отсутствует идентификационный номер налогоплательщика" + }, + "missingTaxIdWarning": { + "message": "Необходимые действия: В платежных реквизитах не указан идентификационный номер налогоплательщика. Если идентификационный номер налогоплательщика не указан, в ваших счетах могут быть указаны дополнительные налоги." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Добавить идентификационный номер налогоплательщика" + }, + "missingTaxIdCalloutTitle": { + "message": "Требуется действие: отсутствует идентификационный номер налогоплательщика" + }, + "missingTaxIdCalloutDescription": { + "message": "Если идентификационный номер налогоплательщика не добавлен, в ваших счетах может быть указан дополнительный налог." + }, + "unverifiedTaxIdWarning": { + "message": "Необходимые действия: Ваш идентификационный номер налогоплательщика не подтвержден. Если ваш идентификационный номер налогоплательщика не подтвержден, в ваших счетах могут быть указаны дополнительные налоги." + }, + "editTaxId": { + "message": "Изменить ваш идентификационный номер налогоплательщика" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Идентификационный номер налогоплательщика не подтвержден" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Проверьте свой идентификационный номер налогоплательщика, чтобы убедиться в правильности формата и отсутствии опечаток." + }, + "pendingVerification": { + "message": "Ожидание верификации" + }, + "checkInputFormat": { + "message": "Проверьте формат ввода на наличие опечаток." + }, + "exampleTaxIdFormat": { + "message": "Пример формата $CODE$: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/si/messages.json b/apps/web/src/locales/si/messages.json index ad39f61f4f8..ab29812f383 100644 --- a/apps/web/src/locales/si/messages.json +++ b/apps/web/src/locales/si/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/sk/messages.json b/apps/web/src/locales/sk/messages.json index 8eecc64856f..f2c493a5f9f 100644 --- a/apps/web/src/locales/sk/messages.json +++ b/apps/web/src/locales/sk/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Vyberte zbierku" }, - "importTargetHint": { - "message": "Zvoľte túto možnosť ak chcete obsah importovaného súboru presunúť do $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Zvoľte túto možnosť, ak chcete obsah importovaného súboru presunúť do zbierky" + }, + "importTargetHintFolder": { + "message": "Zvoľte túto možnosť, ak chcete obsah importovaného súboru presunúť do priečinka" }, "importUnassignedItemsError": { "message": "Súbor obsahuje nepridelené položky." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Zobraziť prehľad cien" + }, + "hidePricingSummary": { + "message": "Skryť prehľad cien" + }, "summary": { "message": "Súhrn" }, @@ -5263,11 +5265,11 @@ "message": "Stiahnuť prílohy" }, "sendAccessPasswordTitle": { - "message": "Enter the password to view this Send", + "message": "Ak chcete zobraziť Send, zadajte heslo", "description": "Title of the Send password authentication screen." }, "sendAccessContentTitle": { - "message": "View Send", + "message": "Zobraziť Send", "description": "Title of the Send view content screen." }, "sendAccessUnavailable": { @@ -5431,34 +5433,34 @@ "message": "Požadovanie vlastníctva údajov organizácie" }, "organizationDataOwnershipDesc": { - "message": "Require all items to be owned by an organization, removing the option to store items at the account level.", + "message": "Odstrániť možnosť uložiť položku pod kontom a požadovať aby všetky položky boli vlastnené organizáciou.", "description": "This is the policy description shown in the policy list." }, "organizationDataOwnershipContent": { - "message": "All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the ", + "message": "Všetky položky budú vo vlastníctve organizácie a uložené v nej, čo umožní kontrolu, prehľadnosť a vykazovanie v rámci celej organizácie. Po zapnutí bude každému členovi k dispozícii predvolená zbierka na ukladanie položiek. Dozvedieť sa viac o správe ", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'All items will be owned and saved to the organization, enabling organization-wide controls, visibility, and reporting. When turned on, a default collection be available for each member to store items. Learn more about managing the credential lifecycle.'" }, "organizationDataOwnershipContentAnchor": { - "message": "credential lifecycle", + "message": "životného cyklu položiek", "description": "This will be used as a hyperlink" }, "organizationDataOwnershipWarningTitle": { - "message": "Are you sure you want to proceed?" + "message": "Naozaj chcete pokračovať?" }, "organizationDataOwnershipWarning1": { - "message": "will remain accessible to members" + "message": "bude naďalej dostupná všetkým členom" }, "organizationDataOwnershipWarning2": { - "message": "will not be automatically selected when creating new items" + "message": "prestane byť predvolenou voľbou pri vytváraní nových položiek" }, "organizationDataOwnershipWarning3": { - "message": "cannot be managed from the Admin Console until the user is offboarded" + "message": "nemôže byt spravovaná prostredníctvom Konzoly Správcu pokiaľ nebude používateľ odhlásený" }, "organizationDataOwnershipWarningContentTop": { - "message": "By turning this policy off, the default collection: " + "message": "Ak vypnete toto pravidlo, predvolená zbierka: " }, "organizationDataOwnershipWarningContentBottom": { - "message": "Learn more about the ", + "message": "Viac informácií o ", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Learn more about the credential lifecycle.'" }, "personalOwnership": { @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Neznáma položka, na prístup k tejto položke sa možno budete musieť prihlásiť pomocou iného účtu." }, + "unknownSecret": { + "message": "Neznáma položka možno potrebujete požiadať o prístup k tejto položke." + }, + "unknownProject": { + "message": "Neznámy projekt, možno potrebujete požiadať o prístup k tomuto projektu." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Natrvalo odstránená položka s identifikátorom: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Obnovená položka s identifikátorom: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Vytvorená nová položka s identifikátorom: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Pristúp k projektu s identifikátorom: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Odstránený projekt s identifikátorom: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Odstránená položka s identifikátorom: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Upravený projekt s identifikátorom: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Odstránený projekt s identifikátorom: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Vytvorený nový projekt s identifikátorom: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "Zobraziť udalosti" + }, "cannotCreateCollection": { "message": "Bezplatné organizácie môžu mat maximálne dve zbierky. Ak chcete pridať viac zbierok povýšte na platené predplatné." }, @@ -10999,15 +11082,66 @@ "message": "Neobmedzený počet položiek a projektov" }, "providersubscriptionCanceled": { - "message": "Subscription canceled" + "message": "Predplatné bolo zrušené" }, "providersubCanceledmessage": { - "message": "To resubscribe, contact Bitwarden Customer Support." + "message": "Ak chcete obnoviť predplatné, kontaktujte zákaznícku podporu Bitwarden." }, "showMore": { - "message": "Show more" + "message": "Zobraziť viac" }, "showLess": { - "message": "Show less" + "message": "Zobraziť menej" + }, + "missingTaxId": { + "message": "Chýbajúce daňové identifikačné číslo" + }, + "missingTaxIdWarning": { + "message": "Požadovaná akcia: V platobných údajoch chýba daňové identifikačné číslo. Ak nepridáte daňové identifikačné číslo, vaše faktúry môžu zahŕňať dodatočnú daň." + }, + "moreBreadcrumbs": { + "message": "Viac", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Pridať daňové identifikačné číslo" + }, + "missingTaxIdCalloutTitle": { + "message": "Požadovaná akcia: Chýbajúce daňové identifikačné číslo" + }, + "missingTaxIdCalloutDescription": { + "message": "Ak nepridáte daňové identifikačné číslo, vaše faktúry môžu zahŕňať dodatočnú daň." + }, + "unverifiedTaxIdWarning": { + "message": "Požadovaná akcia: Vaše daňové identifikačné číslo nie je overene. Ak neoveríte daňové identifikačné číslo, vaše faktúry môžu zahŕňať dodatočnú daň." + }, + "editTaxId": { + "message": "Upraviť vaše daňove identifikačné číslo" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Neoverené daňové identifikačné číslo" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Skontrolujte daňové identifikačné číslo a uistite sa ze má správny formát a neobsahuje preklep." + }, + "pendingVerification": { + "message": "Čaká sa na overenie" + }, + "checkInputFormat": { + "message": "Skontrolujte formát vstupu na preklepy." + }, + "exampleTaxIdFormat": { + "message": "Príklad formátu pre $CODE$: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/sl/messages.json b/apps/web/src/locales/sl/messages.json index 503a4d47320..1057caeb205 100644 --- a/apps/web/src/locales/sl/messages.json +++ b/apps/web/src/locales/sl/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/sr_CS/messages.json b/apps/web/src/locales/sr_CS/messages.json index 93a10704236..c9c857ded51 100644 --- a/apps/web/src/locales/sr_CS/messages.json +++ b/apps/web/src/locales/sr_CS/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/sr_CY/messages.json b/apps/web/src/locales/sr_CY/messages.json index 573e93a51dd..f09ff8a5b05 100644 --- a/apps/web/src/locales/sr_CY/messages.json +++ b/apps/web/src/locales/sr_CY/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Изабери колекцију" }, - "importTargetHint": { - "message": "Изаберите ову опцију ако желите да се садржај увезене датотеке премести у $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Датотека садржи недодељене ставке." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Резиме" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Непозната ставка, можда ћете морати да се пријавите са другим налогом да бисте приступили овој ставци." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Креирати нову тајну са идентификатором: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Ови догађаји су само примери и не одражавају стварне догађаје у вашем Bitwarden отганизацији." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Бесплатне организације могу имати до 2 колекције. Надоградите на плаћени план за додавање више колекција." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/sv/messages.json b/apps/web/src/locales/sv/messages.json index 02cb7f82927..ff1bf0a2a1c 100644 --- a/apps/web/src/locales/sv/messages.json +++ b/apps/web/src/locales/sv/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Välj en samling" }, - "importTargetHint": { - "message": "Välj det här alternativet om du vill att innehållet i den importerade filen ska flyttas till en $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Välj detta alternativ om du vill att innehållet i den importerade filen ska flyttas till en samling" + }, + "importTargetHintFolder": { + "message": "Välj detta alternativ om du vill att innehållet i den importerade filen ska flyttas till en mapp" }, "importUnassignedItemsError": { "message": "Filen innehåller otilldelade objekt." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Sammanfattning" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Okänt objekt, du kan behöva begära tillstånd för att få tillgång till detta objekt." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Du kan inte lösa in för det aktiva kontot. Ange en annan e-postadress." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Skapade en ny hemlighet med identifierare: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Dessa händelser är endast exempel och återspeglar inte verkliga händelser inom din Bitwarden-organisation." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Gratisorganisationer kan ha upp till 2 samlingar. Uppgradera till en betald plan för att lägga till fler samlingar." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Visa mindre" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/te/messages.json b/apps/web/src/locales/te/messages.json index 42148397f33..6ab1431d5a4 100644 --- a/apps/web/src/locales/te/messages.json +++ b/apps/web/src/locales/te/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/th/messages.json b/apps/web/src/locales/th/messages.json index 5c70db799a3..f6faa8c027f 100644 --- a/apps/web/src/locales/th/messages.json +++ b/apps/web/src/locales/th/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Select a collection" }, - "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "File contains unassigned items." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Summary" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Unknown item, you may need to request permission to access this item." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "You cannot redeem for the active account. Enter a different email." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/tr/messages.json b/apps/web/src/locales/tr/messages.json index 388c4421917..cdea2a6077d 100644 --- a/apps/web/src/locales/tr/messages.json +++ b/apps/web/src/locales/tr/messages.json @@ -9,7 +9,7 @@ "message": "Kritik uygulamalar" }, "noCriticalAppsAtRisk": { - "message": "No critical applications at risk" + "message": "Risk altında olan kritik uygulama yok" }, "accessIntelligence": { "message": "Access Intelligence" @@ -54,10 +54,10 @@ } }, "createNewLoginItem": { - "message": "Create new login item" + "message": "Yeni giriş öğesi oluşturun" }, "criticalApplicationsWithCount": { - "message": "Critical applications ($COUNT$)", + "message": "Kritik uygulamalar ($COUNT$)", "placeholders": { "count": { "content": "$1", @@ -75,7 +75,7 @@ } }, "noAppsInOrgTitle": { - "message": "No applications found in $ORG NAME$", + "message": "$ORG NAME$'de hiçbir uygulama bulunmadı", "placeholders": { "org name": { "content": "$1", @@ -84,7 +84,7 @@ } }, "noAppsInOrgDescription": { - "message": "As users save logins, applications appear here, showing any at-risk passwords. Mark critical apps and notify users to update passwords." + "message": "Kullanıcılar oturum açma bilgilerini kaydettikçe, uygulamalar burada görünür ve risk altındaki parolaları gösterir. Kritik uygulamaları işaretleyin ve kullanıcıları parolalarını güncellemeleri için bilgilendirin." }, "noCriticalAppsTitle": { "message": "You haven't marked any applications as a Critical" @@ -114,7 +114,7 @@ "message": "Toplam parola" }, "searchApps": { - "message": "Search applications" + "message": "Uygulamaları ara" }, "atRiskMembers": { "message": "Riskli üyeler" @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Bir koleksiyon seçin" }, - "importTargetHint": { - "message": "İçe aktarılan dosya içeriğinin $DESTINATION$ konumuna taşınmasını istiyorsanız bu seçeneği seçin", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "İçe aktarılan dosya içeriklerinin bir koleksiyona taşınmasını istiyorsanız bu seçeneği seçin" + }, + "importTargetHintFolder": { + "message": "İçe aktarılan dosya içeriklerinin bir klasöre taşınmasını istiyorsanız bu seçeneği seçin" }, "importUnassignedItemsError": { "message": "Dosya atanmamış öğeler içeriyor." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Özet" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Bilinmeyen Öğe, bu öğeye erişmek için izin istemeniz gerekebilir." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Aktif hesap için kullanamazsınız. Farklı bir e-posta girin." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Ücretsiz kuruluşların en fazla 2 koleksiyonu olabilir. Daha fazla koleksiyon eklemek için ücretli bir plana geçin." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Daha az göster" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/uk/messages.json b/apps/web/src/locales/uk/messages.json index b12d0addc3c..2290429de7a 100644 --- a/apps/web/src/locales/uk/messages.json +++ b/apps/web/src/locales/uk/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Вибрати збірку" }, - "importTargetHint": { - "message": "Оберіть цю опцію, якщо ви хочете, щоб вміст імпортованого файлу було збережено в $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Файл містить непризначені записи." @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "Підсумок" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Невідомий запис. Можливо, вам необхідно запитати дозвіл для доступу до нього." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Ви не можете отримати для активного облікового запису. Введіть іншу адресу е-пошти." }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Створено новий секрет з ідентифікатором: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Ці події є лише зразками. Вони не відображають реальних подій у вашій організації Bitwarden." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Безплатні організації можуть мати до 2 збірок. Передплатіть тарифний план, щоб додати більше збірок." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/vi/messages.json b/apps/web/src/locales/vi/messages.json index 69c30f57e08..dd6f35f3f32 100644 --- a/apps/web/src/locales/vi/messages.json +++ b/apps/web/src/locales/vi/messages.json @@ -214,7 +214,7 @@ "message": "Mật khẩu mới" }, "passphrase": { - "message": "Cụm từ mật khẩu" + "message": "Cụm mật khẩu" }, "notes": { "message": "Ghi chú" @@ -1787,7 +1787,7 @@ "message": "Thay đổi địa chỉ email" }, "changeEmailTwoFactorWarning": { - "message": "Thao tác này sẽ thay đổi địa chỉ email tài khoản của bạn. Nó sẽ không thay đổi địa chỉ email được sử dụng cho xác thực đăng nhập hai bước. Bạn có thể thay đổi địa chỉ email này trong cài đặt xác thực đăng nhập hai bước." + "message": "Thao tác này sẽ thay đổi địa chỉ email tài khoản của bạn. Điều này sẽ không thay đổi địa chỉ email được sử dụng cho xác thực đăng nhập hai bước. Bạn có thể thay đổi địa chỉ email này trong cài đặt xác thực đăng nhập hai bước." }, "newEmail": { "message": "Địa chỉ email mới" @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "Chọn bộ sưu tập" }, - "importTargetHint": { - "message": "Chọn tùy chọn này nếu bạn muốn nội dung của tệp đã nhập được di chuyển đến $DESTINATION$", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "Tập tin chứa các mục không xác định." @@ -2532,7 +2528,7 @@ "message": "Mật khẩu bị lộ trong một vụ vi phạm dữ liệu là mục tiêu dễ dàng cho các tin tặc. Hãy thay đổi các mật khẩu này để ngăn chặn các cuộc tấn công tiềm ẩn." }, "exposedPasswordsFound": { - "message": "Phát hiện mật khẩu bị rò rĩ" + "message": "Phát hiện mật khẩu bị lộ" }, "exposedPasswordsFoundReportDesc": { "message": "Chúng tôi đã phát hiện $COUNT$ mục trong $VAULT$ của bạn có mật khẩu bị lộ trong các vụ vi phạm dữ liệu đã biết. Bạn nên thay đổi chúng sang mật khẩu mới.", @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Xem tóm tắt giá" + }, + "hidePricingSummary": { + "message": "Ẩn tóm tắt giá" + }, "summary": { "message": "Tóm tắt" }, @@ -5161,23 +5163,23 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editSend": { - "message": "Sửa mục Gửi", + "message": "Chỉnh sửa Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "createdSend": { - "message": "Đã lưu mục Gửi", + "message": "Đã lưu Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editedSend": { - "message": "Đã lưu mục Gửi", + "message": "Đã lưu Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "deletedSend": { - "message": "Đã xóa mục Gửi", + "message": "Đã xóa Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "deleteSend": { - "message": "Xóa mục Gửi", + "message": "Xóa Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "deleteSendPermanentConfirmation": { @@ -5208,14 +5210,14 @@ "message": "Đã thu hồi" }, "sendLink": { - "message": "Liên kết Gửi", + "message": "Liên kết Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "copyLink": { "message": "Sao chép liên kết" }, "copySendLink": { - "message": "Sao chép liên kết mục Gửi", + "message": "Sao chép liên kết Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "removePassword": { @@ -5228,7 +5230,7 @@ "message": "Bạn có chắc chắn muốn xóa mật khẩu này không?" }, "allSends": { - "message": "Tất cả mục Gửi" + "message": "Tất cả Send" }, "maxAccessCountReached": { "message": "Đã vượt số lần truy cập tối đa", @@ -5244,11 +5246,11 @@ "message": "Đã hết hạn" }, "searchSends": { - "message": "Tìm kiếm mục Gửi", + "message": "Tìm kiếm Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendProtectedPassword": { - "message": "Mục Gửi này được bảo vệ bằng mật khẩu. Hãy nhập mật khẩu vào bên dưới để tiếp tục.", + "message": "Send này được bảo vệ bằng mật khẩu. Hãy nhập mật khẩu vào bên dưới để tiếp tục.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendProtectedPasswordDontKnow": { @@ -5474,7 +5476,7 @@ "message": "Do chính sách của doanh nghiệp, bạn không thể lưu trữ các mục vào kho cá nhân của mình. Hãy thay đổi tùy chọn Quyền sở hữu thành tổ chức và chọn từ các bộ sưu tập có sẵn." }, "disableSend": { - "message": "Xóa Gửi" + "message": "Xóa Send" }, "disableSendPolicyDesc": { "message": "Không cho phép thành viên tạo hoặc chỉnh sửa Sends.", @@ -5484,11 +5486,11 @@ "message": "Các thành viên tổ chức có quyền quản lý chính sách của tổ chức sẽ được miễn áp dụng chính sách này." }, "sendDisabled": { - "message": "Đã loại bỏ Gửi", + "message": "Đã loại bỏ Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendDisabledWarning": { - "message": "Do chính sách doanh nghiệp, bạn chỉ có thể xóa những mục Gửi hiện có.", + "message": "Do chính sách doanh nghiệp, bạn chỉ có thể xóa những Send hiện có.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendOptions": { @@ -5606,7 +5608,7 @@ "message": "Loại bỏ quyền sở hữu cá nhân cho người dùng tổ chức" }, "send": { - "message": "Gửi", + "message": "Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendAccessTaglineProductDesc": { @@ -6982,7 +6984,7 @@ "message": "Sử dụng tính năng địa chỉ phụ của nhà cung cấp email của bạn." }, "catchallEmail": { - "message": "Email bắt tất cả" + "message": "Catch-all email" }, "catchallEmailDesc": { "message": "Sử dụng hộp thư bắt tất cả đã được cấu hình cho tên miền của bạn." @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "Mục không xác định, bạn có thể cần yêu cầu quyền để truy cập mục này." }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "Bạn không thể đổi thưởng cho tài khoản đang hoạt động. Vui lòng nhập email khác." }, @@ -7077,7 +7085,7 @@ "description": "This text is displayed if an organization's billing is managed by a Provider. It tells the user to contact the Provider for assistance." }, "forwardedEmail": { - "message": "Bí danh email chuyển tiếp" + "message": "Địa chỉ email thay thế" }, "forwardedEmailDesc": { "message": "Tạo bí danh email với dịch vụ chuyển tiếp bên ngoài." @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Đã tạo một bí mật mới với định danh: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -9827,7 +9907,7 @@ "message": "Tắt" }, "higherKDFIterations": { - "message": "Số vòng lặp KDF cao hơn có thể giúp bảo vệ mật khẩu chính của bạn khỏi bị kẻ tấn công tấn công brute force." + "message": "Số vòng lặp KDF cao hơn có thể giúp bảo vệ mật khẩu chính của bạn khỏi các vụ tấn công brute force." }, "incrementsOf100,000": { "message": "tăng theo bội số 100.000" @@ -9839,7 +9919,7 @@ "message": "Chúng tôi khuyến nghị 600.000 hoặc cao hơn" }, "kdfToHighWarningIncreaseInIncrements": { - "message": "Đối với các thiết bị cũ, đặt KDF quá cao có thể dẫn đến vấn đề về hiệu suất. Tăng giá trị trong $VALUE$ và kiểm tra thiết bị của bạn.", + "message": "Đối với các thiết bị cũ, đặt KDF quá cao có thể gây ra vấn đề về hiệu suất. Tăng giá trị theo $VALUE$ và kiểm tra thiết bị của bạn.", "placeholders": { "value": { "content": "$1", @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "Những sự kiện này chỉ là ví dụ và không phản ánh các sự kiện thực tế trong tổ chức Bitwarden của bạn." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Các tổ chức miễn phí có thể có tối đa 2 bộ sưu tập. Nâng cấp lên gói trả phí để thêm nhiều bộ sưu tập hơn." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Hiển thị bớt" + }, + "missingTaxId": { + "message": "Thiếu mã số thuế" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "Thêm mục điều hướng", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Thêm mã số thuế" + }, + "missingTaxIdCalloutTitle": { + "message": "Cần thực hiện: Bổ sung mã số thuế" + }, + "missingTaxIdCalloutDescription": { + "message": "Nếu không thêm mã số thuế, hóa đơn của bạn có thể sẽ bao gồm thêm thuế." + }, + "unverifiedTaxIdWarning": { + "message": "Cần thực hiện: Mã số thuế của bạn chưa được xác minh. Nếu mã số thuế không được xác minh, hóa đơn của bạn có thể sẽ bị tính thêm thuế." + }, + "editTaxId": { + "message": "Chỉnh sửa mã số thuế" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Mã số thuế chưa được xác minh" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Kiểm tra mã số thuế của bạn để xác minh định dạng chính xác và không có lỗi chính tả." + }, + "pendingVerification": { + "message": "Đang chờ xác minh" + }, + "checkInputFormat": { + "message": "Kiểm tra định dạng nhập để tránh lỗi chính tả." + }, + "exampleTaxIdFormat": { + "message": "Ví dụ định dạng $CODE$: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/zh_CN/messages.json b/apps/web/src/locales/zh_CN/messages.json index cdd5ed2405d..682f57e5ddd 100644 --- a/apps/web/src/locales/zh_CN/messages.json +++ b/apps/web/src/locales/zh_CN/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "选择一个集合" }, - "importTargetHint": { - "message": "如果您希望将导入的文件内容移动到某个 $DESTINATION$,请选择此选项", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "文件包含未分配项目。" @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "显示定价摘要" + }, + "hidePricingSummary": { + "message": "隐藏定价摘要" + }, "summary": { "message": "摘要" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "未知项目,您可能需要申请权限才能访问这个项目。" }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "您不能为活动账户兑换。请输入其他电子邮箱。" }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "创建了标识符为 $SECRET_ID$ 的新机密", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "这些事件仅为示例,并不反映您 Bitwarden 组织内的真实事件。" }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "免费组织最多拥有 2 个集合。要添加更多集合,请升级到付费计划。" }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "显示更少" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "进一步的指引", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + diff --git a/apps/web/src/locales/zh_TW/messages.json b/apps/web/src/locales/zh_TW/messages.json index 31e4cc0b5ac..39224adbbf5 100644 --- a/apps/web/src/locales/zh_TW/messages.json +++ b/apps/web/src/locales/zh_TW/messages.json @@ -2050,15 +2050,11 @@ "selectImportCollection": { "message": "選擇一個集合" }, - "importTargetHint": { - "message": "如果您要將匯入檔案的内容移動到 $DESTINATION$,請選擇此選項", - "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", - "placeholders": { - "destination": { - "content": "$1", - "example": "folder or collection" - } - } + "importTargetHintCollection": { + "message": "Select this option if you want the imported file contents moved to a collection" + }, + "importTargetHintFolder": { + "message": "Select this option if you want the imported file contents moved to a folder" }, "importUnassignedItemsError": { "message": "檔案包含未指派的項目。" @@ -2821,6 +2817,12 @@ } } }, + "showPricingSummary": { + "message": "Show pricing summary" + }, + "hidePricingSummary": { + "message": "Hide pricing summary" + }, "summary": { "message": "摘要" }, @@ -7026,6 +7028,12 @@ "unknownCipher": { "message": "未知的項目,您可能需要要求權限才能存取此項目。" }, + "unknownSecret": { + "message": "Unknown secret, you may need to request permission to access this secret." + }, + "unknownProject": { + "message": "Unknown project, you may need to request permission to access this project." + }, "cannotSponsorSelf": { "message": "您無法為已經啟用的帳戶兌換。請輸入其他信箱。" }, @@ -8349,6 +8357,24 @@ } } }, + "permanentlyDeletedSecretWithId": { + "message": "Permanently deleted a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "restoredSecretWithId": { + "message": "Restored a secret with identifier: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "createdSecretWithId": { "message": "Created a new secret with identifier: $SECRET_ID$", "placeholders": { @@ -8358,6 +8384,60 @@ } } }, + "accessedProjectWithId": { + "message": "Accessed a project with Id: $PROJECT_ID$.", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableProjectDeleted": { + "message": "Deleted project Id: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "nameUnavailableSecretDeleted": { + "message": "Deleted secret Id: $SECRET_ID$", + "placeholders": { + "secret_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "editedProjectWithId": { + "message": "Edited a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "deletedProjectWithId": { + "message": "Deleted a project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, + "createdProjectWithId": { + "message": "Created a new project with identifier: $PROJECT_ID$", + "placeholders": { + "project_id": { + "content": "$1", + "example": "4d34e8a8" + } + } + }, "sdk": { "message": "SDK", "description": "Software Development Kit" @@ -10742,6 +10822,9 @@ "upgradeEventLogMessage": { "message": "These events are examples only and do not reflect real events within your Bitwarden organization." }, + "viewEvents": { + "message": "View Events" + }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." }, @@ -11009,5 +11092,56 @@ }, "showLess": { "message": "Show less" + }, + "missingTaxId": { + "message": "Missing Tax ID" + }, + "missingTaxIdWarning": { + "message": "Action required: You're missing a Tax ID number in payment details. If a Tax ID is not added, your invoices may include additional tax." + }, + "moreBreadcrumbs": { + "message": "More breadcrumbs", + "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." + }, + "addTaxId": { + "message": "Add a Tax ID" + }, + "missingTaxIdCalloutTitle": { + "message": "Action required: Missing Tax ID" + }, + "missingTaxIdCalloutDescription": { + "message": "If a Tax ID is not added, your invoices may include additional tax." + }, + "unverifiedTaxIdWarning": { + "message": "Action required: Your Tax ID number is unverified. If your Tax ID is left unverified, your invoices may include additional tax." + }, + "editTaxId": { + "message": "Edit your Tax ID" + }, + "unverifiedTaxIdCalloutTitle": { + "message": "Tax ID unverified" + }, + "unverifiedTaxIdCalloutDescription": { + "message": "Check your Tax ID to verify the format is correct and there are no typos." + }, + "pendingVerification": { + "message": "Pending verification" + }, + "checkInputFormat": { + "message": "Check input format for typos." + }, + "exampleTaxIdFormat": { + "message": "Example $CODE$ format: $EXAMPLE$", + "placeholders": { + "code": { + "content": "$1", + "example": "ABN" + }, + "example": { + "content": "$2", + "example": "92873837267" + } + } } } + From 777b92660a2f04065a3ddcd8bccd5d83033c5249 Mon Sep 17 00:00:00 2001 From: Vicki League Date: Mon, 25 Aug 2025 12:09:20 -0400 Subject: [PATCH 035/167] [CL-706] Display all svg icons in Storybook (#16111) --- libs/assets/src/svg/svgs/admin-console.ts | 2 +- .../svg/svgs/background-left-illustration.ts | 2 +- .../svg/svgs/background-right-illustration.ts | 2 +- .../src/svg/svgs/business-unit-portal.ts | 2 +- libs/assets/src/svg/svgs/password-manager.ts | 2 +- libs/assets/src/svg/svgs/provider-portal.ts | 2 +- .../svg/svgs/registration-lock-alt.icon.ts | 6 +-- libs/assets/src/svg/svgs/secrets-manager.ts | 2 +- libs/assets/src/svg/svgs/shield.ts | 2 +- .../two-factor-auth-authenticator.icon.ts | 4 +- .../src/svg/svgs/two-factor-auth-duo.icon.ts | 4 +- .../svgs/two-factor-auth-security-key.icon.ts | 8 +-- .../svg/svgs/two-factor-auth-yubico.icon.ts | 4 +- libs/assets/src/svg/svgs/webauthn.icon.ts | 4 +- libs/components/src/icon/icon.mdx | 7 ++- libs/components/src/icon/icon.stories.ts | 49 ++++++++++++------- 16 files changed, 58 insertions(+), 44 deletions(-) diff --git a/libs/assets/src/svg/svgs/admin-console.ts b/libs/assets/src/svg/svgs/admin-console.ts index aa59c3f7e86..596822dde57 100644 --- a/libs/assets/src/svg/svgs/admin-console.ts +++ b/libs/assets/src/svg/svgs/admin-console.ts @@ -1,7 +1,7 @@ import { svgIcon } from "../icon-service"; const AdminConsoleLogo = svgIcon` - + `; export default AdminConsoleLogo; diff --git a/libs/assets/src/svg/svgs/background-left-illustration.ts b/libs/assets/src/svg/svgs/background-left-illustration.ts index 50d9e76fb53..a34f31f1621 100644 --- a/libs/assets/src/svg/svgs/background-left-illustration.ts +++ b/libs/assets/src/svg/svgs/background-left-illustration.ts @@ -1,5 +1,5 @@ import { svgIcon } from "../icon-service"; export const BackgroundLeftIllustration = svgIcon` - + `; diff --git a/libs/assets/src/svg/svgs/background-right-illustration.ts b/libs/assets/src/svg/svgs/background-right-illustration.ts index 52be2213c3b..b8f02935d83 100644 --- a/libs/assets/src/svg/svgs/background-right-illustration.ts +++ b/libs/assets/src/svg/svgs/background-right-illustration.ts @@ -1,5 +1,5 @@ import { svgIcon } from "../icon-service"; export const BackgroundRightIllustration = svgIcon` - + `; diff --git a/libs/assets/src/svg/svgs/business-unit-portal.ts b/libs/assets/src/svg/svgs/business-unit-portal.ts index 66b30ba06be..bae5ebada6a 100644 --- a/libs/assets/src/svg/svgs/business-unit-portal.ts +++ b/libs/assets/src/svg/svgs/business-unit-portal.ts @@ -1,7 +1,7 @@ import { svgIcon } from "../icon-service"; const BusinessUnitPortalLogo = svgIcon` - + `; export default BusinessUnitPortalLogo; diff --git a/libs/assets/src/svg/svgs/password-manager.ts b/libs/assets/src/svg/svgs/password-manager.ts index 42b3df1a0ed..5c8ef852025 100644 --- a/libs/assets/src/svg/svgs/password-manager.ts +++ b/libs/assets/src/svg/svgs/password-manager.ts @@ -1,7 +1,7 @@ import { svgIcon } from "../icon-service"; const PasswordManagerLogo = svgIcon` - + `; export default PasswordManagerLogo; diff --git a/libs/assets/src/svg/svgs/provider-portal.ts b/libs/assets/src/svg/svgs/provider-portal.ts index 9626cc30c57..54e4b219385 100644 --- a/libs/assets/src/svg/svgs/provider-portal.ts +++ b/libs/assets/src/svg/svgs/provider-portal.ts @@ -1,7 +1,7 @@ import { svgIcon } from "../icon-service"; const ProviderPortalLogo = svgIcon` - + `; export default ProviderPortalLogo; diff --git a/libs/assets/src/svg/svgs/registration-lock-alt.icon.ts b/libs/assets/src/svg/svgs/registration-lock-alt.icon.ts index 2e81989c304..2172d293d96 100644 --- a/libs/assets/src/svg/svgs/registration-lock-alt.icon.ts +++ b/libs/assets/src/svg/svgs/registration-lock-alt.icon.ts @@ -29,13 +29,13 @@ export const RegistrationLockAltIcon = svgIcon` - + `; diff --git a/libs/assets/src/svg/svgs/secrets-manager.ts b/libs/assets/src/svg/svgs/secrets-manager.ts index b2657f8fb67..3a5095b95bd 100644 --- a/libs/assets/src/svg/svgs/secrets-manager.ts +++ b/libs/assets/src/svg/svgs/secrets-manager.ts @@ -1,7 +1,7 @@ import { svgIcon } from "../icon-service"; const SecretsManagerLogo = svgIcon` - + `; export default SecretsManagerLogo; diff --git a/libs/assets/src/svg/svgs/shield.ts b/libs/assets/src/svg/svgs/shield.ts index 57a92e66e82..708642dc6ed 100644 --- a/libs/assets/src/svg/svgs/shield.ts +++ b/libs/assets/src/svg/svgs/shield.ts @@ -10,7 +10,7 @@ const AnonLayoutBitwardenShield = svgIcon` `; const BitwardenShield = svgIcon` - + `; export { AnonLayoutBitwardenShield, BitwardenShield }; diff --git a/libs/assets/src/svg/svgs/two-factor-auth-authenticator.icon.ts b/libs/assets/src/svg/svgs/two-factor-auth-authenticator.icon.ts index 1e6b40898c8..8e4e381eeb9 100644 --- a/libs/assets/src/svg/svgs/two-factor-auth-authenticator.icon.ts +++ b/libs/assets/src/svg/svgs/two-factor-auth-authenticator.icon.ts @@ -2,7 +2,7 @@ import { svgIcon } from "../icon-service"; export const TwoFactorAuthAuthenticatorIcon = svgIcon` - + @@ -31,7 +31,7 @@ export const TwoFactorAuthAuthenticatorIcon = svgIcon` d="M13.411 75.183h1.537v-5.472l-1.84.878v-.941l1.83-.864h.989v6.4h1.517v.82h-4.033v-.82ZM19.806 75.178h3.357v.825h-4.44v-.825c.611-.637 1.145-1.2 1.601-1.688.457-.488.772-.833.945-1.033.326-.395.547-.713.66-.956.115-.246.172-.496.172-.752 0-.404-.12-.721-.362-.95-.238-.23-.566-.345-.984-.345-.297 0-.608.053-.935.16a5.264 5.264 0 0 0-1.037.485v-.99c.336-.158.665-.278.988-.359.327-.08.648-.121.964-.121.715 0 1.29.19 1.723.568.438.375.656.868.656 1.48 0 .31-.073.62-.22.93-.144.311-.378.654-.705 1.03-.183.21-.448.5-.798.873-.345.371-.874.928-1.585 1.668ZM53.79 37.121c.816 0 1.432.34 1.849 1.016.42.678.629 1.68.629 3.007 0 1.327-.21 2.329-.63 3.006-.416.677-1.032 1.016-1.847 1.016-.816 0-1.431-.339-1.848-1.016-.416-.677-.624-1.68-.624-3.006 0-1.327.208-2.33.624-3.007.416-.677 1.032-1.016 1.848-1.016Zm0 7.211c.485 0 .845-.262 1.08-.787.24-.524.359-1.325.359-2.401 0-.573-.034-1.091-.102-1.553l-2.437 3.882c.256.573.623.86 1.1.86Zm0-6.377c-.48 0-.84.262-1.08.787-.235.524-.352 1.325-.352 2.402 0 .49.032.948.097 1.375l2.385-3.871c-.26-.462-.609-.693-1.05-.693ZM60.106 37.121c.816 0 1.432.34 1.848 1.016.42.678.63 1.68.63 3.007 0 1.327-.21 2.329-.63 3.006-.416.677-1.032 1.016-1.848 1.016-.815 0-1.43-.339-1.847-1.016-.416-.677-.624-1.68-.624-3.006 0-1.327.208-2.33.624-3.007.416-.677 1.032-1.016 1.847-1.016Zm0 7.211c.485 0 .845-.262 1.08-.787.24-.524.359-1.325.359-2.401 0-.573-.035-1.091-.103-1.553l-2.436 3.882c.256.573.623.86 1.1.86Zm0-6.377c-.48 0-.84.262-1.08.787-.235.524-.353 1.325-.353 2.402 0 .49.033.948.098 1.375l2.385-3.871c-.26-.462-.61-.693-1.05-.693ZM66.422 37.121c.816 0 1.431.34 1.848 1.016.42.678.63 1.68.63 3.007 0 1.327-.21 2.329-.63 3.006-.416.677-1.032 1.016-1.848 1.016-.815 0-1.431-.339-1.847-1.016-.417-.677-.625-1.68-.625-3.006 0-1.327.208-2.33.624-3.007.417-.677 1.033-1.016 1.848-1.016Zm0 7.211c.485 0 .845-.262 1.08-.787.239-.524.358-1.325.358-2.401 0-.573-.034-1.091-.102-1.553l-2.436 3.882c.256.573.622.86 1.1.86Zm0-6.377c-.481 0-.84.262-1.08.787-.235.524-.353 1.325-.353 2.402 0 .49.032.948.097 1.375l2.385-3.871c-.259-.462-.609-.693-1.049-.693ZM76.433 37.121c.815 0 1.431.34 1.848 1.016.42.678.63 1.68.63 3.007 0 1.327-.21 2.329-.63 3.006-.417.677-1.033 1.016-1.848 1.016-.816 0-1.431-.339-1.848-1.016-.416-.677-.624-1.68-.624-3.006 0-1.327.208-2.33.624-3.007.417-.677 1.033-1.016 1.848-1.016Zm0 7.211c.484 0 .844-.262 1.08-.787.239-.524.358-1.325.358-2.401 0-.573-.034-1.091-.102-1.553l-2.436 3.882c.255.573.622.86 1.1.86Zm0-6.377c-.481 0-.841.262-1.08.787-.235.524-.353 1.325-.353 2.402 0 .49.032.948.097 1.375l2.385-3.871c-.26-.462-.609-.693-1.049-.693ZM82.749 37.121c.815 0 1.43.34 1.847 1.016.42.678.63 1.68.63 3.007 0 1.327-.21 2.329-.63 3.006-.416.677-1.032 1.016-1.847 1.016-.816 0-1.432-.339-1.848-1.016-.416-.677-.624-1.68-.624-3.006 0-1.327.208-2.33.624-3.007.416-.677 1.032-1.016 1.848-1.016Zm0 7.211c.484 0 .844-.262 1.08-.787.238-.524.358-1.325.358-2.401 0-.573-.034-1.091-.103-1.553l-2.436 3.882c.256.573.623.86 1.1.86Zm0-6.377c-.481 0-.841.262-1.08.787-.236.524-.353 1.325-.353 2.402 0 .49.032.948.097 1.375l2.385-3.871c-.26-.462-.61-.693-1.05-.693ZM89.064 37.121c.816 0 1.432.34 1.848 1.016.42.678.63 1.68.63 3.007 0 1.327-.21 2.329-.63 3.006-.416.677-1.032 1.016-1.848 1.016-.815 0-1.431-.339-1.847-1.016-.417-.677-.625-1.68-.625-3.006 0-1.327.208-2.33.625-3.007.416-.677 1.032-1.016 1.847-1.016Zm0 7.211c.485 0 .845-.262 1.08-.787.239-.524.358-1.325.358-2.401 0-.573-.034-1.091-.102-1.553l-2.436 3.882c.256.573.623.86 1.1.86Zm0-6.377c-.48 0-.84.262-1.08.787-.235.524-.353 1.325-.353 2.402 0 .49.033.948.097 1.375l2.385-3.871c-.259-.462-.609-.693-1.049-.693Z" /> - + diff --git a/libs/assets/src/svg/svgs/two-factor-auth-duo.icon.ts b/libs/assets/src/svg/svgs/two-factor-auth-duo.icon.ts index d56e3b325d1..53a81386e04 100644 --- a/libs/assets/src/svg/svgs/two-factor-auth-duo.icon.ts +++ b/libs/assets/src/svg/svgs/two-factor-auth-duo.icon.ts @@ -2,7 +2,7 @@ import { svgIcon } from "../icon-service"; export const TwoFactorAuthDuoIcon = svgIcon` - + @@ -12,7 +12,7 @@ export const TwoFactorAuthDuoIcon = svgIcon` - + diff --git a/libs/assets/src/svg/svgs/two-factor-auth-security-key.icon.ts b/libs/assets/src/svg/svgs/two-factor-auth-security-key.icon.ts index 644f98a0cbd..30ef25baabb 100644 --- a/libs/assets/src/svg/svgs/two-factor-auth-security-key.icon.ts +++ b/libs/assets/src/svg/svgs/two-factor-auth-security-key.icon.ts @@ -2,7 +2,7 @@ import { svgIcon } from "../icon-service"; export const TwoFactorAuthSecurityKeyIcon = svgIcon` - + @@ -24,7 +24,7 @@ export const TwoFactorAuthSecurityKeyIcon = svgIcon` - + @@ -41,10 +41,10 @@ export const TwoFactorAuthSecurityKeyIcon = svgIcon` clip-rule="evenodd" /> - + - + diff --git a/libs/assets/src/svg/svgs/two-factor-auth-yubico.icon.ts b/libs/assets/src/svg/svgs/two-factor-auth-yubico.icon.ts index 231b3c3f5b1..e00bc905880 100644 --- a/libs/assets/src/svg/svgs/two-factor-auth-yubico.icon.ts +++ b/libs/assets/src/svg/svgs/two-factor-auth-yubico.icon.ts @@ -2,12 +2,12 @@ import { svgIcon } from "../icon-service"; export const TwoFactorAuthYubicoIcon = svgIcon` - + - + diff --git a/libs/assets/src/svg/svgs/webauthn.icon.ts b/libs/assets/src/svg/svgs/webauthn.icon.ts index c679438106c..923c75b43c4 100644 --- a/libs/assets/src/svg/svgs/webauthn.icon.ts +++ b/libs/assets/src/svg/svgs/webauthn.icon.ts @@ -11,7 +11,7 @@ export const WebAuthnIcon = svgIcon` aria-label="[title]" > Webauthn - + - + `; diff --git a/libs/components/src/icon/icon.mdx b/libs/components/src/icon/icon.mdx index 9d48a2f3c45..800a4711ff8 100644 --- a/libs/components/src/icon/icon.mdx +++ b/libs/components/src/icon/icon.mdx @@ -77,7 +77,10 @@ import { IconModule } from "@bitwarden/components"; - **Note:** Scaling is required for any SVG used as an [AnonLayout](?path=/docs/component-library-anon-layout--docs) `pageIcon`. -7. **Import your SVG const** anywhere you want to use the SVG. +7. **Replace any generic `clipPath` ids** (such as `id="a"`) with a unique id, and update the + referencing element to use the new id (such as `clip-path="url(#unique-id-here)"`). + +8. **Import your SVG const** anywhere you want to use the SVG. - **Angular Component Example:** - **TypeScript:** @@ -113,5 +116,5 @@ import { IconModule } from "@bitwarden/components"; ``` -8. **Ensure your SVG renders properly** according to Figma in both light and dark modes on a client +9. **Ensure your SVG renders properly** according to Figma in both light and dark modes on a client which supports multiple style modes. diff --git a/libs/components/src/icon/icon.stories.ts b/libs/components/src/icon/icon.stories.ts index e71a7597913..e355c3e6e75 100644 --- a/libs/components/src/icon/icon.stories.ts +++ b/libs/components/src/icon/icon.stories.ts @@ -1,4 +1,4 @@ -import { Meta, StoryObj } from "@storybook/angular"; +import { Meta } from "@storybook/angular"; import * as SvgIcons from "@bitwarden/assets/svg"; @@ -15,25 +15,36 @@ export default { }, } as Meta; -type Story = StoryObj; +const { + // Filtering out the few non-icons in the libs/assets/svg import + // eslint-disable-next-line @typescript-eslint/no-unused-vars + DynamicContentNotAllowedError: _DynamicContentNotAllowedError, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isIcon, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + svgIcon, + ...Icons +}: { + [key: string]: any; +} = SvgIcons; -// Filtering out the few non-icons in the libs/assets/svg import -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const { DynamicContentNotAllowedError, isIcon, svgIcon, ...Icons } = SvgIcons; - -export const Default: Story = { +export const Default = { + render: (args: { icons: [string, any][] }) => ({ + props: args, + template: /*html*/ ` +
+ @for (icon of icons; track icon[0]) { +
+
{{icon[0]}}
+
+ +
+
+ } +
+ `, + }), args: { - icon: Icons.NoAccess, - }, - argTypes: { - icon: { - options: Object.keys(Icons), - mapping: Icons, - control: { type: "select" }, - }, - ariaLabel: { - control: "text", - description: "the text used by a screen reader to describe the icon", - }, + icons: Object.entries(Icons), }, }; From 5f7f1d19242c418bb7f989ce50dc0c528e27b22c Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Mon, 25 Aug 2025 12:38:28 -0400 Subject: [PATCH 036/167] Resolve state <-> state-test-utils circular dependency (#16093) * Resolve state <-> state-test-utils circular dependency * Fix type errors --- .github/CODEOWNERS | 1 + .../browser/src/background/main.background.ts | 39 ++++---- .../background-memory-storage.service.ts | 6 +- .../browser-storage-service.provider.ts | 7 +- .../src/popup/services/services.module.ts | 9 +- .../service-container/service-container.ts | 47 +++++----- .../src/app/services/services.module.ts | 5 +- apps/desktop/src/main.ts | 25 +++--- apps/web/src/app/core/core.module.ts | 6 +- .../web-storage-service.provider.spec.ts | 9 +- .../platform/web-storage-service.provider.ts | 9 +- .../src/services/jslib-services.module.ts | 42 ++++----- .../src/platform/state/derive-definition.ts | 1 - .../platform/state/derived-state.provider.ts | 1 - .../src/platform/state/derived-state.ts | 1 - .../platform/state/global-state.provider.ts | 1 - .../common/src/platform/state/global-state.ts | 1 - .../default-active-user-state.provider.ts | 36 -------- .../default-active-user-state.ts | 1 - .../default-derived-state.provider.ts | 1 - .../implementations/default-derived-state.ts | 1 - .../default-global-state.provider.ts | 1 - .../implementations/default-global-state.ts | 1 - .../default-single-user-state.provider.ts | 1 - .../default-single-user-state.ts | 1 - .../implementations/default-state.provider.ts | 1 - .../implementations/inline-derived-state.ts | 1 - .../state/implementations/state-base.ts | 1 - libs/common/src/platform/state/index.ts | 5 ++ .../src/platform/state/key-definition.ts | 1 - .../src/platform/state/state-definition.ts | 3 - .../state/state-event-registrar.service.ts | 6 -- .../state/state-event-runner.service.ts | 1 - .../src/platform/state/state.provider.ts | 1 - .../state/storage/memory-storage.service.ts | 1 - .../src/platform/state/user-key-definition.ts | 1 - .../src/platform/state/user-state.provider.ts | 1 - libs/common/src/platform/state/user-state.ts | 1 - libs/state-internal/README.md | 5 ++ libs/state-internal/eslint.config.mjs | 3 + libs/state-internal/jest.config.js | 10 +++ libs/state-internal/package.json | 11 +++ libs/state-internal/project.json | 33 +++++++ .../src}/active-user.accessor.ts | 0 ...default-active-user-state.provider.spec.ts | 11 +-- .../default-active-user-state.provider.ts | 12 +-- .../src}/default-active-user-state.spec.ts | 5 +- .../src}/default-active-user-state.ts | 15 ++-- .../src}/default-derived-state.provider.ts | 10 ++- .../src}/default-derived-state.spec.ts | 4 +- .../src}/default-derived-state.ts | 4 +- .../src}/default-global-state.provider.ts | 5 +- .../src}/default-global-state.spec.ts | 5 +- .../src}/default-global-state.ts | 5 +- .../default-single-user-state.provider.ts | 11 +-- .../src}/default-single-user-state.spec.ts | 5 +- .../src}/default-single-user-state.ts | 10 ++- ...ult-state-event-registrar.service.spec.ts} | 10 ++- .../default-state-event-registrar.service.ts | 78 ++++++++++++++++ ...efault-state-event-runner.service.spec.ts} | 8 +- .../src/default-state-event-runner.service.ts | 89 +++++++++++++++++++ .../src}/default-state.provider.spec.ts | 11 +-- .../src}/default-state.provider.ts | 20 +++-- .../src}/index.ts | 4 + .../src}/inline-derived-state.spec.ts | 3 +- .../src}/inline-derived-state.ts | 10 ++- .../src/legacy/default-state.service.ts | 4 +- .../src/legacy/global-state.ts | 0 .../src}/specific-state.provider.spec.ts | 11 +-- .../src}/state-base.ts | 13 ++- .../state-internal/src/state-internal.spec.ts | 8 ++ .../src}/util.spec.ts | 0 libs/state-internal/src/util.ts | 38 ++++++++ libs/state-internal/tsconfig.eslint.json | 6 ++ libs/state-internal/tsconfig.json | 13 +++ libs/state-internal/tsconfig.lib.json | 10 +++ libs/state-internal/tsconfig.spec.json | 10 +++ .../src/fake-state-provider.ts | 8 +- libs/state/src/core/active-user.accessor.ts | 11 --- libs/state/src/core/global-state.ts | 2 +- libs/state/src/core/implementations/util.ts | 17 ---- libs/state/src/core/index.ts | 6 +- libs/state/src/core/key-definition.ts | 11 --- .../src/core/state-event-registrar.service.ts | 77 +--------------- .../src/core/state-event-runner.service.ts | 81 +---------------- libs/state/src/core/state-update-options.ts | 27 +----- libs/state/src/core/user-state.ts | 4 +- libs/state/src/legacy/index.ts | 3 +- package-lock.json | 8 ++ tsconfig.base.json | 1 + 90 files changed, 543 insertions(+), 500 deletions(-) delete mode 100644 libs/common/src/platform/state/derive-definition.ts delete mode 100644 libs/common/src/platform/state/derived-state.provider.ts delete mode 100644 libs/common/src/platform/state/derived-state.ts delete mode 100644 libs/common/src/platform/state/global-state.provider.ts delete mode 100644 libs/common/src/platform/state/global-state.ts delete mode 100644 libs/common/src/platform/state/implementations/default-active-user-state.provider.ts delete mode 100644 libs/common/src/platform/state/implementations/default-active-user-state.ts delete mode 100644 libs/common/src/platform/state/implementations/default-derived-state.provider.ts delete mode 100644 libs/common/src/platform/state/implementations/default-derived-state.ts delete mode 100644 libs/common/src/platform/state/implementations/default-global-state.provider.ts delete mode 100644 libs/common/src/platform/state/implementations/default-global-state.ts delete mode 100644 libs/common/src/platform/state/implementations/default-single-user-state.provider.ts delete mode 100644 libs/common/src/platform/state/implementations/default-single-user-state.ts delete mode 100644 libs/common/src/platform/state/implementations/default-state.provider.ts delete mode 100644 libs/common/src/platform/state/implementations/inline-derived-state.ts delete mode 100644 libs/common/src/platform/state/implementations/state-base.ts delete mode 100644 libs/common/src/platform/state/key-definition.ts delete mode 100644 libs/common/src/platform/state/state-event-registrar.service.ts delete mode 100644 libs/common/src/platform/state/state-event-runner.service.ts delete mode 100644 libs/common/src/platform/state/state.provider.ts delete mode 100644 libs/common/src/platform/state/storage/memory-storage.service.ts delete mode 100644 libs/common/src/platform/state/user-key-definition.ts delete mode 100644 libs/common/src/platform/state/user-state.provider.ts delete mode 100644 libs/common/src/platform/state/user-state.ts create mode 100644 libs/state-internal/README.md create mode 100644 libs/state-internal/eslint.config.mjs create mode 100644 libs/state-internal/jest.config.js create mode 100644 libs/state-internal/package.json create mode 100644 libs/state-internal/project.json rename libs/{common/src/platform/state => state-internal/src}/active-user.accessor.ts (100%) rename libs/{state/src/core/implementations => state-internal/src}/default-active-user-state.provider.spec.ts (97%) rename libs/{state/src/core/implementations => state-internal/src}/default-active-user-state.provider.ts (83%) rename libs/{state/src/core/implementations => state-internal/src}/default-active-user-state.spec.ts (99%) rename libs/{state/src/core/implementations => state-internal/src}/default-active-user-state.ts (84%) rename libs/{state/src/core/implementations => state-internal/src}/default-derived-state.provider.ts (88%) rename libs/{state/src/core/implementations => state-internal/src}/default-derived-state.spec.ts (98%) rename libs/{state/src/core/implementations => state-internal/src}/default-derived-state.ts (88%) rename libs/{state/src/core/implementations => state-internal/src}/default-global-state.provider.ts (90%) rename libs/{state/src/core/implementations => state-internal/src}/default-global-state.spec.ts (98%) rename libs/{state/src/core/implementations => state-internal/src}/default-global-state.ts (82%) rename libs/{state/src/core/implementations => state-internal/src}/default-single-user-state.provider.ts (87%) rename libs/{state/src/core/implementations => state-internal/src}/default-single-user-state.spec.ts (98%) rename libs/{state/src/core/implementations => state-internal/src}/default-single-user-state.ts (85%) rename libs/{state/src/core/state-event-registrar.service.spec.ts => state-internal/src/default-state-event-registrar.service.spec.ts} (87%) create mode 100644 libs/state-internal/src/default-state-event-registrar.service.ts rename libs/{state/src/core/state-event-runner.service.spec.ts => state-internal/src/default-state-event-runner.service.spec.ts} (88%) create mode 100644 libs/state-internal/src/default-state-event-runner.service.ts rename libs/{state/src/core/implementations => state-internal/src}/default-state.provider.spec.ts (97%) rename libs/{state/src/core/implementations => state-internal/src}/default-state.provider.ts (84%) rename libs/{state/src/core/implementations => state-internal/src}/index.ts (62%) rename libs/{state/src/core/implementations => state-internal/src}/inline-derived-state.spec.ts (93%) rename libs/{state/src/core/implementations => state-internal/src}/inline-derived-state.ts (80%) rename libs/{state => state-internal}/src/legacy/default-state.service.ts (96%) rename libs/{state => state-internal}/src/legacy/global-state.ts (100%) rename libs/{state/src/core/implementations => state-internal/src}/specific-state.provider.spec.ts (96%) rename libs/{state/src/core/implementations => state-internal/src}/state-base.ts (90%) create mode 100644 libs/state-internal/src/state-internal.spec.ts rename libs/{state/src/core/implementations => state-internal/src}/util.spec.ts (100%) create mode 100644 libs/state-internal/src/util.ts create mode 100644 libs/state-internal/tsconfig.eslint.json create mode 100644 libs/state-internal/tsconfig.json create mode 100644 libs/state-internal/tsconfig.lib.json create mode 100644 libs/state-internal/tsconfig.spec.json delete mode 100644 libs/state/src/core/active-user.accessor.ts delete mode 100644 libs/state/src/core/implementations/util.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index df71b6545fb..d6028d106db 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -101,6 +101,7 @@ libs/guid @bitwarden/team-platform-dev libs/client-type @bitwarden/team-platform-dev libs/core-test-utils @bitwarden/team-platform-dev libs/state @bitwarden/team-platform-dev +libs/state-internal @bitwarden/team-platform-dev libs/state-test-utils @bitwarden/team-platform-dev # Web utils used across app and connectors apps/web/src/utils/ @bitwarden/team-platform-dev diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index cd045c9874e..2f87e347410 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -143,23 +143,6 @@ import { DefaultSdkService } from "@bitwarden/common/platform/services/sdk/defau import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory"; import { SystemService } from "@bitwarden/common/platform/services/system.service"; import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service"; -import { - ActiveUserStateProvider, - DefaultStateService, - DerivedStateProvider, - GlobalStateProvider, - SingleUserStateProvider, - StateEventRunnerService, - StateProvider, -} from "@bitwarden/common/platform/state"; -/* eslint-disable import/no-restricted-paths -- We need the implementation to inject, but generally these should not be accessed */ -import { DefaultActiveUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-active-user-state.provider"; -import { DefaultGlobalStateProvider } from "@bitwarden/common/platform/state/implementations/default-global-state.provider"; -import { DefaultSingleUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-single-user-state.provider"; -import { DefaultStateProvider } from "@bitwarden/common/platform/state/implementations/default-state.provider"; -import { InlineDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/inline-derived-state"; -import { StateEventRegistrarService } from "@bitwarden/common/platform/state/state-event-registrar.service"; -/* eslint-enable import/no-restricted-paths */ import { PrimarySecondaryStorageService } from "@bitwarden/common/platform/storage/primary-secondary-storage.service"; import { WindowStorageService } from "@bitwarden/common/platform/storage/window-storage.service"; import { SyncService } from "@bitwarden/common/platform/sync"; @@ -232,6 +215,24 @@ import { KeyService as KeyServiceAbstraction, } from "@bitwarden/key-management"; import { BackgroundSyncService } from "@bitwarden/platform/background-sync"; +import { + ActiveUserStateProvider, + DerivedStateProvider, + GlobalStateProvider, + SingleUserStateProvider, + StateEventRunnerService, + StateProvider, +} from "@bitwarden/state"; +import { + DefaultActiveUserStateProvider, + DefaultGlobalStateProvider, + DefaultSingleUserStateProvider, + DefaultStateEventRegistrarService, + DefaultStateEventRunnerService, + DefaultStateProvider, + DefaultStateService, + InlineDerivedStateProvider, +} from "@bitwarden/state-internal"; import { IndividualVaultExportService, IndividualVaultExportServiceAbstraction, @@ -569,12 +570,12 @@ export default class MainBackground { this.logService, ); - const stateEventRegistrarService = new StateEventRegistrarService( + const stateEventRegistrarService = new DefaultStateEventRegistrarService( this.globalStateProvider, storageServiceProvider, ); - this.stateEventRunnerService = new StateEventRunnerService( + this.stateEventRunnerService = new DefaultStateEventRunnerService( this.globalStateProvider, storageServiceProvider, ); diff --git a/apps/browser/src/platform/storage/background-memory-storage.service.ts b/apps/browser/src/platform/storage/background-memory-storage.service.ts index 9c0cac0d044..ec1da43391f 100644 --- a/apps/browser/src/platform/storage/background-memory-storage.service.ts +++ b/apps/browser/src/platform/storage/background-memory-storage.service.ts @@ -1,14 +1,14 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -// eslint-disable-next-line import/no-restricted-paths -- Implementation for memory storage specifically for browser backgrounds -import { MemoryStorageService } from "@bitwarden/common/platform/state/storage/memory-storage.service"; + +import { SerializedMemoryStorageService } from "@bitwarden/storage-core"; import { BrowserApi } from "../browser/browser-api"; import { MemoryStoragePortMessage } from "./port-messages"; import { portName } from "./port-name"; -export class BackgroundMemoryStorageService extends MemoryStorageService { +export class BackgroundMemoryStorageService extends SerializedMemoryStorageService { private _ports: chrome.runtime.Port[] = []; constructor() { diff --git a/apps/browser/src/platform/storage/browser-storage-service.provider.ts b/apps/browser/src/platform/storage/browser-storage-service.provider.ts index 5854669138a..66a1bf3f2a7 100644 --- a/apps/browser/src/platform/storage/browser-storage-service.provider.ts +++ b/apps/browser/src/platform/storage/browser-storage-service.provider.ts @@ -1,13 +1,10 @@ import { AbstractStorageService, + ClientLocations, ObservableStorageService, -} from "@bitwarden/common/platform/abstractions/storage.service"; -import { PossibleLocation, StorageServiceProvider, -} from "@bitwarden/common/platform/services/storage-service.provider"; -// eslint-disable-next-line import/no-restricted-paths -import { ClientLocations } from "@bitwarden/common/platform/state/state-definition"; +} from "@bitwarden/storage-core"; export class BrowserStorageServiceProvider extends StorageServiceProvider { constructor( diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 358ed33408c..d8b4b1d600f 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -104,13 +104,6 @@ import { ContainerService } from "@bitwarden/common/platform/services/container. import { DefaultSdkClientFactory } from "@bitwarden/common/platform/services/sdk/default-sdk-client-factory"; import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory"; import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; -import { - DerivedStateProvider, - GlobalStateProvider, - StateProvider, -} from "@bitwarden/common/platform/state"; -// eslint-disable-next-line import/no-restricted-paths -- Used for dependency injection -import { InlineDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/inline-derived-state"; import { PrimarySecondaryStorageService } from "@bitwarden/common/platform/storage/primary-secondary-storage.service"; import { WindowStorageService } from "@bitwarden/common/platform/storage/window-storage.service"; import { SyncService } from "@bitwarden/common/platform/sync"; @@ -140,6 +133,8 @@ import { KeyService, } from "@bitwarden/key-management"; import { LockComponentService } from "@bitwarden/key-management-ui"; +import { DerivedStateProvider, GlobalStateProvider, StateProvider } from "@bitwarden/state"; +import { InlineDerivedStateProvider } from "@bitwarden/state-internal"; import { DefaultSshImportPromptService, PasswordRepromptService, diff --git a/apps/cli/src/service-container/service-container.ts b/apps/cli/src/service-container/service-container.ts index 0268eed06ae..508ade4650e 100644 --- a/apps/cli/src/service-container/service-container.ts +++ b/apps/cli/src/service-container/service-container.ts @@ -107,25 +107,6 @@ import { DefaultSdkService } from "@bitwarden/common/platform/services/sdk/defau import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory"; import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service"; -import { - ActiveUserStateProvider, - DefaultStateService, - DerivedStateProvider, - GlobalStateProvider, - SingleUserStateProvider, - StateEventRunnerService, - StateProvider, - StateService, -} from "@bitwarden/common/platform/state"; -/* eslint-disable import/no-restricted-paths -- We need the implementation to inject, but generally these should not be accessed */ -import { DefaultActiveUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-active-user-state.provider"; -import { DefaultDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/default-derived-state.provider"; -import { DefaultGlobalStateProvider } from "@bitwarden/common/platform/state/implementations/default-global-state.provider"; -import { DefaultSingleUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-single-user-state.provider"; -import { DefaultStateProvider } from "@bitwarden/common/platform/state/implementations/default-state.provider"; -import { StateEventRegistrarService } from "@bitwarden/common/platform/state/state-event-registrar.service"; -import { MemoryStorageService as MemoryStorageServiceForStateProviders } from "@bitwarden/common/platform/state/storage/memory-storage.service"; -/* eslint-enable import/no-restricted-paths */ import { SyncService } from "@bitwarden/common/platform/sync"; // eslint-disable-next-line no-restricted-imports -- Needed for service construction import { DefaultSyncService } from "@bitwarden/common/platform/sync/internal"; @@ -172,6 +153,26 @@ import { DefaultBiometricStateService, } from "@bitwarden/key-management"; import { NodeCryptoFunctionService } from "@bitwarden/node/services/node-crypto-function.service"; +import { + ActiveUserStateProvider, + DerivedStateProvider, + GlobalStateProvider, + SingleUserStateProvider, + StateEventRunnerService, + StateProvider, + StateService, +} from "@bitwarden/state"; +import { + DefaultActiveUserStateProvider, + DefaultDerivedStateProvider, + DefaultGlobalStateProvider, + DefaultSingleUserStateProvider, + DefaultStateEventRegistrarService, + DefaultStateEventRunnerService, + DefaultStateProvider, + DefaultStateService, +} from "@bitwarden/state-internal"; +import { SerializedMemoryStorageService } from "@bitwarden/storage-core"; import { IndividualVaultExportService, IndividualVaultExportServiceAbstraction, @@ -209,7 +210,7 @@ export class ServiceContainer { storageService: LowdbStorageService; secureStorageService: NodeEnvSecureStorageService; memoryStorageService: MemoryStorageService; - memoryStorageForStateProviders: MemoryStorageServiceForStateProviders; + memoryStorageForStateProviders: SerializedMemoryStorageService; migrationRunner: MigrationRunner; i18nService: I18nService; platformUtilsService: CliPlatformUtilsService; @@ -339,7 +340,7 @@ export class ServiceContainer { ); this.memoryStorageService = new MemoryStorageService(); - this.memoryStorageForStateProviders = new MemoryStorageServiceForStateProviders(); + this.memoryStorageForStateProviders = new SerializedMemoryStorageService(); const storageServiceProvider = new StorageServiceProvider( this.storageService, @@ -351,12 +352,12 @@ export class ServiceContainer { this.logService, ); - const stateEventRegistrarService = new StateEventRegistrarService( + const stateEventRegistrarService = new DefaultStateEventRegistrarService( this.globalStateProvider, storageServiceProvider, ); - this.stateEventRunnerService = new StateEventRunnerService( + this.stateEventRunnerService = new DefaultStateEventRunnerService( this.globalStateProvider, storageServiceProvider, ); diff --git a/apps/desktop/src/app/services/services.module.ts b/apps/desktop/src/app/services/services.module.ts index 3d65094ba60..9171f4f7657 100644 --- a/apps/desktop/src/app/services/services.module.ts +++ b/apps/desktop/src/app/services/services.module.ts @@ -91,8 +91,6 @@ import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/no import { NoopSdkLoadService } from "@bitwarden/common/platform/services/sdk/noop-sdk-load.service"; import { SystemService } from "@bitwarden/common/platform/services/system.service"; import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state"; -// eslint-disable-next-line import/no-restricted-paths -- Implementation for memory storage -import { MemoryStorageService as MemoryStorageServiceForStateProviders } from "@bitwarden/common/platform/state/storage/memory-storage.service"; import { SyncService } from "@bitwarden/common/platform/sync"; import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service"; import { DialogService, ToastService } from "@bitwarden/components"; @@ -105,6 +103,7 @@ import { BiometricsService, } from "@bitwarden/key-management"; import { LockComponentService } from "@bitwarden/key-management-ui"; +import { SerializedMemoryStorageService } from "@bitwarden/storage-core"; import { DefaultSshImportPromptService, SshImportPromptService } from "@bitwarden/vault"; import { DesktopLoginApprovalDialogComponentService } from "../../auth/login/desktop-login-approval-dialog-component.service"; @@ -234,7 +233,7 @@ const safeProviders: SafeProvider[] = [ safeProvider({ provide: MEMORY_STORAGE, useClass: MemoryStorageService, deps: [] }), safeProvider({ provide: OBSERVABLE_MEMORY_STORAGE, - useClass: MemoryStorageServiceForStateProviders, + useClass: SerializedMemoryStorageService, deps: [], }), safeProvider({ provide: OBSERVABLE_DISK_STORAGE, useExisting: AbstractStorageService }), diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index deb09d2f335..6d5f536fadb 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -21,18 +21,17 @@ import { DefaultEnvironmentService } from "@bitwarden/common/platform/services/d import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service"; import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service"; import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner"; -/* eslint-disable import/no-restricted-paths -- We need the implementation to inject, but generally this should not be accessed */ -import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; -import { DefaultActiveUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-active-user-state.provider"; -import { DefaultDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/default-derived-state.provider"; -import { DefaultGlobalStateProvider } from "@bitwarden/common/platform/state/implementations/default-global-state.provider"; -import { DefaultSingleUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-single-user-state.provider"; -import { DefaultStateProvider } from "@bitwarden/common/platform/state/implementations/default-state.provider"; -import { StateEventRegistrarService } from "@bitwarden/common/platform/state/state-event-registrar.service"; -import { MemoryStorageService as MemoryStorageServiceForStateProviders } from "@bitwarden/common/platform/state/storage/memory-storage.service"; -/* eslint-enable import/no-restricted-paths */ import { DefaultBiometricStateService } from "@bitwarden/key-management"; import { NodeCryptoFunctionService } from "@bitwarden/node/services/node-crypto-function.service"; +import { + DefaultActiveUserStateProvider, + DefaultDerivedStateProvider, + DefaultGlobalStateProvider, + DefaultSingleUserStateProvider, + DefaultStateEventRegistrarService, + DefaultStateProvider, +} from "@bitwarden/state-internal"; +import { SerializedMemoryStorageService, StorageServiceProvider } from "@bitwarden/storage-core"; import { MainDesktopAutotypeService } from "./autofill/main/main-desktop-autotype.service"; import { MainSshAgentService } from "./autofill/main/main-ssh-agent.service"; @@ -66,7 +65,7 @@ export class Main { i18nService: I18nMainService; storageService: ElectronStorageService; memoryStorageService: MemoryStorageService; - memoryStorageForStateProviders: MemoryStorageServiceForStateProviders; + memoryStorageForStateProviders: SerializedMemoryStorageService; messagingService: MessageSender; environmentService: DefaultEnvironmentService; desktopCredentialStorageListener: DesktopCredentialStorageListener; @@ -134,7 +133,7 @@ export class Main { const storageDefaults: any = {}; this.storageService = new ElectronStorageService(app.getPath("userData"), storageDefaults); this.memoryStorageService = new MemoryStorageService(); - this.memoryStorageForStateProviders = new MemoryStorageServiceForStateProviders(); + this.memoryStorageForStateProviders = new SerializedMemoryStorageService(); const storageServiceProvider = new StorageServiceProvider( this.storageService, this.memoryStorageForStateProviders, @@ -150,7 +149,7 @@ export class Main { this.mainCryptoFunctionService = new NodeCryptoFunctionService(); - const stateEventRegistrarService = new StateEventRegistrarService( + const stateEventRegistrarService = new DefaultStateEventRegistrarService( globalStateProvider, storageServiceProvider, ); diff --git a/apps/web/src/app/core/core.module.ts b/apps/web/src/app/core/core.module.ts index 965a9d5c99d..cccbe26c524 100644 --- a/apps/web/src/app/core/core.module.ts +++ b/apps/web/src/app/core/core.module.ts @@ -93,10 +93,7 @@ import { DefaultSdkClientFactory } from "@bitwarden/common/platform/services/sdk import { NoopSdkClientFactory } from "@bitwarden/common/platform/services/sdk/noop-sdk-client-factory"; import { NoopSdkLoadService } from "@bitwarden/common/platform/services/sdk/noop-sdk-load.service"; import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; -/* eslint-disable import/no-restricted-paths -- Implementation for memory storage */ import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state"; -import { MemoryStorageService as MemoryStorageServiceForStateProviders } from "@bitwarden/common/platform/state/storage/memory-storage.service"; -/* eslint-enable import/no-restricted-paths -- Implementation for memory storage */ import { WindowStorageService } from "@bitwarden/common/platform/storage/window-storage.service"; import { DefaultThemeStateService, @@ -110,6 +107,7 @@ import { BiometricsService, } from "@bitwarden/key-management"; import { LockComponentService } from "@bitwarden/key-management-ui"; +import { SerializedMemoryStorageService } from "@bitwarden/storage-core"; import { DefaultSshImportPromptService, SshImportPromptService } from "@bitwarden/vault"; import { WebOrganizationInviteService } from "@bitwarden/web-vault/app/auth/core/services/organization-invite/web-organization-invite.service"; @@ -186,7 +184,7 @@ const safeProviders: SafeProvider[] = [ }), safeProvider({ provide: OBSERVABLE_MEMORY_STORAGE, - useClass: MemoryStorageServiceForStateProviders, + useClass: SerializedMemoryStorageService, deps: [], }), safeProvider({ diff --git a/apps/web/src/app/platform/web-storage-service.provider.spec.ts b/apps/web/src/app/platform/web-storage-service.provider.spec.ts index 53f047d137d..e28b8772b16 100644 --- a/apps/web/src/app/platform/web-storage-service.provider.spec.ts +++ b/apps/web/src/app/platform/web-storage-service.provider.spec.ts @@ -2,14 +2,11 @@ import { mock } from "jest-mock-extended"; import { AbstractStorageService, - ObservableStorageService, -} from "@bitwarden/common/platform/abstractions/storage.service"; -import { PossibleLocation } from "@bitwarden/common/platform/services/storage-service.provider"; -import { ClientLocations, + ObservableStorageService, + PossibleLocation, StorageLocation, - // eslint-disable-next-line import/no-restricted-paths -} from "@bitwarden/common/platform/state/state-definition"; +} from "@bitwarden/storage-core"; import { WebStorageServiceProvider } from "./web-storage-service.provider"; diff --git a/apps/web/src/app/platform/web-storage-service.provider.ts b/apps/web/src/app/platform/web-storage-service.provider.ts index da9a8517856..2e5ccaf5720 100644 --- a/apps/web/src/app/platform/web-storage-service.provider.ts +++ b/apps/web/src/app/platform/web-storage-service.provider.ts @@ -1,15 +1,10 @@ import { AbstractStorageService, + ClientLocations, ObservableStorageService, -} from "@bitwarden/common/platform/abstractions/storage.service"; -import { PossibleLocation, StorageServiceProvider, -} from "@bitwarden/common/platform/services/storage-service.provider"; -import { - ClientLocations, - // eslint-disable-next-line import/no-restricted-paths -} from "@bitwarden/common/platform/state/state-definition"; +} from "@bitwarden/storage-core"; export class WebStorageServiceProvider extends StorageServiceProvider { constructor( diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index ab7c12ceffa..fa7de5484d9 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -230,24 +230,6 @@ import { DefaultSdkService } from "@bitwarden/common/platform/services/sdk/defau import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; import { UserAutoUnlockKeyService } from "@bitwarden/common/platform/services/user-auto-unlock-key.service"; import { ValidationService } from "@bitwarden/common/platform/services/validation.service"; -import { - ActiveUserAccessor, - ActiveUserStateProvider, - DefaultStateService, - DerivedStateProvider, - GlobalStateProvider, - SingleUserStateProvider, - StateProvider, -} from "@bitwarden/common/platform/state"; -/* eslint-disable import/no-restricted-paths -- We need the implementations to inject, but generally these should not be accessed */ -import { DefaultActiveUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-active-user-state.provider"; -import { DefaultDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/default-derived-state.provider"; -import { DefaultGlobalStateProvider } from "@bitwarden/common/platform/state/implementations/default-global-state.provider"; -import { DefaultSingleUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-single-user-state.provider"; -import { DefaultStateProvider } from "@bitwarden/common/platform/state/implementations/default-state.provider"; -import { StateEventRegistrarService } from "@bitwarden/common/platform/state/state-event-registrar.service"; -import { StateEventRunnerService } from "@bitwarden/common/platform/state/state-event-runner.service"; -/* eslint-enable import/no-restricted-paths */ import { SyncService } from "@bitwarden/common/platform/sync"; // eslint-disable-next-line no-restricted-imports -- Needed for DI import { DefaultSyncService } from "@bitwarden/common/platform/sync/internal"; @@ -329,6 +311,26 @@ import { UserAsymmetricKeysRegenerationApiService, UserAsymmetricKeysRegenerationService, } from "@bitwarden/key-management"; +import { + ActiveUserStateProvider, + DerivedStateProvider, + GlobalStateProvider, + SingleUserStateProvider, + StateEventRegistrarService, + StateEventRunnerService, + StateProvider, +} from "@bitwarden/state"; +import { + ActiveUserAccessor, + DefaultActiveUserStateProvider, + DefaultDerivedStateProvider, + DefaultGlobalStateProvider, + DefaultSingleUserStateProvider, + DefaultStateEventRegistrarService, + DefaultStateEventRunnerService, + DefaultStateProvider, + DefaultStateService, +} from "@bitwarden/state-internal"; import { SafeInjectionToken } from "@bitwarden/ui-common"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports @@ -1246,12 +1248,12 @@ const safeProviders: SafeProvider[] = [ }), safeProvider({ provide: StateEventRegistrarService, - useClass: StateEventRegistrarService, + useClass: DefaultStateEventRegistrarService, deps: [GlobalStateProvider, StorageServiceProvider], }), safeProvider({ provide: StateEventRunnerService, - useClass: StateEventRunnerService, + useClass: DefaultStateEventRunnerService, deps: [GlobalStateProvider, StorageServiceProvider], }), safeProvider({ diff --git a/libs/common/src/platform/state/derive-definition.ts b/libs/common/src/platform/state/derive-definition.ts deleted file mode 100644 index 3882e89fd68..00000000000 --- a/libs/common/src/platform/state/derive-definition.ts +++ /dev/null @@ -1 +0,0 @@ -export { DeriveDefinition } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/derived-state.provider.ts b/libs/common/src/platform/state/derived-state.provider.ts deleted file mode 100644 index 3118780a0cf..00000000000 --- a/libs/common/src/platform/state/derived-state.provider.ts +++ /dev/null @@ -1 +0,0 @@ -export { DerivedStateProvider } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/derived-state.ts b/libs/common/src/platform/state/derived-state.ts deleted file mode 100644 index 06dd28bf4f0..00000000000 --- a/libs/common/src/platform/state/derived-state.ts +++ /dev/null @@ -1 +0,0 @@ -export { DerivedState } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/global-state.provider.ts b/libs/common/src/platform/state/global-state.provider.ts deleted file mode 100644 index a92e6374c49..00000000000 --- a/libs/common/src/platform/state/global-state.provider.ts +++ /dev/null @@ -1 +0,0 @@ -export { GlobalStateProvider } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/global-state.ts b/libs/common/src/platform/state/global-state.ts deleted file mode 100644 index d65866c9305..00000000000 --- a/libs/common/src/platform/state/global-state.ts +++ /dev/null @@ -1 +0,0 @@ -export { GlobalState } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/implementations/default-active-user-state.provider.ts b/libs/common/src/platform/state/implementations/default-active-user-state.provider.ts deleted file mode 100644 index d24d2f8df72..00000000000 --- a/libs/common/src/platform/state/implementations/default-active-user-state.provider.ts +++ /dev/null @@ -1,36 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { Observable, distinctUntilChanged } from "rxjs"; - -import { UserId } from "../../../types/guid"; -import { ActiveUserAccessor } from "../active-user.accessor"; -import { UserKeyDefinition } from "../user-key-definition"; -import { ActiveUserState } from "../user-state"; -import { ActiveUserStateProvider, SingleUserStateProvider } from "../user-state.provider"; - -import { DefaultActiveUserState } from "./default-active-user-state"; - -export class DefaultActiveUserStateProvider implements ActiveUserStateProvider { - activeUserId$: Observable; - - constructor( - private readonly activeAccountAccessor: ActiveUserAccessor, - private readonly singleUserStateProvider: SingleUserStateProvider, - ) { - this.activeUserId$ = this.activeAccountAccessor.activeUserId$.pipe( - // To avoid going to storage when we don't need to, only get updates when there is a true change. - distinctUntilChanged((a, b) => (a == null || b == null ? a == b : a === b)), // Treat null and undefined as equal - ); - } - - get(keyDefinition: UserKeyDefinition): ActiveUserState { - // All other providers cache the creation of their corresponding `State` objects, this instance - // doesn't need to do that since it calls `SingleUserStateProvider` it will go through their caching - // layer, because of that, the creation of this instance is quite simple and not worth caching. - return new DefaultActiveUserState( - keyDefinition, - this.activeUserId$, - this.singleUserStateProvider, - ); - } -} diff --git a/libs/common/src/platform/state/implementations/default-active-user-state.ts b/libs/common/src/platform/state/implementations/default-active-user-state.ts deleted file mode 100644 index eb8165f8534..00000000000 --- a/libs/common/src/platform/state/implementations/default-active-user-state.ts +++ /dev/null @@ -1 +0,0 @@ -export { DefaultActiveUserState } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/implementations/default-derived-state.provider.ts b/libs/common/src/platform/state/implementations/default-derived-state.provider.ts deleted file mode 100644 index 06e5e30b5a4..00000000000 --- a/libs/common/src/platform/state/implementations/default-derived-state.provider.ts +++ /dev/null @@ -1 +0,0 @@ -export { DefaultDerivedStateProvider } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/implementations/default-derived-state.ts b/libs/common/src/platform/state/implementations/default-derived-state.ts deleted file mode 100644 index e66bc754c42..00000000000 --- a/libs/common/src/platform/state/implementations/default-derived-state.ts +++ /dev/null @@ -1 +0,0 @@ -export { DefaultDerivedState } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/implementations/default-global-state.provider.ts b/libs/common/src/platform/state/implementations/default-global-state.provider.ts deleted file mode 100644 index 667dcd60faf..00000000000 --- a/libs/common/src/platform/state/implementations/default-global-state.provider.ts +++ /dev/null @@ -1 +0,0 @@ -export { DefaultGlobalStateProvider } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/implementations/default-global-state.ts b/libs/common/src/platform/state/implementations/default-global-state.ts deleted file mode 100644 index 6306721cd6b..00000000000 --- a/libs/common/src/platform/state/implementations/default-global-state.ts +++ /dev/null @@ -1 +0,0 @@ -export { DefaultGlobalState } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/implementations/default-single-user-state.provider.ts b/libs/common/src/platform/state/implementations/default-single-user-state.provider.ts deleted file mode 100644 index b822c917a7f..00000000000 --- a/libs/common/src/platform/state/implementations/default-single-user-state.provider.ts +++ /dev/null @@ -1 +0,0 @@ -export { DefaultSingleUserStateProvider } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/implementations/default-single-user-state.ts b/libs/common/src/platform/state/implementations/default-single-user-state.ts deleted file mode 100644 index aec186a2756..00000000000 --- a/libs/common/src/platform/state/implementations/default-single-user-state.ts +++ /dev/null @@ -1 +0,0 @@ -export { DefaultSingleUserState } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/implementations/default-state.provider.ts b/libs/common/src/platform/state/implementations/default-state.provider.ts deleted file mode 100644 index e79cf5b59b2..00000000000 --- a/libs/common/src/platform/state/implementations/default-state.provider.ts +++ /dev/null @@ -1 +0,0 @@ -export { DefaultStateProvider } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/implementations/inline-derived-state.ts b/libs/common/src/platform/state/implementations/inline-derived-state.ts deleted file mode 100644 index aa19d8d7f16..00000000000 --- a/libs/common/src/platform/state/implementations/inline-derived-state.ts +++ /dev/null @@ -1 +0,0 @@ -export { InlineDerivedState, InlineDerivedStateProvider } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/implementations/state-base.ts b/libs/common/src/platform/state/implementations/state-base.ts deleted file mode 100644 index 88a2c8cfacf..00000000000 --- a/libs/common/src/platform/state/implementations/state-base.ts +++ /dev/null @@ -1 +0,0 @@ -export { StateBase } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/index.ts b/libs/common/src/platform/state/index.ts index 8a9175b171c..191e152ef67 100644 --- a/libs/common/src/platform/state/index.ts +++ b/libs/common/src/platform/state/index.ts @@ -1 +1,6 @@ +import { StateUpdateOptions as RequiredStateUpdateOptions } from "@bitwarden/state"; + export * from "@bitwarden/state"; +export { ActiveUserAccessor } from "@bitwarden/state-internal"; + +export type StateUpdateOptions = Partial>; diff --git a/libs/common/src/platform/state/key-definition.ts b/libs/common/src/platform/state/key-definition.ts deleted file mode 100644 index bc5b02ad5d6..00000000000 --- a/libs/common/src/platform/state/key-definition.ts +++ /dev/null @@ -1 +0,0 @@ -export { KeyDefinition, KeyDefinitionOptions } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/state-definition.ts b/libs/common/src/platform/state/state-definition.ts index f2a40429d1c..3fb66a99fb1 100644 --- a/libs/common/src/platform/state/state-definition.ts +++ b/libs/common/src/platform/state/state-definition.ts @@ -1,4 +1 @@ export { StateDefinition } from "@bitwarden/state"; - -// To be removed once references are updated to point to @bitwarden/storage-core -export { StorageLocation, ClientLocations } from "@bitwarden/storage-core"; diff --git a/libs/common/src/platform/state/state-event-registrar.service.ts b/libs/common/src/platform/state/state-event-registrar.service.ts deleted file mode 100644 index 1186221c626..00000000000 --- a/libs/common/src/platform/state/state-event-registrar.service.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { - StateEventRegistrarService, - StateEventInfo, - STATE_LOCK_EVENT, - STATE_LOGOUT_EVENT, -} from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/state-event-runner.service.ts b/libs/common/src/platform/state/state-event-runner.service.ts deleted file mode 100644 index 60fb11a8f5e..00000000000 --- a/libs/common/src/platform/state/state-event-runner.service.ts +++ /dev/null @@ -1 +0,0 @@ -export { StateEventRunnerService } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/state.provider.ts b/libs/common/src/platform/state/state.provider.ts deleted file mode 100644 index 4c36bed9593..00000000000 --- a/libs/common/src/platform/state/state.provider.ts +++ /dev/null @@ -1 +0,0 @@ -export { StateProvider } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/storage/memory-storage.service.ts b/libs/common/src/platform/state/storage/memory-storage.service.ts deleted file mode 100644 index 53810f11d22..00000000000 --- a/libs/common/src/platform/state/storage/memory-storage.service.ts +++ /dev/null @@ -1 +0,0 @@ -export { SerializedMemoryStorageService as MemoryStorageService } from "@bitwarden/storage-core"; diff --git a/libs/common/src/platform/state/user-key-definition.ts b/libs/common/src/platform/state/user-key-definition.ts deleted file mode 100644 index fd3bdea32d2..00000000000 --- a/libs/common/src/platform/state/user-key-definition.ts +++ /dev/null @@ -1 +0,0 @@ -export { UserKeyDefinition, UserKeyDefinitionOptions } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/user-state.provider.ts b/libs/common/src/platform/state/user-state.provider.ts deleted file mode 100644 index eff529d79b7..00000000000 --- a/libs/common/src/platform/state/user-state.provider.ts +++ /dev/null @@ -1 +0,0 @@ -export { ActiveUserStateProvider, SingleUserStateProvider } from "@bitwarden/state"; diff --git a/libs/common/src/platform/state/user-state.ts b/libs/common/src/platform/state/user-state.ts deleted file mode 100644 index 2fbfd4ce418..00000000000 --- a/libs/common/src/platform/state/user-state.ts +++ /dev/null @@ -1 +0,0 @@ -export { ActiveUserState, SingleUserState, CombinedState } from "@bitwarden/state"; diff --git a/libs/state-internal/README.md b/libs/state-internal/README.md new file mode 100644 index 00000000000..b13c81a00d6 --- /dev/null +++ b/libs/state-internal/README.md @@ -0,0 +1,5 @@ +# state-internal + +Owned by: platform + +The internal parts of @bitwarden/state that should not be used by other teams. diff --git a/libs/state-internal/eslint.config.mjs b/libs/state-internal/eslint.config.mjs new file mode 100644 index 00000000000..9c37d10e3ff --- /dev/null +++ b/libs/state-internal/eslint.config.mjs @@ -0,0 +1,3 @@ +import baseConfig from "../../eslint.config.mjs"; + +export default [...baseConfig]; diff --git a/libs/state-internal/jest.config.js b/libs/state-internal/jest.config.js new file mode 100644 index 00000000000..84c62e4d54f --- /dev/null +++ b/libs/state-internal/jest.config.js @@ -0,0 +1,10 @@ +module.exports = { + displayName: "state-internal", + preset: "../../jest.preset.js", + testEnvironment: "node", + transform: { + "^.+\\.[tj]s$": ["ts-jest", { tsconfig: "/tsconfig.spec.json" }], + }, + moduleFileExtensions: ["ts", "js", "html"], + coverageDirectory: "../../coverage/libs/state-internal", +}; diff --git a/libs/state-internal/package.json b/libs/state-internal/package.json new file mode 100644 index 00000000000..2a625220598 --- /dev/null +++ b/libs/state-internal/package.json @@ -0,0 +1,11 @@ +{ + "name": "@bitwarden/state-internal", + "version": "0.0.1", + "description": "The internal parts of @bitwarden/state that should not be used by other teams.", + "private": true, + "type": "commonjs", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "license": "GPL-3.0", + "author": "platform" +} diff --git a/libs/state-internal/project.json b/libs/state-internal/project.json new file mode 100644 index 00000000000..fde95837ff8 --- /dev/null +++ b/libs/state-internal/project.json @@ -0,0 +1,33 @@ +{ + "name": "state-internal", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/state-internal/src", + "projectType": "library", + "tags": [], + "targets": { + "build": { + "executor": "@nx/js:tsc", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/libs/state-internal", + "main": "libs/state-internal/src/index.ts", + "tsConfig": "libs/state-internal/tsconfig.lib.json", + "assets": ["libs/state-internal/*.md"] + } + }, + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/state-internal/**/*.ts"] + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/state-internal/jest.config.js" + } + } + } +} diff --git a/libs/common/src/platform/state/active-user.accessor.ts b/libs/state-internal/src/active-user.accessor.ts similarity index 100% rename from libs/common/src/platform/state/active-user.accessor.ts rename to libs/state-internal/src/active-user.accessor.ts diff --git a/libs/state/src/core/implementations/default-active-user-state.provider.spec.ts b/libs/state-internal/src/default-active-user-state.provider.spec.ts similarity index 97% rename from libs/state/src/core/implementations/default-active-user-state.provider.spec.ts rename to libs/state-internal/src/default-active-user-state.provider.spec.ts index 419daeb1ecc..cf1ab1f14c4 100644 --- a/libs/state/src/core/implementations/default-active-user-state.provider.spec.ts +++ b/libs/state-internal/src/default-active-user-state.provider.spec.ts @@ -5,6 +5,12 @@ import { Observable, of } from "rxjs"; import { awaitAsync, trackEmissions } from "@bitwarden/core-test-utils"; +import { + DeriveDefinition, + KeyDefinition, + StateDefinition, + UserKeyDefinition, +} from "@bitwarden/state"; import { FakeActiveUserAccessor, FakeActiveUserStateProvider, @@ -14,11 +20,6 @@ import { } from "@bitwarden/state-test-utils"; import { UserId } from "@bitwarden/user-core"; -import { DeriveDefinition } from "../derive-definition"; -import { KeyDefinition } from "../key-definition"; -import { StateDefinition } from "../state-definition"; -import { UserKeyDefinition } from "../user-key-definition"; - import { DefaultStateProvider } from "./default-state.provider"; describe("DefaultStateProvider", () => { diff --git a/libs/state/src/core/implementations/default-active-user-state.provider.ts b/libs/state-internal/src/default-active-user-state.provider.ts similarity index 83% rename from libs/state/src/core/implementations/default-active-user-state.provider.ts rename to libs/state-internal/src/default-active-user-state.provider.ts index e7e456f7401..681f69f5801 100644 --- a/libs/state/src/core/implementations/default-active-user-state.provider.ts +++ b/libs/state-internal/src/default-active-user-state.provider.ts @@ -2,13 +2,15 @@ // @ts-strict-ignore import { Observable, distinctUntilChanged } from "rxjs"; +import { + ActiveUserState, + ActiveUserStateProvider, + SingleUserStateProvider, + UserKeyDefinition, +} from "@bitwarden/state"; import { UserId } from "@bitwarden/user-core"; -import { ActiveUserAccessor } from "../active-user.accessor"; -import { UserKeyDefinition } from "../user-key-definition"; -import { ActiveUserState } from "../user-state"; -import { ActiveUserStateProvider, SingleUserStateProvider } from "../user-state.provider"; - +import { ActiveUserAccessor } from "./active-user.accessor"; import { DefaultActiveUserState } from "./default-active-user-state"; export class DefaultActiveUserStateProvider implements ActiveUserStateProvider { diff --git a/libs/state/src/core/implementations/default-active-user-state.spec.ts b/libs/state-internal/src/default-active-user-state.spec.ts similarity index 99% rename from libs/state/src/core/implementations/default-active-user-state.spec.ts rename to libs/state-internal/src/default-active-user-state.spec.ts index 0c3834ee574..88f4d94a105 100644 --- a/libs/state/src/core/implementations/default-active-user-state.spec.ts +++ b/libs/state-internal/src/default-active-user-state.spec.ts @@ -8,14 +8,11 @@ import { Jsonify } from "type-fest"; import { awaitAsync, trackEmissions } from "@bitwarden/core-test-utils"; import { LogService } from "@bitwarden/logging"; +import { StateDefinition, StateEventRegistrarService, UserKeyDefinition } from "@bitwarden/state"; import { StorageServiceProvider } from "@bitwarden/storage-core"; import { FakeStorageService } from "@bitwarden/storage-test-utils"; import { UserId } from "@bitwarden/user-core"; -import { StateDefinition } from "../state-definition"; -import { StateEventRegistrarService } from "../state-event-registrar.service"; -import { UserKeyDefinition } from "../user-key-definition"; - import { DefaultActiveUserState } from "./default-active-user-state"; import { DefaultSingleUserStateProvider } from "./default-single-user-state.provider"; diff --git a/libs/state/src/core/implementations/default-active-user-state.ts b/libs/state-internal/src/default-active-user-state.ts similarity index 84% rename from libs/state/src/core/implementations/default-active-user-state.ts rename to libs/state-internal/src/default-active-user-state.ts index aa8b1e401da..e4a0d3c0519 100644 --- a/libs/state/src/core/implementations/default-active-user-state.ts +++ b/libs/state-internal/src/default-active-user-state.ts @@ -2,13 +2,16 @@ // @ts-strict-ignore import { Observable, map, switchMap, firstValueFrom, timeout, throwError, NEVER } from "rxjs"; +import { + activeMarker, + ActiveUserState, + CombinedState, + SingleUserStateProvider, + StateUpdateOptions, + UserKeyDefinition, +} from "@bitwarden/state"; import { UserId } from "@bitwarden/user-core"; -import { StateUpdateOptions } from "../state-update-options"; -import { UserKeyDefinition } from "../user-key-definition"; -import { ActiveUserState, CombinedState, activeMarker } from "../user-state"; -import { SingleUserStateProvider } from "../user-state.provider"; - export class DefaultActiveUserState implements ActiveUserState { [activeMarker]: true; combinedState$: Observable>; @@ -33,7 +36,7 @@ export class DefaultActiveUserState implements ActiveUserState { async update( configureState: (state: T, dependency: TCombine) => T, - options: StateUpdateOptions = {}, + options: Partial> = {}, ): Promise<[UserId, T]> { const userId = await firstValueFrom( this.activeUserId$.pipe( diff --git a/libs/state/src/core/implementations/default-derived-state.provider.ts b/libs/state-internal/src/default-derived-state.provider.ts similarity index 88% rename from libs/state/src/core/implementations/default-derived-state.provider.ts rename to libs/state-internal/src/default-derived-state.provider.ts index 04883f63117..7ac809e0568 100644 --- a/libs/state/src/core/implementations/default-derived-state.provider.ts +++ b/libs/state-internal/src/default-derived-state.provider.ts @@ -1,9 +1,11 @@ import { Observable } from "rxjs"; -import { DerivedStateDependencies } from "../../types/state"; -import { DeriveDefinition } from "../derive-definition"; -import { DerivedState } from "../derived-state"; -import { DerivedStateProvider } from "../derived-state.provider"; +import { + DeriveDefinition, + DerivedState, + DerivedStateDependencies, + DerivedStateProvider, +} from "@bitwarden/state"; import { DefaultDerivedState } from "./default-derived-state"; diff --git a/libs/state/src/core/implementations/default-derived-state.spec.ts b/libs/state-internal/src/default-derived-state.spec.ts similarity index 98% rename from libs/state/src/core/implementations/default-derived-state.spec.ts rename to libs/state-internal/src/default-derived-state.spec.ts index 052a04ed19a..2ca9f8fb9ab 100644 --- a/libs/state/src/core/implementations/default-derived-state.spec.ts +++ b/libs/state-internal/src/default-derived-state.spec.ts @@ -5,9 +5,7 @@ import { Subject, firstValueFrom } from "rxjs"; import { awaitAsync, trackEmissions } from "@bitwarden/core-test-utils"; - -import { DeriveDefinition } from "../derive-definition"; -import { StateDefinition } from "../state-definition"; +import { DeriveDefinition, StateDefinition } from "@bitwarden/state"; import { DefaultDerivedState } from "./default-derived-state"; import { DefaultDerivedStateProvider } from "./default-derived-state.provider"; diff --git a/libs/state/src/core/implementations/default-derived-state.ts b/libs/state-internal/src/default-derived-state.ts similarity index 88% rename from libs/state/src/core/implementations/default-derived-state.ts rename to libs/state-internal/src/default-derived-state.ts index 377a9e4dda3..ce84be93f92 100644 --- a/libs/state/src/core/implementations/default-derived-state.ts +++ b/libs/state-internal/src/default-derived-state.ts @@ -1,8 +1,6 @@ import { Observable, ReplaySubject, Subject, concatMap, merge, share, timer } from "rxjs"; -import { DerivedStateDependencies } from "../../types/state"; -import { DeriveDefinition } from "../derive-definition"; -import { DerivedState } from "../derived-state"; +import { DeriveDefinition, DerivedState, DerivedStateDependencies } from "@bitwarden/state"; /** * Default derived state diff --git a/libs/state/src/core/implementations/default-global-state.provider.ts b/libs/state-internal/src/default-global-state.provider.ts similarity index 90% rename from libs/state/src/core/implementations/default-global-state.provider.ts rename to libs/state-internal/src/default-global-state.provider.ts index f0828736147..1dc5e3a1dc3 100644 --- a/libs/state/src/core/implementations/default-global-state.provider.ts +++ b/libs/state-internal/src/default-global-state.provider.ts @@ -1,12 +1,9 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore import { LogService } from "@bitwarden/logging"; +import { GlobalState, GlobalStateProvider, KeyDefinition } from "@bitwarden/state"; import { StorageServiceProvider } from "@bitwarden/storage-core"; -import { GlobalState } from "../global-state"; -import { GlobalStateProvider } from "../global-state.provider"; -import { KeyDefinition } from "../key-definition"; - import { DefaultGlobalState } from "./default-global-state"; export class DefaultGlobalStateProvider implements GlobalStateProvider { diff --git a/libs/state/src/core/implementations/default-global-state.spec.ts b/libs/state-internal/src/default-global-state.spec.ts similarity index 98% rename from libs/state/src/core/implementations/default-global-state.spec.ts rename to libs/state-internal/src/default-global-state.spec.ts index ecfbc001cf0..9532962809a 100644 --- a/libs/state/src/core/implementations/default-global-state.spec.ts +++ b/libs/state-internal/src/default-global-state.spec.ts @@ -9,12 +9,11 @@ import { Jsonify } from "type-fest"; import { trackEmissions, awaitAsync } from "@bitwarden/core-test-utils"; import { LogService } from "@bitwarden/logging"; +import { KeyDefinition, StateDefinition } from "@bitwarden/state"; import { FakeStorageService } from "@bitwarden/storage-test-utils"; -import { KeyDefinition, globalKeyBuilder } from "../key-definition"; -import { StateDefinition } from "../state-definition"; - import { DefaultGlobalState } from "./default-global-state"; +import { globalKeyBuilder } from "./util"; class TestState { date: Date; diff --git a/libs/state/src/core/implementations/default-global-state.ts b/libs/state-internal/src/default-global-state.ts similarity index 82% rename from libs/state/src/core/implementations/default-global-state.ts rename to libs/state-internal/src/default-global-state.ts index cb6c6c41a02..e8109ffc1ed 100644 --- a/libs/state/src/core/implementations/default-global-state.ts +++ b/libs/state-internal/src/default-global-state.ts @@ -1,10 +1,9 @@ import { LogService } from "@bitwarden/logging"; +import { GlobalState, KeyDefinition } from "@bitwarden/state"; import { AbstractStorageService, ObservableStorageService } from "@bitwarden/storage-core"; -import { GlobalState } from "../global-state"; -import { KeyDefinition, globalKeyBuilder } from "../key-definition"; - import { StateBase } from "./state-base"; +import { globalKeyBuilder } from "./util"; export class DefaultGlobalState extends StateBase> diff --git a/libs/state/src/core/implementations/default-single-user-state.provider.ts b/libs/state-internal/src/default-single-user-state.provider.ts similarity index 87% rename from libs/state/src/core/implementations/default-single-user-state.provider.ts rename to libs/state-internal/src/default-single-user-state.provider.ts index 252ea1fa3e7..103ba36a156 100644 --- a/libs/state/src/core/implementations/default-single-user-state.provider.ts +++ b/libs/state-internal/src/default-single-user-state.provider.ts @@ -1,14 +1,15 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore import { LogService } from "@bitwarden/logging"; +import { + SingleUserState, + SingleUserStateProvider, + StateEventRegistrarService, + UserKeyDefinition, +} from "@bitwarden/state"; import { StorageServiceProvider } from "@bitwarden/storage-core"; import { UserId } from "@bitwarden/user-core"; -import { StateEventRegistrarService } from "../state-event-registrar.service"; -import { UserKeyDefinition } from "../user-key-definition"; -import { SingleUserState } from "../user-state"; -import { SingleUserStateProvider } from "../user-state.provider"; - import { DefaultSingleUserState } from "./default-single-user-state"; export class DefaultSingleUserStateProvider implements SingleUserStateProvider { diff --git a/libs/state/src/core/implementations/default-single-user-state.spec.ts b/libs/state-internal/src/default-single-user-state.spec.ts similarity index 98% rename from libs/state/src/core/implementations/default-single-user-state.spec.ts rename to libs/state-internal/src/default-single-user-state.spec.ts index c6262581fa6..97a2173f669 100644 --- a/libs/state/src/core/implementations/default-single-user-state.spec.ts +++ b/libs/state-internal/src/default-single-user-state.spec.ts @@ -10,13 +10,10 @@ import { Jsonify } from "type-fest"; import { trackEmissions, awaitAsync } from "@bitwarden/core-test-utils"; import { newGuid } from "@bitwarden/guid"; import { LogService } from "@bitwarden/logging"; +import { StateDefinition, StateEventRegistrarService, UserKeyDefinition } from "@bitwarden/state"; import { FakeStorageService } from "@bitwarden/storage-test-utils"; import { UserId } from "@bitwarden/user-core"; -import { StateDefinition } from "../state-definition"; -import { StateEventRegistrarService } from "../state-event-registrar.service"; -import { UserKeyDefinition } from "../user-key-definition"; - import { DefaultSingleUserState } from "./default-single-user-state"; class TestState { diff --git a/libs/state/src/core/implementations/default-single-user-state.ts b/libs/state-internal/src/default-single-user-state.ts similarity index 85% rename from libs/state/src/core/implementations/default-single-user-state.ts rename to libs/state-internal/src/default-single-user-state.ts index b177faf011d..1496a710537 100644 --- a/libs/state/src/core/implementations/default-single-user-state.ts +++ b/libs/state-internal/src/default-single-user-state.ts @@ -1,13 +1,15 @@ import { Observable, combineLatest, of } from "rxjs"; import { LogService } from "@bitwarden/logging"; +import { + CombinedState, + SingleUserState, + StateEventRegistrarService, + UserKeyDefinition, +} from "@bitwarden/state"; import { AbstractStorageService, ObservableStorageService } from "@bitwarden/storage-core"; import { UserId } from "@bitwarden/user-core"; -import { StateEventRegistrarService } from "../state-event-registrar.service"; -import { UserKeyDefinition } from "../user-key-definition"; -import { CombinedState, SingleUserState } from "../user-state"; - import { StateBase } from "./state-base"; export class DefaultSingleUserState diff --git a/libs/state/src/core/state-event-registrar.service.spec.ts b/libs/state-internal/src/default-state-event-registrar.service.spec.ts similarity index 87% rename from libs/state/src/core/state-event-registrar.service.spec.ts rename to libs/state-internal/src/default-state-event-registrar.service.spec.ts index e79269077d3..12b7db2e88e 100644 --- a/libs/state/src/core/state-event-registrar.service.spec.ts +++ b/libs/state-internal/src/default-state-event-registrar.service.spec.ts @@ -1,5 +1,6 @@ import { mock } from "jest-mock-extended"; +import { StateDefinition, UserKeyDefinition } from "@bitwarden/state"; import { FakeGlobalStateProvider } from "@bitwarden/state-test-utils"; import { AbstractStorageService, @@ -7,16 +8,17 @@ import { StorageServiceProvider, } from "@bitwarden/storage-core"; -import { StateDefinition } from "./state-definition"; -import { STATE_LOCK_EVENT, StateEventRegistrarService } from "./state-event-registrar.service"; -import { UserKeyDefinition } from "./user-key-definition"; +import { + DefaultStateEventRegistrarService, + STATE_LOCK_EVENT, +} from "./default-state-event-registrar.service"; describe("StateEventRegistrarService", () => { const globalStateProvider = new FakeGlobalStateProvider(); const lockState = globalStateProvider.getFake(STATE_LOCK_EVENT); const storageServiceProvider = mock(); - const sut = new StateEventRegistrarService(globalStateProvider, storageServiceProvider); + const sut = new DefaultStateEventRegistrarService(globalStateProvider, storageServiceProvider); describe("registerEvents", () => { const fakeKeyDefinition = new UserKeyDefinition( diff --git a/libs/state-internal/src/default-state-event-registrar.service.ts b/libs/state-internal/src/default-state-event-registrar.service.ts new file mode 100644 index 00000000000..897b797c578 --- /dev/null +++ b/libs/state-internal/src/default-state-event-registrar.service.ts @@ -0,0 +1,78 @@ +import { + CLEAR_EVENT_DISK, + ClearEvent, + GlobalState, + GlobalStateProvider, + KeyDefinition, + UserKeyDefinition, +} from "@bitwarden/state"; +import { PossibleLocation, StorageServiceProvider } from "@bitwarden/storage-core"; + +export type StateEventInfo = { + state: string; + key: string; + location: PossibleLocation; +}; + +export const STATE_LOCK_EVENT = KeyDefinition.array(CLEAR_EVENT_DISK, "lock", { + deserializer: (e) => e, +}); + +export const STATE_LOGOUT_EVENT = KeyDefinition.array(CLEAR_EVENT_DISK, "logout", { + deserializer: (e) => e, +}); + +export class DefaultStateEventRegistrarService { + private readonly stateEventStateMap: { [Prop in ClearEvent]: GlobalState }; + + constructor( + globalStateProvider: GlobalStateProvider, + private storageServiceProvider: StorageServiceProvider, + ) { + this.stateEventStateMap = { + lock: globalStateProvider.get(STATE_LOCK_EVENT), + logout: globalStateProvider.get(STATE_LOGOUT_EVENT), + }; + } + + async registerEvents(keyDefinition: UserKeyDefinition) { + for (const clearEvent of keyDefinition.clearOn) { + const eventState = this.stateEventStateMap[clearEvent]; + // Determine the storage location for this + const [storageLocation] = this.storageServiceProvider.get( + keyDefinition.stateDefinition.defaultStorageLocation, + keyDefinition.stateDefinition.storageLocationOverrides, + ); + + const newEvent: StateEventInfo = { + state: keyDefinition.stateDefinition.name, + key: keyDefinition.key, + location: storageLocation, + }; + + // Only update the event state if the existing list doesn't have a matching entry + await eventState.update( + (existingTickets) => { + existingTickets ??= []; + existingTickets.push(newEvent); + return existingTickets; + }, + { + shouldUpdate: (currentTickets) => { + return ( + // If the current tickets are null, then it will for sure be added + currentTickets == null || + // If an existing match couldn't be found, we also need to add one + currentTickets.findIndex( + (e) => + e.state === newEvent.state && + e.key === newEvent.key && + e.location === newEvent.location, + ) === -1 + ); + }, + }, + ); + } + } +} diff --git a/libs/state/src/core/state-event-runner.service.spec.ts b/libs/state-internal/src/default-state-event-runner.service.spec.ts similarity index 88% rename from libs/state/src/core/state-event-runner.service.spec.ts rename to libs/state-internal/src/default-state-event-runner.service.spec.ts index 7a7ddb2d9f5..422d8a307be 100644 --- a/libs/state/src/core/state-event-runner.service.spec.ts +++ b/libs/state-internal/src/default-state-event-runner.service.spec.ts @@ -8,16 +8,16 @@ import { } from "@bitwarden/storage-core"; import { UserId } from "@bitwarden/user-core"; -import { STATE_LOCK_EVENT } from "./state-event-registrar.service"; -import { StateEventRunnerService } from "./state-event-runner.service"; +import { STATE_LOCK_EVENT } from "./default-state-event-registrar.service"; +import { DefaultStateEventRunnerService } from "./default-state-event-runner.service"; -describe("EventRunnerService", () => { +describe("DefaultStateEventRunnerService", () => { const fakeGlobalStateProvider = new FakeGlobalStateProvider(); const lockState = fakeGlobalStateProvider.getFake(STATE_LOCK_EVENT); const storageServiceProvider = mock(); - const sut = new StateEventRunnerService(fakeGlobalStateProvider, storageServiceProvider); + const sut = new DefaultStateEventRunnerService(fakeGlobalStateProvider, storageServiceProvider); describe("handleEvent", () => { it("does nothing if there are no events in state", async () => { diff --git a/libs/state-internal/src/default-state-event-runner.service.ts b/libs/state-internal/src/default-state-event-runner.service.ts new file mode 100644 index 00000000000..a81612d1fee --- /dev/null +++ b/libs/state-internal/src/default-state-event-runner.service.ts @@ -0,0 +1,89 @@ +import { firstValueFrom } from "rxjs"; + +import { + ClearEvent, + GlobalState, + GlobalStateProvider, + StateDefinition, + StateEventRunnerService, + UserKeyDefinition, +} from "@bitwarden/state"; +import { StorageLocation, StorageServiceProvider } from "@bitwarden/storage-core"; +import { UserId } from "@bitwarden/user-core"; + +import { + STATE_LOCK_EVENT, + STATE_LOGOUT_EVENT, + StateEventInfo, +} from "./default-state-event-registrar.service"; + +export class DefaultStateEventRunnerService implements StateEventRunnerService { + private readonly stateEventMap: { [Prop in ClearEvent]: GlobalState }; + + constructor( + globalStateProvider: GlobalStateProvider, + private storageServiceProvider: StorageServiceProvider, + ) { + this.stateEventMap = { + lock: globalStateProvider.get(STATE_LOCK_EVENT), + logout: globalStateProvider.get(STATE_LOGOUT_EVENT), + }; + } + + async handleEvent(event: ClearEvent, userId: UserId) { + let tickets = await firstValueFrom(this.stateEventMap[event].state$); + tickets ??= []; + + const failures: string[] = []; + + for (const ticket of tickets) { + try { + const [, service] = this.storageServiceProvider.get( + ticket.location, + {}, // The storage location is already the computed storage location for this client + ); + + const ticketStorageKey = this.storageKeyFor(userId, ticket); + + // Evaluate current value so we can avoid writing to state if we don't need to + const currentValue = await service.get(ticketStorageKey); + if (currentValue != null) { + await service.remove(ticketStorageKey); + } + } catch (err: unknown) { + let errorMessage = "Unknown Error"; + if ( + err != null && + typeof err === "object" && + "message" in err && + typeof err.message === "string" + ) { + errorMessage = err.message; + } + + failures.push( + `${errorMessage} in ${ticket.state} > ${ticket.key} located ${ticket.location}`, + ); + } + } + + if (failures.length > 0) { + // Throw aggregated error + throw new Error( + `One or more errors occurred while handling event '${event}' for user ${userId}.\n${failures.join("\n")}`, + ); + } + } + + private storageKeyFor(userId: UserId, ticket: StateEventInfo) { + const userKey = new UserKeyDefinition( + new StateDefinition(ticket.state, ticket.location as unknown as StorageLocation), + ticket.key, + { + deserializer: (v) => v, + clearOn: [], + }, + ); + return userKey.buildKey(userId); + } +} diff --git a/libs/state/src/core/implementations/default-state.provider.spec.ts b/libs/state-internal/src/default-state.provider.spec.ts similarity index 97% rename from libs/state/src/core/implementations/default-state.provider.spec.ts rename to libs/state-internal/src/default-state.provider.spec.ts index 419daeb1ecc..cf1ab1f14c4 100644 --- a/libs/state/src/core/implementations/default-state.provider.spec.ts +++ b/libs/state-internal/src/default-state.provider.spec.ts @@ -5,6 +5,12 @@ import { Observable, of } from "rxjs"; import { awaitAsync, trackEmissions } from "@bitwarden/core-test-utils"; +import { + DeriveDefinition, + KeyDefinition, + StateDefinition, + UserKeyDefinition, +} from "@bitwarden/state"; import { FakeActiveUserAccessor, FakeActiveUserStateProvider, @@ -14,11 +20,6 @@ import { } from "@bitwarden/state-test-utils"; import { UserId } from "@bitwarden/user-core"; -import { DeriveDefinition } from "../derive-definition"; -import { KeyDefinition } from "../key-definition"; -import { StateDefinition } from "../state-definition"; -import { UserKeyDefinition } from "../user-key-definition"; - import { DefaultStateProvider } from "./default-state.provider"; describe("DefaultStateProvider", () => { diff --git a/libs/state/src/core/implementations/default-state.provider.ts b/libs/state-internal/src/default-state.provider.ts similarity index 84% rename from libs/state/src/core/implementations/default-state.provider.ts rename to libs/state-internal/src/default-state.provider.ts index 45a8bc8e8d3..1219246e2da 100644 --- a/libs/state/src/core/implementations/default-state.provider.ts +++ b/libs/state-internal/src/default-state.provider.ts @@ -2,17 +2,19 @@ // @ts-strict-ignore import { Observable, filter, of, switchMap, take } from "rxjs"; +import { + ActiveUserStateProvider, + DeriveDefinition, + DerivedState, + DerivedStateDependencies, + DerivedStateProvider, + GlobalStateProvider, + SingleUserStateProvider, + StateProvider, + UserKeyDefinition, +} from "@bitwarden/state"; import { UserId } from "@bitwarden/user-core"; -import { DerivedStateDependencies } from "../../types/state"; -import { DeriveDefinition } from "../derive-definition"; -import { DerivedState } from "../derived-state"; -import { DerivedStateProvider } from "../derived-state.provider"; -import { GlobalStateProvider } from "../global-state.provider"; -import { StateProvider } from "../state.provider"; -import { UserKeyDefinition } from "../user-key-definition"; -import { ActiveUserStateProvider, SingleUserStateProvider } from "../user-state.provider"; - export class DefaultStateProvider implements StateProvider { activeUserId$: Observable; constructor( diff --git a/libs/state/src/core/implementations/index.ts b/libs/state-internal/src/index.ts similarity index 62% rename from libs/state/src/core/implementations/index.ts rename to libs/state-internal/src/index.ts index bb2544ad6dc..c742e6e74da 100644 --- a/libs/state/src/core/implementations/index.ts +++ b/libs/state-internal/src/index.ts @@ -10,3 +10,7 @@ export * from "./default-state.provider"; export * from "./inline-derived-state"; export * from "./state-base"; export * from "./util"; +export { ActiveUserAccessor } from "./active-user.accessor"; +export { DefaultStateService } from "./legacy/default-state.service"; +export { DefaultStateEventRegistrarService } from "./default-state-event-registrar.service"; +export { DefaultStateEventRunnerService } from "./default-state-event-runner.service"; diff --git a/libs/state/src/core/implementations/inline-derived-state.spec.ts b/libs/state-internal/src/inline-derived-state.spec.ts similarity index 93% rename from libs/state/src/core/implementations/inline-derived-state.spec.ts rename to libs/state-internal/src/inline-derived-state.spec.ts index 28a1a701b0b..1347a823d67 100644 --- a/libs/state/src/core/implementations/inline-derived-state.spec.ts +++ b/libs/state-internal/src/inline-derived-state.spec.ts @@ -1,7 +1,6 @@ import { Subject, firstValueFrom } from "rxjs"; -import { DeriveDefinition } from "../derive-definition"; -import { StateDefinition } from "../state-definition"; +import { DeriveDefinition, StateDefinition } from "@bitwarden/state"; import { InlineDerivedState } from "./inline-derived-state"; diff --git a/libs/state/src/core/implementations/inline-derived-state.ts b/libs/state-internal/src/inline-derived-state.ts similarity index 80% rename from libs/state/src/core/implementations/inline-derived-state.ts rename to libs/state-internal/src/inline-derived-state.ts index 1202839d5c0..2c03443d42c 100644 --- a/libs/state/src/core/implementations/inline-derived-state.ts +++ b/libs/state-internal/src/inline-derived-state.ts @@ -1,9 +1,11 @@ import { Observable, concatMap } from "rxjs"; -import { DerivedStateDependencies } from "../../types/state"; -import { DeriveDefinition } from "../derive-definition"; -import { DerivedState } from "../derived-state"; -import { DerivedStateProvider } from "../derived-state.provider"; +import { + DeriveDefinition, + DerivedState, + DerivedStateDependencies, + DerivedStateProvider, +} from "@bitwarden/state"; export class InlineDerivedStateProvider implements DerivedStateProvider { get( diff --git a/libs/state/src/legacy/default-state.service.ts b/libs/state-internal/src/legacy/default-state.service.ts similarity index 96% rename from libs/state/src/legacy/default-state.service.ts rename to libs/state-internal/src/legacy/default-state.service.ts index b1c5ddb3a0b..99580b8c518 100644 --- a/libs/state/src/legacy/default-state.service.ts +++ b/libs/state-internal/src/legacy/default-state.service.ts @@ -1,12 +1,12 @@ import { firstValueFrom } from "rxjs"; +import { RequiredUserId, StateService } from "@bitwarden/state"; import { StorageService } from "@bitwarden/storage-core"; import { UserId } from "@bitwarden/user-core"; -import { ActiveUserAccessor } from "../core"; +import { ActiveUserAccessor } from "../active-user.accessor"; import { GlobalState } from "./global-state"; -import { RequiredUserId, StateService } from "./state.service"; const keys = { global: "global", diff --git a/libs/state/src/legacy/global-state.ts b/libs/state-internal/src/legacy/global-state.ts similarity index 100% rename from libs/state/src/legacy/global-state.ts rename to libs/state-internal/src/legacy/global-state.ts diff --git a/libs/state/src/core/implementations/specific-state.provider.spec.ts b/libs/state-internal/src/specific-state.provider.spec.ts similarity index 96% rename from libs/state/src/core/implementations/specific-state.provider.spec.ts rename to libs/state-internal/src/specific-state.provider.spec.ts index 287fd8702eb..2a74de2cb9f 100644 --- a/libs/state/src/core/implementations/specific-state.provider.spec.ts +++ b/libs/state-internal/src/specific-state.provider.spec.ts @@ -1,16 +1,17 @@ import { mock } from "jest-mock-extended"; import { LogService } from "@bitwarden/logging"; +import { + KeyDefinition, + StateDefinition, + StateEventRegistrarService, + UserKeyDefinition, +} from "@bitwarden/state"; import { FakeActiveUserAccessor } from "@bitwarden/state-test-utils"; import { StorageServiceProvider } from "@bitwarden/storage-core"; import { FakeStorageService } from "@bitwarden/storage-test-utils"; import { UserId } from "@bitwarden/user-core"; -import { KeyDefinition } from "../key-definition"; -import { StateDefinition } from "../state-definition"; -import { StateEventRegistrarService } from "../state-event-registrar.service"; -import { UserKeyDefinition } from "../user-key-definition"; - import { DefaultActiveUserState } from "./default-active-user-state"; import { DefaultActiveUserStateProvider } from "./default-active-user-state.provider"; import { DefaultGlobalState } from "./default-global-state"; diff --git a/libs/state/src/core/implementations/state-base.ts b/libs/state-internal/src/state-base.ts similarity index 90% rename from libs/state/src/core/implementations/state-base.ts rename to libs/state-internal/src/state-base.ts index 72da2075e71..d35eebce4d8 100644 --- a/libs/state/src/core/implementations/state-base.ts +++ b/libs/state-internal/src/state-base.ts @@ -16,13 +16,10 @@ import { import { Jsonify } from "type-fest"; import { LogService } from "@bitwarden/logging"; +import { DebugOptions, StateUpdateOptions, StorageKey } from "@bitwarden/state"; import { AbstractStorageService, ObservableStorageService } from "@bitwarden/storage-core"; -import { StorageKey } from "../../types/state"; -import { DebugOptions } from "../key-definition"; -import { populateOptionsWithDefault, StateUpdateOptions } from "../state-update-options"; - -import { getStoredValue } from "./util"; +import { getStoredValue, populateOptionsWithDefault } from "./util"; // The parts of a KeyDefinition this class cares about to make it work type KeyDefinitionRequirements = { @@ -85,15 +82,15 @@ export abstract class StateBase> async update( configureState: (state: T | null, dependency: TCombine) => T | null, - options: StateUpdateOptions = {}, + options: Partial> = {}, ): Promise { - options = populateOptionsWithDefault(options); + const normalizedOptions = populateOptionsWithDefault(options); if (this.updatePromise != null) { await this.updatePromise; } try { - this.updatePromise = this.internalUpdate(configureState, options); + this.updatePromise = this.internalUpdate(configureState, normalizedOptions); return await this.updatePromise; } finally { this.updatePromise = null; diff --git a/libs/state-internal/src/state-internal.spec.ts b/libs/state-internal/src/state-internal.spec.ts new file mode 100644 index 00000000000..65af2748714 --- /dev/null +++ b/libs/state-internal/src/state-internal.spec.ts @@ -0,0 +1,8 @@ +import * as lib from "./index"; + +describe("state-internal", () => { + // This test will fail until something is exported from index.ts + it("should work", () => { + expect(lib).toBeDefined(); + }); +}); diff --git a/libs/state/src/core/implementations/util.spec.ts b/libs/state-internal/src/util.spec.ts similarity index 100% rename from libs/state/src/core/implementations/util.spec.ts rename to libs/state-internal/src/util.spec.ts diff --git a/libs/state-internal/src/util.ts b/libs/state-internal/src/util.ts new file mode 100644 index 00000000000..3b0e25f8ce4 --- /dev/null +++ b/libs/state-internal/src/util.ts @@ -0,0 +1,38 @@ +import { Jsonify } from "type-fest"; + +import { KeyDefinition, StateUpdateOptions, StorageKey } from "@bitwarden/state"; +import { AbstractStorageService } from "@bitwarden/storage-core"; + +export async function getStoredValue( + key: string, + storage: AbstractStorageService, + deserializer: (jsonValue: Jsonify) => T | null, +) { + if (storage.valuesRequireDeserialization) { + const jsonValue = await storage.get>(key); + return deserializer(jsonValue); + } else { + const value = await storage.get(key); + return value ?? null; + } +} + +/** + * Creates a {@link StorageKey} + * @param keyDefinition The key definition of which data the key should point to. + * @returns A key that is ready to be used in a storage service to get data. + */ +export function globalKeyBuilder(keyDefinition: KeyDefinition): StorageKey { + return `global_${keyDefinition.stateDefinition.name}_${keyDefinition.key}` as StorageKey; +} + +export function populateOptionsWithDefault( + options: Partial>, +): StateUpdateOptions { + const { combineLatestWith = null, shouldUpdate = () => true, msTimeout = 1000 } = options; + return { + combineLatestWith: combineLatestWith, + shouldUpdate: shouldUpdate, + msTimeout: msTimeout, + }; +} diff --git a/libs/state-internal/tsconfig.eslint.json b/libs/state-internal/tsconfig.eslint.json new file mode 100644 index 00000000000..3daf120441a --- /dev/null +++ b/libs/state-internal/tsconfig.eslint.json @@ -0,0 +1,6 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": ["src/**/*.ts", "src/**/*.js"], + "exclude": ["**/build", "**/dist"] +} diff --git a/libs/state-internal/tsconfig.json b/libs/state-internal/tsconfig.json new file mode 100644 index 00000000000..62ebbd94647 --- /dev/null +++ b/libs/state-internal/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/state-internal/tsconfig.lib.json b/libs/state-internal/tsconfig.lib.json new file mode 100644 index 00000000000..9cbf6736007 --- /dev/null +++ b/libs/state-internal/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.js", "src/**/*.spec.ts"] +} diff --git a/libs/state-internal/tsconfig.spec.json b/libs/state-internal/tsconfig.spec.json new file mode 100644 index 00000000000..1275f148a18 --- /dev/null +++ b/libs/state-internal/tsconfig.spec.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "moduleResolution": "node10", + "types": ["jest", "node"] + }, + "include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"] +} diff --git a/libs/state-test-utils/src/fake-state-provider.ts b/libs/state-test-utils/src/fake-state-provider.ts index 47b1ee3dd0f..35e868ab04c 100644 --- a/libs/state-test-utils/src/fake-state-provider.ts +++ b/libs/state-test-utils/src/fake-state-provider.ts @@ -17,22 +17,22 @@ import { DeriveDefinition, DerivedStateProvider, UserKeyDefinition, - ActiveUserAccessor, } from "@bitwarden/state"; +import { UserId } from "@bitwarden/user-core"; + import { FakeActiveUserState, FakeDerivedState, FakeGlobalState, FakeSingleUserState, -} from "@bitwarden/state-test-utils"; -import { UserId } from "@bitwarden/user-core"; +} from "./fake-state"; export interface MinimalAccountService { activeUserId: UserId | null; activeAccount$: Observable<{ id: UserId } | null>; } -export class FakeActiveUserAccessor implements MinimalAccountService, ActiveUserAccessor { +export class FakeActiveUserAccessor implements MinimalAccountService { private _subject: BehaviorSubject; constructor(startingUser: UserId | null) { diff --git a/libs/state/src/core/active-user.accessor.ts b/libs/state/src/core/active-user.accessor.ts deleted file mode 100644 index 8ee2d53a93f..00000000000 --- a/libs/state/src/core/active-user.accessor.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Observable } from "rxjs"; - -import { UserId } from "@bitwarden/user-core"; - -export abstract class ActiveUserAccessor { - /** - * Returns a stream of the current active user for the application. The stream either emits the user id for that account - * or returns null if there is no current active user. - */ - abstract activeUserId$: Observable; -} diff --git a/libs/state/src/core/global-state.ts b/libs/state/src/core/global-state.ts index b2ac634df24..2a7cd938a27 100644 --- a/libs/state/src/core/global-state.ts +++ b/libs/state/src/core/global-state.ts @@ -19,7 +19,7 @@ export interface GlobalState { */ update: ( configureState: (state: T | null, dependency: TCombine) => T | null, - options?: StateUpdateOptions, + options?: Partial>, ) => Promise; /** diff --git a/libs/state/src/core/implementations/util.ts b/libs/state/src/core/implementations/util.ts deleted file mode 100644 index 14b11f6b553..00000000000 --- a/libs/state/src/core/implementations/util.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Jsonify } from "type-fest"; - -import { AbstractStorageService } from "@bitwarden/storage-core"; - -export async function getStoredValue( - key: string, - storage: AbstractStorageService, - deserializer: (jsonValue: Jsonify) => T | null, -) { - if (storage.valuesRequireDeserialization) { - const jsonValue = await storage.get>(key); - return deserializer(jsonValue); - } else { - const value = await storage.get(key); - return value ?? null; - } -} diff --git a/libs/state/src/core/index.ts b/libs/state/src/core/index.ts index 6cf92b7ecc5..64b1325eed3 100644 --- a/libs/state/src/core/index.ts +++ b/libs/state/src/core/index.ts @@ -6,14 +6,12 @@ export { StateProvider } from "./state.provider"; export { GlobalStateProvider } from "./global-state.provider"; export { ActiveUserState, SingleUserState, CombinedState } from "./user-state"; export { ActiveUserStateProvider, SingleUserStateProvider } from "./user-state.provider"; -export { KeyDefinition, KeyDefinitionOptions } from "./key-definition"; +export { KeyDefinition, KeyDefinitionOptions, DebugOptions } from "./key-definition"; export { StateUpdateOptions } from "./state-update-options"; -export { UserKeyDefinitionOptions, UserKeyDefinition } from "./user-key-definition"; +export { UserKeyDefinitionOptions, UserKeyDefinition, ClearEvent } from "./user-key-definition"; export { StateEventRunnerService } from "./state-event-runner.service"; export { activeMarker } from "./user-state"; export { StateDefinition } from "./state-definition"; -export { ActiveUserAccessor } from "./active-user.accessor"; export * from "./state-definitions"; -export * from "./implementations"; export * from "./state-event-registrar.service"; diff --git a/libs/state/src/core/key-definition.ts b/libs/state/src/core/key-definition.ts index be52368ac83..c0f2bb57de2 100644 --- a/libs/state/src/core/key-definition.ts +++ b/libs/state/src/core/key-definition.ts @@ -4,8 +4,6 @@ import { Jsonify } from "type-fest"; import { array, record } from "@bitwarden/serialization"; -import { StorageKey } from "../types/state"; - import { StateDefinition } from "./state-definition"; export type DebugOptions = { @@ -172,12 +170,3 @@ export class KeyDefinition { return `${this.stateDefinition.name} > ${this.key}`; } } - -/** - * Creates a {@link StorageKey} - * @param keyDefinition The key definition of which data the key should point to. - * @returns A key that is ready to be used in a storage service to get data. - */ -export function globalKeyBuilder(keyDefinition: KeyDefinition): StorageKey { - return `global_${keyDefinition.stateDefinition.name}_${keyDefinition.key}` as StorageKey; -} diff --git a/libs/state/src/core/state-event-registrar.service.ts b/libs/state/src/core/state-event-registrar.service.ts index 5e21fe1fcf7..1d99ee049c9 100644 --- a/libs/state/src/core/state-event-registrar.service.ts +++ b/libs/state/src/core/state-event-registrar.service.ts @@ -1,76 +1,5 @@ -import { PossibleLocation, StorageServiceProvider } from "@bitwarden/storage-core"; +import { UserKeyDefinition } from "./user-key-definition"; -import { GlobalState } from "./global-state"; -import { GlobalStateProvider } from "./global-state.provider"; -import { KeyDefinition } from "./key-definition"; -import { CLEAR_EVENT_DISK } from "./state-definitions"; -import { ClearEvent, UserKeyDefinition } from "./user-key-definition"; - -export type StateEventInfo = { - state: string; - key: string; - location: PossibleLocation; -}; - -export const STATE_LOCK_EVENT = KeyDefinition.array(CLEAR_EVENT_DISK, "lock", { - deserializer: (e) => e, -}); - -export const STATE_LOGOUT_EVENT = KeyDefinition.array(CLEAR_EVENT_DISK, "logout", { - deserializer: (e) => e, -}); - -export class StateEventRegistrarService { - private readonly stateEventStateMap: { [Prop in ClearEvent]: GlobalState }; - - constructor( - globalStateProvider: GlobalStateProvider, - private storageServiceProvider: StorageServiceProvider, - ) { - this.stateEventStateMap = { - lock: globalStateProvider.get(STATE_LOCK_EVENT), - logout: globalStateProvider.get(STATE_LOGOUT_EVENT), - }; - } - - async registerEvents(keyDefinition: UserKeyDefinition) { - for (const clearEvent of keyDefinition.clearOn) { - const eventState = this.stateEventStateMap[clearEvent]; - // Determine the storage location for this - const [storageLocation] = this.storageServiceProvider.get( - keyDefinition.stateDefinition.defaultStorageLocation, - keyDefinition.stateDefinition.storageLocationOverrides, - ); - - const newEvent: StateEventInfo = { - state: keyDefinition.stateDefinition.name, - key: keyDefinition.key, - location: storageLocation, - }; - - // Only update the event state if the existing list doesn't have a matching entry - await eventState.update( - (existingTickets) => { - existingTickets ??= []; - existingTickets.push(newEvent); - return existingTickets; - }, - { - shouldUpdate: (currentTickets) => { - return ( - // If the current tickets are null, then it will for sure be added - currentTickets == null || - // If an existing match couldn't be found, we also need to add one - currentTickets.findIndex( - (e) => - e.state === newEvent.state && - e.key === newEvent.key && - e.location === newEvent.location, - ) === -1 - ); - }, - }, - ); - } - } +export abstract class StateEventRegistrarService { + abstract registerEvents(keyDefinition: UserKeyDefinition): Promise; } diff --git a/libs/state/src/core/state-event-runner.service.ts b/libs/state/src/core/state-event-runner.service.ts index 046816a2ce9..37ac0a3240a 100644 --- a/libs/state/src/core/state-event-runner.service.ts +++ b/libs/state/src/core/state-event-runner.service.ts @@ -1,82 +1,7 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { firstValueFrom } from "rxjs"; - -import { StorageServiceProvider, StorageLocation } from "@bitwarden/storage-core"; import { UserId } from "@bitwarden/user-core"; -import { GlobalState } from "./global-state"; -import { GlobalStateProvider } from "./global-state.provider"; -import { StateDefinition } from "./state-definition"; -import { - STATE_LOCK_EVENT, - STATE_LOGOUT_EVENT, - StateEventInfo, -} from "./state-event-registrar.service"; -import { ClearEvent, UserKeyDefinition } from "./user-key-definition"; +import { ClearEvent } from "./user-key-definition"; -export class StateEventRunnerService { - private readonly stateEventMap: { [Prop in ClearEvent]: GlobalState }; - - constructor( - globalStateProvider: GlobalStateProvider, - private storageServiceProvider: StorageServiceProvider, - ) { - this.stateEventMap = { - lock: globalStateProvider.get(STATE_LOCK_EVENT), - logout: globalStateProvider.get(STATE_LOGOUT_EVENT), - }; - } - - async handleEvent(event: ClearEvent, userId: UserId) { - let tickets = await firstValueFrom(this.stateEventMap[event].state$); - tickets ??= []; - - const failures: string[] = []; - - for (const ticket of tickets) { - try { - const [, service] = this.storageServiceProvider.get( - ticket.location, - {}, // The storage location is already the computed storage location for this client - ); - - const ticketStorageKey = this.storageKeyFor(userId, ticket); - - // Evaluate current value so we can avoid writing to state if we don't need to - const currentValue = await service.get(ticketStorageKey); - if (currentValue != null) { - await service.remove(ticketStorageKey); - } - } catch (err: unknown) { - let errorMessage = "Unknown Error"; - if (typeof err === "object" && "message" in err && typeof err.message === "string") { - errorMessage = err.message; - } - - failures.push( - `${errorMessage} in ${ticket.state} > ${ticket.key} located ${ticket.location}`, - ); - } - } - - if (failures.length > 0) { - // Throw aggregated error - throw new Error( - `One or more errors occurred while handling event '${event}' for user ${userId}.\n${failures.join("\n")}`, - ); - } - } - - private storageKeyFor(userId: UserId, ticket: StateEventInfo) { - const userKey = new UserKeyDefinition( - new StateDefinition(ticket.state, ticket.location as unknown as StorageLocation), - ticket.key, - { - deserializer: (v) => v, - clearOn: [], - }, - ); - return userKey.buildKey(userId); - } +export abstract class StateEventRunnerService { + abstract handleEvent(event: ClearEvent, userId: UserId): Promise; } diff --git a/libs/state/src/core/state-update-options.ts b/libs/state/src/core/state-update-options.ts index 1a70dd2731e..3733ea55e30 100644 --- a/libs/state/src/core/state-update-options.ts +++ b/libs/state/src/core/state-update-options.ts @@ -2,27 +2,8 @@ // @ts-strict-ignore import { Observable } from "rxjs"; -export const DEFAULT_OPTIONS = { - shouldUpdate: () => true, - combineLatestWith: null as Observable, - msTimeout: 1000, +export type StateUpdateOptions = { + readonly shouldUpdate: (state: T, dependency: TCombine) => boolean; + readonly combineLatestWith: Observable | null; + readonly msTimeout: number; }; - -type DefinitelyTypedDefault = Omit< - typeof DEFAULT_OPTIONS, - "shouldUpdate" | "combineLatestWith" -> & { - shouldUpdate: (state: T, dependency: TCombine) => boolean; - combineLatestWith?: Observable; -}; - -export type StateUpdateOptions = Partial>; - -export function populateOptionsWithDefault( - options: StateUpdateOptions, -): StateUpdateOptions { - return { - ...(DEFAULT_OPTIONS as StateUpdateOptions), - ...options, - }; -} diff --git a/libs/state/src/core/user-state.ts b/libs/state/src/core/user-state.ts index 43c989ca22c..8607515127c 100644 --- a/libs/state/src/core/user-state.ts +++ b/libs/state/src/core/user-state.ts @@ -39,7 +39,7 @@ export interface ActiveUserState extends UserState { */ readonly update: ( configureState: (state: T | null, dependencies: TCombine) => T | null, - options?: StateUpdateOptions, + options?: Partial>, ) => Promise<[UserId, T | null]>; } @@ -59,6 +59,6 @@ export interface SingleUserState extends UserState { */ readonly update: ( configureState: (state: T | null, dependencies: TCombine) => T | null, - options?: StateUpdateOptions, + options?: Partial>, ) => Promise; } diff --git a/libs/state/src/legacy/index.ts b/libs/state/src/legacy/index.ts index d25d4d4616a..e426f25d149 100644 --- a/libs/state/src/legacy/index.ts +++ b/libs/state/src/legacy/index.ts @@ -1,2 +1 @@ -export { StateService } from "./state.service"; -export { DefaultStateService } from "./default-state.service"; +export { StateService, RequiredUserId } from "./state.service"; diff --git a/package-lock.json b/package-lock.json index de84620d5ef..5f4aedffd1f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -402,6 +402,10 @@ "version": "0.0.1", "license": "GPL-3.0" }, + "libs/state-internal": { + "version": "0.0.1", + "license": "GPL-3.0" + }, "libs/state-test-utils": { "name": "@bitwarden/state-test-utils", "version": "0.0.1", @@ -4709,6 +4713,10 @@ "resolved": "libs/state", "link": true }, + "node_modules/@bitwarden/state-internal": { + "resolved": "libs/state-internal", + "link": true + }, "node_modules/@bitwarden/state-test-utils": { "resolved": "libs/state-test-utils", "link": true diff --git a/tsconfig.base.json b/tsconfig.base.json index 8053bfe6c63..3d38f0f8210 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -52,6 +52,7 @@ "@bitwarden/send-ui": ["./libs/tools/send/send-ui/src"], "@bitwarden/serialization": ["libs/serialization/src/index.ts"], "@bitwarden/state": ["libs/state/src/index.ts"], + "@bitwarden/state-internal": ["libs/state-internal/src/index.ts"], "@bitwarden/state-test-utils": ["libs/state-test-utils/src/index.ts"], "@bitwarden/storage-core": ["libs/storage-core/src/index.ts"], "@bitwarden/storage-test-utils": ["libs/storage-test-utils/src/index.ts"], From 0736e61ad840d710a34f8414699fe7dbe20c8f9f Mon Sep 17 00:00:00 2001 From: Brandon Treston Date: Mon, 25 Aug 2025 15:37:09 -0400 Subject: [PATCH 037/167] fix icon spacing (#16147) --- .../admin-console/organizations/members/members.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/app/admin-console/organizations/members/members.component.html b/apps/web/src/app/admin-console/organizations/members/members.component.html index 7e0aa465bf3..cc475009700 100644 --- a/apps/web/src/app/admin-console/organizations/members/members.component.html +++ b/apps/web/src/app/admin-console/organizations/members/members.component.html @@ -326,7 +326,7 @@ - + Date: Mon, 25 Aug 2025 16:24:50 -0400 Subject: [PATCH 038/167] fix permission order (#16148) --- .../components/access-selector/access-selector.models.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.models.ts b/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.models.ts index 884483d32b0..45691ae98d6 100644 --- a/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.models.ts +++ b/apps/web/src/app/admin-console/organizations/shared/components/access-selector/access-selector.models.ts @@ -87,10 +87,10 @@ export type Permission = { export const getPermissionList = (): Permission[] => { const permissions = [ - { perm: CollectionPermission.View, labelId: "viewItems" }, { perm: CollectionPermission.ViewExceptPass, labelId: "viewItemsHidePass" }, - { perm: CollectionPermission.Edit, labelId: "editItems" }, + { perm: CollectionPermission.View, labelId: "viewItems" }, { perm: CollectionPermission.EditExceptPass, labelId: "editItemsHidePass" }, + { perm: CollectionPermission.Edit, labelId: "editItems" }, { perm: CollectionPermission.Manage, labelId: "manageCollection" }, ]; From ae2259db2f221ecccee30fb7441fc62545d1ed91 Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Mon, 25 Aug 2025 14:07:22 -0700 Subject: [PATCH 039/167] [PM-17723] - [Web | Browser | Desktop] Cannot search for port in vault login item URI (#15962) * add port search in uriExtractor * revert to original check --- .../src/vault/services/search.service.ts | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/libs/common/src/vault/services/search.service.ts b/libs/common/src/vault/services/search.service.ts index cb6ac4a0ed4..041f978f4ea 100644 --- a/libs/common/src/vault/services/search.service.ts +++ b/libs/common/src/vault/services/search.service.ts @@ -426,11 +426,30 @@ export class SearchService implements SearchServiceAbstraction { if (u.uri == null || u.uri === "") { return; } - if (u.hostname != null) { - uris.push(u.hostname); - return; - } + + // Match ports + const portMatch = u.uri.match(/:(\d+)(?:[/?#]|$)/); + const port = portMatch?.[1]; + let uri = u.uri; + + if (u.hostname !== null) { + uris.push(u.hostname); + if (port) { + uris.push(`${u.hostname}:${port}`); + uris.push(port); + } + return; + } else { + const slash = uri.indexOf("/"); + const hostPart = slash > -1 ? uri.substring(0, slash) : uri; + uris.push(hostPart); + if (port) { + uris.push(`${hostPart}`); + uris.push(port); + } + } + if (u.match !== UriMatchStrategy.RegularExpression) { const protocolIndex = uri.indexOf("://"); if (protocolIndex > -1) { From e10d13faa81a9380238f67e9a1eb5e9aa1c62f0a Mon Sep 17 00:00:00 2001 From: Shane Melton Date: Mon, 25 Aug 2025 14:50:54 -0700 Subject: [PATCH 040/167] [PM-22695] Remove unused vault service (#16134) * [PM-22695] Remove obsolete browser vault filter service * [PM-22695] Remove obsolete vault browser state service --- .../browser/src/background/main.background.ts | 15 ---- apps/browser/src/popup/app.component.ts | 27 ------ .../src/popup/services/services.module.ts | 30 +------ .../vault-browser-state.service.spec.ts | 87 ------------------ .../services/vault-browser-state.service.ts | 74 ---------------- .../vault/services/vault-filter.service.ts | 88 ------------------- 6 files changed, 1 insertion(+), 320 deletions(-) delete mode 100644 apps/browser/src/vault/services/vault-browser-state.service.spec.ts delete mode 100644 apps/browser/src/vault/services/vault-browser-state.service.ts delete mode 100644 apps/browser/src/vault/services/vault-filter.service.ts diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 2f87e347410..c2c62625bb6 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -299,7 +299,6 @@ import { OffscreenStorageService } from "../platform/storage/offscreen-storage.s import { SyncServiceListener } from "../platform/sync/sync-service.listener"; import { BrowserSystemNotificationService } from "../platform/system-notifications/browser-system-notification.service"; import { fromChromeRuntimeMessaging } from "../platform/utils/from-chrome-runtime-messaging"; -import { VaultFilterService } from "../vault/services/vault-filter.service"; import CommandsBackground from "./commands.background"; import IdleBackground from "./idle.background"; @@ -364,7 +363,6 @@ export default class MainBackground { providerService: ProviderServiceAbstraction; keyConnectorService: KeyConnectorServiceAbstraction; userVerificationService: UserVerificationServiceAbstraction; - vaultFilterService: VaultFilterService; usernameGenerationService: UsernameGenerationServiceAbstraction; encryptService: EncryptService; folderApiService: FolderApiServiceAbstraction; @@ -919,18 +917,6 @@ export default class MainBackground { this.biometricsService, ); - this.vaultFilterService = new VaultFilterService( - this.organizationService, - this.folderService, - this.cipherService, - this.collectionService, - this.policyService, - this.stateProvider, - this.accountService, - this.configService, - this.i18nService, - ); - this.vaultSettingsService = new VaultSettingsService( this.stateProvider, this.restrictedItemTypesService, @@ -1600,7 +1586,6 @@ export default class MainBackground { this.cipherService.clear(userBeingLoggedOut), this.folderService.clear(userBeingLoggedOut), this.vaultTimeoutSettingsService.clear(userBeingLoggedOut), - this.vaultFilterService.clear(), this.biometricStateService.logout(userBeingLoggedOut), this.popupViewCacheBackgroundService.clearState(), /* We intentionally do not clear: diff --git a/apps/browser/src/popup/app.component.ts b/apps/browser/src/popup/app.component.ts index bd7b41b6e5f..ee75dbaf7af 100644 --- a/apps/browser/src/popup/app.component.ts +++ b/apps/browser/src/popup/app.component.ts @@ -49,7 +49,6 @@ import { BiometricsService, BiometricStateService, KeyService } from "@bitwarden import { PopupCompactModeService } from "../platform/popup/layout/popup-compact-mode.service"; import { PopupSizeService } from "../platform/popup/layout/popup-size.service"; import { initPopupClosedListener } from "../platform/services/popup-view-cache-background.service"; -import { VaultBrowserStateService } from "../vault/services/vault-browser-state.service"; import { routerTransition } from "./app-routing.animations"; import { DesktopSyncVerificationDialogComponent } from "./components/desktop-sync-verification-dialog.component"; @@ -103,7 +102,6 @@ export class AppComponent implements OnInit, OnDestroy { private i18nService: I18nService, private router: Router, private readonly tokenService: TokenService, - private vaultBrowserStateService: VaultBrowserStateService, private cipherService: CipherService, private changeDetectorRef: ChangeDetectorRef, private ngZone: NgZone, @@ -135,10 +133,6 @@ export class AppComponent implements OnInit, OnDestroy { this.compactModeService.init(); await this.popupSizeService.setHeight(); - // Component states must not persist between closing and reopening the popup, otherwise they become dead objects - // Clear them aggressively to make sure this doesn't occur - await this.clearComponentStates(); - this.accountService.activeAccount$.pipe(takeUntil(this.destroy$)).subscribe((account) => { this.activeUserId = account?.id; }); @@ -249,13 +243,6 @@ export class AppComponent implements OnInit, OnDestroy { this.router.events.pipe(takeUntil(this.destroy$)).subscribe(async (event) => { if (event instanceof NavigationEnd) { const url = event.urlAfterRedirects || event.url || ""; - if ( - url.startsWith("/tabs/") && - (window as any).previousPopupUrl != null && - (window as any).previousPopupUrl.startsWith("/tabs/") - ) { - await this.clearComponentStates(); - } if (url.startsWith("/tabs/")) { await this.cipherService.setAddEditCipherInfo(null, this.activeUserId); } @@ -320,20 +307,6 @@ export class AppComponent implements OnInit, OnDestroy { return firstValueFrom(dialogRef.closed); } - private async clearComponentStates() { - if (this.activeUserId == null) { - return; - } - if (!(await firstValueFrom(this.tokenService.hasAccessToken$(this.activeUserId)))) { - return; - } - - await Promise.all([ - this.vaultBrowserStateService.setBrowserGroupingsComponentState(null), - this.vaultBrowserStateService.setBrowserVaultItemsComponentState(null), - ]); - } - // Displaying toasts isn't super useful on the popup due to the reloads we do. // However, it is visible for a moment on the FF sidebar logout. private async displayLogoutReason(logoutReason: LogoutReason) { diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index d8b4b1d600f..aaf85389f9c 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -39,7 +39,6 @@ import { import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { DefaultOrganizationService } from "@bitwarden/common/admin-console/services/organization/default-organization.service"; import { AccountService, AccountService as AccountServiceAbstraction, @@ -112,10 +111,7 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s import { InternalSendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction"; -import { - FolderService as FolderServiceAbstraction, - InternalFolderService, -} from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; +import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/vault/abstractions/totp.service"; import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service"; import { TotpService } from "@bitwarden/common/vault/services/totp.service"; @@ -186,8 +182,6 @@ import { BrowserSystemNotificationService } from "../../platform/system-notifica import { fromChromeRuntimeMessaging } from "../../platform/utils/from-chrome-runtime-messaging"; import { FilePopoutUtilsService } from "../../tools/popup/services/file-popout-utils.service"; import { Fido2UserVerificationService } from "../../vault/services/fido2-user-verification.service"; -import { VaultBrowserStateService } from "../../vault/services/vault-browser-state.service"; -import { VaultFilterService } from "../../vault/services/vault-filter.service"; import { ExtensionAnonLayoutWrapperDataService } from "../components/extension-anon-layout-wrapper/extension-anon-layout-wrapper-data.service"; import { DebounceNavigationService } from "./debounce-navigation.service"; @@ -402,21 +396,6 @@ const safeProviders: SafeProvider[] = [ useClass: ForegroundVaultTimeoutService, deps: [MessagingServiceAbstraction], }), - safeProvider({ - provide: VaultFilterService, - useClass: VaultFilterService, - deps: [ - DefaultOrganizationService, - FolderServiceAbstraction, - CipherService, - CollectionService, - PolicyService, - StateProvider, - AccountServiceAbstraction, - ConfigService, - I18nServiceAbstraction, - ], - }), safeProvider({ provide: SECURE_STORAGE, useExisting: AbstractStorageService, // Secure storage is not available in the browser, so we use normal storage instead and warn users when it is used. @@ -454,13 +433,6 @@ const safeProviders: SafeProvider[] = [ provide: OBSERVABLE_DISK_STORAGE, useExisting: AbstractStorageService, }), - safeProvider({ - provide: VaultBrowserStateService, - useFactory: (stateProvider: StateProvider) => { - return new VaultBrowserStateService(stateProvider); - }, - deps: [StateProvider], - }), safeProvider({ provide: FileDownloadService, useClass: BrowserFileDownloadService, diff --git a/apps/browser/src/vault/services/vault-browser-state.service.spec.ts b/apps/browser/src/vault/services/vault-browser-state.service.spec.ts deleted file mode 100644 index b9369aa826b..00000000000 --- a/apps/browser/src/vault/services/vault-browser-state.service.spec.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { - FakeAccountService, - mockAccountServiceWith, -} from "@bitwarden/common/../spec/fake-account-service"; -import { FakeStateProvider } from "@bitwarden/common/../spec/fake-state-provider"; -import { Jsonify } from "type-fest"; - -import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { UserId } from "@bitwarden/common/types/guid"; -import { CipherType } from "@bitwarden/common/vault/enums"; - -import { BrowserComponentState } from "../../models/browserComponentState"; -import { BrowserGroupingsComponentState } from "../../models/browserGroupingsComponentState"; - -import { - VAULT_BROWSER_COMPONENT, - VAULT_BROWSER_GROUPINGS_COMPONENT, - VaultBrowserStateService, -} from "./vault-browser-state.service"; - -describe("Vault Browser State Service", () => { - let stateProvider: FakeStateProvider; - - let accountService: FakeAccountService; - let stateService: VaultBrowserStateService; - const mockUserId = Utils.newGuid() as UserId; - - beforeEach(() => { - accountService = mockAccountServiceWith(mockUserId); - stateProvider = new FakeStateProvider(accountService); - - stateService = new VaultBrowserStateService(stateProvider); - }); - - describe("getBrowserGroupingsComponentState", () => { - it("should return a BrowserGroupingsComponentState", async () => { - await stateService.setBrowserGroupingsComponentState(new BrowserGroupingsComponentState()); - - const actual = await stateService.getBrowserGroupingsComponentState(); - - expect(actual).toBeInstanceOf(BrowserGroupingsComponentState); - }); - - it("should deserialize BrowserGroupingsComponentState", () => { - const sut = VAULT_BROWSER_GROUPINGS_COMPONENT; - - const expectedState = { - deletedCount: 0, - collectionCounts: new Map(), - folderCounts: new Map(), - typeCounts: new Map(), - }; - - const result = sut.deserializer( - JSON.parse(JSON.stringify(expectedState)) as Jsonify, - ); - - expect(result).toEqual(expectedState); - }); - }); - - describe("getBrowserVaultItemsComponentState", () => { - it("should deserialize BrowserComponentState", () => { - const sut = VAULT_BROWSER_COMPONENT; - - const expectedState = { - scrollY: 0, - searchText: "test", - }; - - const result = sut.deserializer(JSON.parse(JSON.stringify(expectedState))); - - expect(result).toEqual(expectedState); - }); - - it("should return a BrowserComponentState", async () => { - const componentState = new BrowserComponentState(); - componentState.scrollY = 0; - componentState.searchText = "test"; - - await stateService.setBrowserVaultItemsComponentState(componentState); - - const actual = await stateService.getBrowserVaultItemsComponentState(); - expect(actual).toStrictEqual(componentState); - }); - }); -}); diff --git a/apps/browser/src/vault/services/vault-browser-state.service.ts b/apps/browser/src/vault/services/vault-browser-state.service.ts deleted file mode 100644 index 58ce717bf1e..00000000000 --- a/apps/browser/src/vault/services/vault-browser-state.service.ts +++ /dev/null @@ -1,74 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { Observable, firstValueFrom } from "rxjs"; -import { Jsonify } from "type-fest"; - -import { - ActiveUserState, - StateProvider, - UserKeyDefinition, - VAULT_BROWSER_MEMORY, -} from "@bitwarden/common/platform/state"; - -import { BrowserComponentState } from "../../models/browserComponentState"; -import { BrowserGroupingsComponentState } from "../../models/browserGroupingsComponentState"; - -export const VAULT_BROWSER_GROUPINGS_COMPONENT = - new UserKeyDefinition( - VAULT_BROWSER_MEMORY, - "vault_browser_groupings_component", - { - deserializer: (obj: Jsonify) => - BrowserGroupingsComponentState.fromJSON(obj), - clearOn: ["logout", "lock"], - }, - ); - -export const VAULT_BROWSER_COMPONENT = new UserKeyDefinition( - VAULT_BROWSER_MEMORY, - "vault_browser_component", - { - deserializer: (obj: Jsonify) => BrowserComponentState.fromJSON(obj), - clearOn: ["logout", "lock"], - }, -); - -export class VaultBrowserStateService { - vaultBrowserGroupingsComponentState$: Observable; - vaultBrowserComponentState$: Observable; - - private activeUserVaultBrowserGroupingsComponentState: ActiveUserState; - private activeUserVaultBrowserComponentState: ActiveUserState; - - constructor(protected stateProvider: StateProvider) { - this.activeUserVaultBrowserGroupingsComponentState = this.stateProvider.getActive( - VAULT_BROWSER_GROUPINGS_COMPONENT, - ); - this.activeUserVaultBrowserComponentState = - this.stateProvider.getActive(VAULT_BROWSER_COMPONENT); - - this.vaultBrowserGroupingsComponentState$ = - this.activeUserVaultBrowserGroupingsComponentState.state$; - this.vaultBrowserComponentState$ = this.activeUserVaultBrowserComponentState.state$; - } - - async getBrowserGroupingsComponentState(): Promise { - return await firstValueFrom(this.vaultBrowserGroupingsComponentState$); - } - - async setBrowserGroupingsComponentState(value: BrowserGroupingsComponentState): Promise { - await this.activeUserVaultBrowserGroupingsComponentState.update(() => value, { - shouldUpdate: (current) => !(current == null && value == null), - }); - } - - async getBrowserVaultItemsComponentState(): Promise { - return await firstValueFrom(this.vaultBrowserComponentState$); - } - - async setBrowserVaultItemsComponentState(value: BrowserComponentState): Promise { - await this.activeUserVaultBrowserComponentState.update(() => value, { - shouldUpdate: (current) => !(current == null && value == null), - }); - } -} diff --git a/apps/browser/src/vault/services/vault-filter.service.ts b/apps/browser/src/vault/services/vault-filter.service.ts deleted file mode 100644 index f33e8e1c130..00000000000 --- a/apps/browser/src/vault/services/vault-filter.service.ts +++ /dev/null @@ -1,88 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { CollectionService } from "@bitwarden/admin-console/common"; -import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model"; -import { VaultFilterService as BaseVaultFilterService } from "@bitwarden/angular/vault/vault-filter/services/vault-filter.service"; -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { StateProvider } from "@bitwarden/common/platform/state"; -import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; - -export class VaultFilterService extends BaseVaultFilterService { - vaultFilter: VaultFilter = new VaultFilter(); - - allVaults = "allVaults"; - myVault = "myVault"; - - constructor( - organizationService: OrganizationService, - folderService: FolderService, - cipherService: CipherService, - collectionService: CollectionService, - policyService: PolicyService, - stateProvider: StateProvider, - accountService: AccountService, - configService: ConfigService, - i18nService: I18nService, - ) { - super( - organizationService, - folderService, - cipherService, - collectionService, - policyService, - stateProvider, - accountService, - configService, - i18nService, - ); - this.vaultFilter.myVaultOnly = false; - this.vaultFilter.selectedOrganizationId = null; - - accountService.activeAccount$.subscribe((account) => { - this.setVaultFilter(this.allVaults); - }); - } - - getVaultFilter() { - return this.vaultFilter; - } - - setVaultFilter(filter: string) { - if (filter === this.allVaults) { - this.vaultFilter.myVaultOnly = false; - this.vaultFilter.selectedOrganizationId = null; - } else if (filter === this.myVault) { - this.vaultFilter.myVaultOnly = true; - this.vaultFilter.selectedOrganizationId = null; - } else { - this.vaultFilter.myVaultOnly = false; - this.vaultFilter.selectedOrganizationId = filter; - } - } - - clear() { - this.setVaultFilter(this.allVaults); - } - - filterCipherForSelectedVault(cipher: CipherView) { - if (!this.vaultFilter.selectedOrganizationId && !this.vaultFilter.myVaultOnly) { - return false; - } - if (this.vaultFilter.selectedOrganizationId) { - if (cipher.organizationId === this.vaultFilter.selectedOrganizationId) { - return false; - } - } else if (this.vaultFilter.myVaultOnly) { - if (!cipher.organizationId) { - return false; - } - } - return true; - } -} From 9ed69ef4b81954b41511b22b5083f6286807a8c6 Mon Sep 17 00:00:00 2001 From: Jordan Aasen <166539328+jaasen-livefront@users.noreply.github.com> Date: Mon, 25 Aug 2025 15:48:00 -0700 Subject: [PATCH 041/167] [PM-24304][PM-24305] - [Defect] Some fields are not disabled when editing an item from My Vault (#15982) * disable all remaining form fields for editing personally owned My Items * fix failing tests * ensure collection field is also properly disabled * clean up logic * fix failing test * fix test * refactor variable to avoid using `is` prefix * directly reference parent form for status rather than subscribe to it * refactor subscription for form status changes * use observable as an Output * disable attachment button on desktop vault when the form * disable custom field components when custom fields already exist and parent form is disabled * disable attachments button in the browser when the edit form is disabled * grab icon button instance for disabled state --------- Co-authored-by: Nick Krantz --- .../open-attachments.component.html | 7 ++- .../open-attachments.component.spec.ts | 23 +++++++ .../open-attachments.component.ts | 9 +++ .../vault/app/vault/vault-v2.component.html | 8 ++- .../src/vault/app/vault/vault-v2.component.ts | 7 +++ .../vault-item-dialog.component.html | 8 ++- .../vault-item-dialog.component.ts | 6 ++ .../src/cipher-form/cipher-form-container.ts | 6 +- .../additional-options-section.component.html | 2 +- ...ditional-options-section.component.spec.ts | 3 +- .../additional-options-section.component.ts | 5 ++ .../autofill-options.component.spec.ts | 3 +- .../autofill-options.component.ts | 17 +++++- .../components/cipher-form.component.ts | 7 ++- .../custom-fields.component.html | 5 +- .../custom-fields.component.spec.ts | 60 ++++++++++++++++++- .../custom-fields/custom-fields.component.ts | 7 +++ .../item-details-section.component.html | 1 + .../item-details-section.component.ts | 49 +++++++++------ .../login-details-section.component.spec.ts | 2 + .../login-details-section.component.ts | 17 +++++- .../sshkey-section.component.ts | 8 ++- 22 files changed, 224 insertions(+), 36 deletions(-) diff --git a/apps/browser/src/vault/popup/components/vault-v2/attachments/open-attachments/open-attachments.component.html b/apps/browser/src/vault/popup/components/vault-v2/attachments/open-attachments/open-attachments.component.html index 6345c3ea4e1..2650345e94b 100644 --- a/apps/browser/src/vault/popup/components/vault-v2/attachments/open-attachments/open-attachments.component.html +++ b/apps/browser/src/vault/popup/components/vault-v2/attachments/open-attachments/open-attachments.component.html @@ -1,5 +1,10 @@ - @@ -104,6 +105,7 @@ [label]="'reorderToggleButton' | i18n: field.value.name" (keydown)="handleKeyDown($event, field.value.name, i)" data-testid="reorder-toggle-button" + [disabled]="parentFormDisabled" *ngIf="canEdit(field.value.type)" > @@ -113,7 +115,8 @@ bitLink linkType="primary" (click)="openAddEditCustomFieldDialog()" - *ngIf="!isPartialEdit" + data-testid="add-field-button" + *ngIf="!isPartialEdit && !parentFormDisabled" > {{ "addField" | i18n }} diff --git a/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.spec.ts b/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.spec.ts index ced8763f895..1d1bcfa1ee0 100644 --- a/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.spec.ts +++ b/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.spec.ts @@ -4,6 +4,7 @@ import { DebugElement } from "@angular/core"; import { ComponentFixture, TestBed } from "@angular/core/testing"; import { By } from "@angular/platform-browser"; import { mock } from "jest-mock-extended"; +import { BehaviorSubject } from "rxjs"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -16,7 +17,12 @@ import { } from "@bitwarden/common/vault/enums"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FieldView } from "@bitwarden/common/vault/models/view/field.view"; -import { DialogRef, BitPasswordInputToggleDirective, DialogService } from "@bitwarden/components"; +import { + DialogRef, + BitPasswordInputToggleDirective, + DialogService, + BitIconButtonComponent, +} from "@bitwarden/components"; import { CipherFormConfig } from "../../abstractions/cipher-form-config.service"; import { CipherFormContainer } from "../../cipher-form-container"; @@ -39,6 +45,7 @@ describe("CustomFieldsComponent", () => { let announce: jest.Mock; let patchCipher: jest.Mock; let config: CipherFormConfig; + const formStatusChange$ = new BehaviorSubject<"disabled" | "enabled">("enabled"); beforeEach(async () => { open = jest.fn(); @@ -65,6 +72,7 @@ describe("CustomFieldsComponent", () => { registerChildForm: jest.fn(), config, getInitialCipherView: jest.fn(() => originalCipherView), + formStatusChange$, }, }, { @@ -552,4 +560,54 @@ describe("CustomFieldsComponent", () => { expect(editButtons).toHaveLength(3); }); }); + + describe("parent form disabled", () => { + beforeEach(() => { + originalCipherView!.fields = mockFieldViews; + formStatusChange$.next("disabled"); + component.ngOnInit(); + + fixture.detectChanges(); + }); + + afterEach(() => { + formStatusChange$.next("enabled"); + fixture.detectChanges(); + }); + + it("disables edit and reorder buttons", () => { + const reorderButtonQuery = By.directive(BitIconButtonComponent); + const editButtonQuery = By.directive(BitIconButtonComponent); + + let reorderButton = fixture.debugElement.query(reorderButtonQuery); + let editButton = fixture.debugElement.query(editButtonQuery); + + expect(reorderButton.componentInstance.disabled()).toBe(true); + expect(editButton.componentInstance.disabled()).toBe(true); + + formStatusChange$.next("enabled"); + fixture.detectChanges(); + + reorderButton = fixture.debugElement.query(reorderButtonQuery); + editButton = fixture.debugElement.query(editButtonQuery); + + expect(reorderButton.componentInstance.disabled()).toBe(false); + expect(editButton.componentInstance.disabled()).toBe(false); + }); + + it("hides add field button", () => { + const query = By.css('button[data-testid="add-field-button"]'); + + let addFieldButton = fixture.debugElement.query(query); + + expect(addFieldButton).toBeNull(); + + formStatusChange$.next("enabled"); + fixture.detectChanges(); + + addFieldButton = fixture.debugElement.query(query); + + expect(addFieldButton).not.toBeNull(); + }); + }); }); diff --git a/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.ts b/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.ts index c8edba6c9fd..e3612e75a1b 100644 --- a/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.ts +++ b/libs/vault/src/cipher-form/components/custom-fields/custom-fields.component.ts @@ -113,6 +113,9 @@ export class CustomFieldsComponent implements OnInit, AfterViewInit { /** Emits when a new custom field should be focused */ private focusOnNewInput$ = new Subject(); + /** Tracks the disabled status of the edit cipher form */ + protected parentFormDisabled: boolean = false; + disallowHiddenField?: boolean; destroyed$: DestroyRef; @@ -133,6 +136,10 @@ export class CustomFieldsComponent implements OnInit, AfterViewInit { // getRawValue ensures disabled fields are included this.updateCipher(this.fields.getRawValue()); }); + + this.cipherFormContainer.formStatusChange$.pipe(takeUntilDestroyed()).subscribe((status) => { + this.parentFormDisabled = status === "disabled"; + }); } /** Fields form array, referenced via a getter to avoid type-casting in multiple places */ diff --git a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.html b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.html index fc208bd9b92..9bf6dc32758 100644 --- a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.html +++ b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.html @@ -11,6 +11,7 @@ [attr.aria-checked]="itemDetailsForm.value.favorite" [label]="'favorite' | i18n" (click)="toggleFavorite()" + [disabled]="favoriteButtonDisabled" > diff --git a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.ts b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.ts index 4fd999ae601..bc5e7c43d12 100644 --- a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.ts +++ b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.ts @@ -82,6 +82,8 @@ export class ItemDetailsSectionComponent implements OnInit { protected userId: UserId; + protected favoriteButtonDisabled = false; + @Input({ required: true }) config: CipherFormConfig; @@ -241,15 +243,19 @@ export class ItemDetailsSectionComponent implements OnInit { /** * When the cipher does not belong to an organization but the user's organization * requires all ciphers to be owned by an organization, disable the entire form - * until the user selects an organization. + * until the user selects an organization. Once the organization is set, enable the form. + * Ensure to properly set the collections control state when the form is enabled. */ private setFormState() { if (this.config.originalCipher && !this.allowPersonalOwnership) { if (this.itemDetailsForm.controls.organizationId.value === null) { this.cipherFormContainer.disableFormFields(); this.itemDetailsForm.controls.organizationId.enable(); + this.favoriteButtonDisabled = true; } else { this.cipherFormContainer.enableFormFields(); + this.favoriteButtonDisabled = false; + this.setCollectionControlState(); } } } @@ -305,7 +311,6 @@ export class ItemDetailsSectionComponent implements OnInit { }); const orgId = this.itemDetailsForm.controls.organizationId.value as OrganizationId; - const organization = this.organizations.find((o) => o.id === orgId); const initializedWithCachedCipher = this.cipherFormContainer.initializedWithCachedCipher(); // Configure form for clone mode. @@ -327,9 +332,7 @@ export class ItemDetailsSectionComponent implements OnInit { await this.updateCollectionOptions(prefillCollections); - if (!organization?.canEditAllCiphers && !prefillCipher.canAssignToCollections) { - this.itemDetailsForm.controls.collectionIds.disable(); - } + this.setCollectionControlState(); if (this.partialEdit) { this.itemDetailsForm.disable(); @@ -344,22 +347,34 @@ export class ItemDetailsSectionComponent implements OnInit { c.readOnly && this.originalCipherView.collectionIds.includes(c.id as CollectionId), ); - - // When Owners/Admins access setting is turned on. - // Disable Collections Options if Owner/Admin does not have Edit/Manage permissions on item - // Disable Collections Options if Custom user does not have Edit/Manage permissions on item - if ( - (organization?.allowAdminAccessToAllCollectionItems && - (!this.originalCipherView.viewPassword || !this.originalCipherView.edit)) || - (organization?.type === OrganizationUserType.Custom && - !this.originalCipherView.viewPassword) - ) { - this.itemDetailsForm.controls.collectionIds.disable(); - } } } } + private setCollectionControlState() { + const initialCipherView = this.cipherFormContainer.getInitialCipherView(); + const orgId = this.itemDetailsForm.controls.organizationId.value as OrganizationId; + const organization = this.organizations.find((o) => o.id === orgId); + if (!organization || !initialCipherView) { + return; + } + // Disable the collection control if either of the following apply: + // 1. The organization does not allow editing all ciphers and the existing cipher cannot be assigned to + // collections + // 2. When Owners/Admins access setting is turned on. + // AND either: + // a. Disable Collections Options if Owner/Admin does not have Edit/Manage permissions on item + // b. Disable Collections Options if Custom user does not have Edit/Manage permissions on item + if ( + (!organization.canEditAllCiphers && !initialCipherView.canAssignToCollections) || + (organization.allowAdminAccessToAllCollectionItems && + (!initialCipherView.viewPassword || !initialCipherView.edit)) || + (organization.type === OrganizationUserType.Custom && !initialCipherView.viewPassword) + ) { + this.itemDetailsForm.controls.collectionIds.disable(); + } + } + /** * Updates the collection options based on the selected organization. * @param startingSelection - Optional starting selection of collectionIds to be automatically selected. diff --git a/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.spec.ts b/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.spec.ts index c5b1fc7897b..b07a50fd383 100644 --- a/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.spec.ts +++ b/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.spec.ts @@ -3,6 +3,7 @@ import { Component } from "@angular/core"; import { ComponentFixture, fakeAsync, TestBed, tick } from "@angular/core/testing"; import { By } from "@angular/platform-browser"; import { mock, MockProxy } from "jest-mock-extended"; +import { BehaviorSubject } from "rxjs"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; @@ -47,6 +48,7 @@ describe("LoginDetailsSectionComponent", () => { getInitialCipherView.mockClear(); cipherFormContainer = mock({ getInitialCipherView, + formStatusChange$: new BehaviorSubject<"enabled" | "disabled">("enabled"), website: "example.com", }); diff --git a/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.ts b/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.ts index e74d9915cdb..061a8c4abf4 100644 --- a/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.ts +++ b/libs/vault/src/cipher-form/components/login-details-section/login-details-section.component.ts @@ -1,7 +1,7 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore import { DatePipe, NgIf } from "@angular/common"; -import { Component, inject, OnInit, Optional } from "@angular/core"; +import { Component, DestroyRef, inject, OnInit, Optional } from "@angular/core"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { FormBuilder, ReactiveFormsModule } from "@angular/forms"; import { map } from "rxjs"; @@ -81,6 +81,8 @@ export class LoginDetailsSectionComponent implements OnInit { */ private existingFido2Credentials?: Fido2CredentialView[]; + private destroyRef = inject(DestroyRef); + get hasPasskey(): boolean { return this.existingFido2Credentials != null && this.existingFido2Credentials.length > 0; } @@ -148,6 +150,19 @@ export class LoginDetailsSectionComponent implements OnInit { if (this.cipherFormContainer.config.mode === "partial-edit") { this.loginDetailsForm.disable(); } + + // If the form is enabled, ensure to disable password or TOTP + // for hidden password users + this.cipherFormContainer.formStatusChange$ + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe((status) => { + if (status === "enabled") { + if (!this.viewHiddenFields) { + this.loginDetailsForm.controls.password.disable(); + this.loginDetailsForm.controls.totp.disable(); + } + } + }); } private initFromExistingCipher(existingLogin: LoginView) { diff --git a/libs/vault/src/cipher-form/components/sshkey-section/sshkey-section.component.ts b/libs/vault/src/cipher-form/components/sshkey-section/sshkey-section.component.ts index f83f93267c9..f92c4420d03 100644 --- a/libs/vault/src/cipher-form/components/sshkey-section/sshkey-section.component.ts +++ b/libs/vault/src/cipher-form/components/sshkey-section/sshkey-section.component.ts @@ -98,9 +98,13 @@ export class SshKeySectionComponent implements OnInit { // Disable the form if the cipher form container is enabled // to prevent user interaction - this.cipherFormContainer.formEnabled$ + this.cipherFormContainer.formStatusChange$ .pipe(takeUntilDestroyed(this.destroyRef)) - .subscribe(() => this.sshKeyForm.disable()); + .subscribe((status) => { + if (status === "enabled") { + this.sshKeyForm.disable(); + } + }); } /** Set form initial form values from the current cipher */ From c7b2e3f9c2b6d55f6ce6b5b78b938c7305359bdb Mon Sep 17 00:00:00 2001 From: Vince Grassia <593223+vgrassia@users.noreply.github.com> Date: Tue, 26 Aug 2025 09:09:09 +0000 Subject: [PATCH 042/167] Fix typo (#16152) --- apps/browser/store/locales/en/copy.resx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/browser/store/locales/en/copy.resx b/apps/browser/store/locales/en/copy.resx index 82e4eb1d88e..377b13e7423 100644 --- a/apps/browser/store/locales/en/copy.resx +++ b/apps/browser/store/locales/en/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. From d4e2e73d135cd73093feb8d7578f78a0ca86fb27 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Tue, 26 Aug 2025 10:09:06 +0000 Subject: [PATCH 043/167] Autosync the updated translations (#16160) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/web/src/locales/sv/messages.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/web/src/locales/sv/messages.json b/apps/web/src/locales/sv/messages.json index ff1bf0a2a1c..d050d1a18e2 100644 --- a/apps/web/src/locales/sv/messages.json +++ b/apps/web/src/locales/sv/messages.json @@ -7029,10 +7029,10 @@ "message": "Okänt objekt, du kan behöva begära tillstånd för att få tillgång till detta objekt." }, "unknownSecret": { - "message": "Unknown secret, you may need to request permission to access this secret." + "message": "Okänd hemlighet, du kan behöver begära behörighet för att komma åt denna hemlighet." }, "unknownProject": { - "message": "Unknown project, you may need to request permission to access this project." + "message": "Okänt projekt, du kan behöver begära behörighet för att komma åt detta projekt." }, "cannotSponsorSelf": { "message": "Du kan inte lösa in för det aktiva kontot. Ange en annan e-postadress." @@ -10823,7 +10823,7 @@ "message": "Dessa händelser är endast exempel och återspeglar inte verkliga händelser inom din Bitwarden-organisation." }, "viewEvents": { - "message": "View Events" + "message": "Visa händelser" }, "cannotCreateCollection": { "message": "Gratisorganisationer kan ha upp till 2 samlingar. Uppgradera till en betald plan för att lägga till fler samlingar." @@ -11125,13 +11125,13 @@ "message": "Check your Tax ID to verify the format is correct and there are no typos." }, "pendingVerification": { - "message": "Pending verification" + "message": "Väntande verifiering" }, "checkInputFormat": { "message": "Check input format for typos." }, "exampleTaxIdFormat": { - "message": "Example $CODE$ format: $EXAMPLE$", + "message": "Exempel $CODE$ format: $EXAMPLE$", "placeholders": { "code": { "content": "$1", From 00dc1702317568276517e7f1afeaef4f6f07974a Mon Sep 17 00:00:00 2001 From: aj-bw <81774843+aj-bw@users.noreply.github.com> Date: Tue, 26 Aug 2025 08:47:19 -0400 Subject: [PATCH 044/167] add shadow package, restore entrypoint functionality (#16124) --- apps/web/Dockerfile | 1 + apps/web/entrypoint.sh | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile index 7ac2223ab10..6017d60df5f 100644 --- a/apps/web/Dockerfile +++ b/apps/web/Dockerfile @@ -67,6 +67,7 @@ EXPOSE 5000 RUN apk add --no-cache curl \ icu-libs \ + shadow \ && apk add --no-cache --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community gosu # Copy app from the build stage diff --git a/apps/web/entrypoint.sh b/apps/web/entrypoint.sh index 72fd2b43b1d..96bb7773534 100644 --- a/apps/web/entrypoint.sh +++ b/apps/web/entrypoint.sh @@ -22,10 +22,11 @@ fi if [ "$(id -u)" = "0" ]; then # Create user and group - addgroup -g "$LGID" -S "$GROUPNAME" 2>/dev/null || true - adduser -u "$LUID" -G "$GROUPNAME" -S -D -H "$USERNAME" 2>/dev/null || true - mkdir -p /home/$USERNAME - chown $USERNAME:$GROUPNAME /home/$USERNAME + groupadd -o -g $LGID $GROUPNAME >/dev/null 2>&1 || + groupmod -o -g $LGID $GROUPNAME >/dev/null 2>&1 + useradd -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1 || + usermod -o -u $LUID -g $GROUPNAME -s /bin/false $USERNAME >/dev/null 2>&1 + mkhomedir_helper $USERNAME # The rest... From ebe133f579b298c78d1ea148b9a4cc9ac763377c Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Tue, 26 Aug 2025 13:50:35 +0000 Subject: [PATCH 045/167] Autosync the updated translations (#16159) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/browser/store/locales/ar/copy.resx | 56 +++++++++++----------- apps/browser/store/locales/az/copy.resx | 5 +- apps/browser/store/locales/be/copy.resx | 2 +- apps/browser/store/locales/bn/copy.resx | 2 +- apps/browser/store/locales/bs/copy.resx | 2 +- apps/browser/store/locales/ca/copy.resx | 2 +- apps/browser/store/locales/cs/copy.resx | 2 +- apps/browser/store/locales/cy/copy.resx | 2 +- apps/browser/store/locales/da/copy.resx | 2 +- apps/browser/store/locales/de/copy.resx | 2 +- apps/browser/store/locales/el/copy.resx | 2 +- apps/browser/store/locales/en_GB/copy.resx | 2 +- apps/browser/store/locales/en_IN/copy.resx | 2 +- apps/browser/store/locales/es/copy.resx | 2 +- apps/browser/store/locales/et/copy.resx | 2 +- apps/browser/store/locales/eu/copy.resx | 2 +- apps/browser/store/locales/fil/copy.resx | 2 +- apps/browser/store/locales/gl/copy.resx | 2 +- apps/browser/store/locales/hi/copy.resx | 2 +- apps/browser/store/locales/hr/copy.resx | 2 +- apps/browser/store/locales/hu/copy.resx | 2 +- apps/browser/store/locales/id/copy.resx | 52 ++++++++++---------- apps/browser/store/locales/it/copy.resx | 2 +- apps/browser/store/locales/ja/copy.resx | 53 ++++++++++---------- apps/browser/store/locales/ka/copy.resx | 2 +- apps/browser/store/locales/km/copy.resx | 2 +- apps/browser/store/locales/kn/copy.resx | 2 +- apps/browser/store/locales/ko/copy.resx | 56 +++++++++++----------- apps/browser/store/locales/lt/copy.resx | 2 +- apps/browser/store/locales/ml/copy.resx | 2 +- apps/browser/store/locales/mr/copy.resx | 2 +- apps/browser/store/locales/my/copy.resx | 2 +- apps/browser/store/locales/nb/copy.resx | 2 +- apps/browser/store/locales/ne/copy.resx | 2 +- apps/browser/store/locales/nl/copy.resx | 2 +- apps/browser/store/locales/nn/copy.resx | 2 +- apps/browser/store/locales/or/copy.resx | 2 +- apps/browser/store/locales/pt_BR/copy.resx | 2 +- apps/browser/store/locales/pt_PT/copy.resx | 2 +- apps/browser/store/locales/ro/copy.resx | 2 +- apps/browser/store/locales/si/copy.resx | 2 +- apps/browser/store/locales/sl/copy.resx | 2 +- apps/browser/store/locales/sr/copy.resx | 2 +- apps/browser/store/locales/sv/copy.resx | 2 +- apps/browser/store/locales/te/copy.resx | 2 +- apps/browser/store/locales/th/copy.resx | 2 +- apps/browser/store/locales/tr/copy.resx | 5 +- apps/browser/store/locales/vi/copy.resx | 2 +- apps/browser/store/locales/zh_CN/copy.resx | 53 ++++++++++---------- apps/browser/store/locales/zh_TW/copy.resx | 54 ++++++++++----------- 50 files changed, 209 insertions(+), 209 deletions(-) diff --git a/apps/browser/store/locales/ar/copy.resx b/apps/browser/store/locales/ar/copy.resx index a83bafbf1ae..78246175bef 100644 --- a/apps/browser/store/locales/ar/copy.resx +++ b/apps/browser/store/locales/ar/copy.resx @@ -124,50 +124,48 @@ في المنزل، في العمل، أو في أثناء التنقل، يقوم بتواردن بتأمين جميع كلمات المرور والمعلومات الحساسة بسهولة. - مُعترف به كأفضل مدير كلمات مرور من قِبل PCMag وWIRED وThe Verge وCNET وG2 وغيرها! + Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more! -أمّن حياتك الرقمية +SECURE YOUR DIGITAL LIFE +Secure your digital life and protect against data breaches by generating and saving unique, strong passwords for every account. Maintain everything in an end-to-end encrypted password vault that only you can access. -أمّن حياتك الرقمية واحمِ بياناتك من الاختراقات بإنشاء كلمات مرور فريدة وقوية وحفظها لكل حساب. احفظ كل شيء في مخزن كلمات مرور مشفّر من البداية إلى النهاية، لا يمكن لأحد الوصول إليه سواك. +ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE +Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions. -الوصول إلى بياناتك، من أي مكان، وفي أي وقت، وعلى أي جهاز +EVERYONE SHOULD HAVE THE TOOLS TO STAY SAFE ONLINE +Utilize Bitwarden for free with no ads or selling data. Bitwarden believes everyone should have the ability to stay safe online. Premium plans offer access to advanced features. -يمكنك بسهولة إدارة كلمات مرور غير محدودة وتخزينها وتأمينها ومشاركتها عبر عدد غير محدود من الأجهزة دون قيود. +EMPOWER YOUR TEAMS WITH BITWARDEN +Plans for Teams and Enterprise come with professional business features. Some examples include SSO integration, self-hosting, directory integration and SCIM provisioning, global policies, API access, event logs, and more. -يجب أن يمتلك الجميع الأدوات اللازمة للبقاء آمنًا على الإنترنت +Use Bitwarden to secure your workforce and share sensitive information with colleagues. -استخدم بيتواردن مجانًا دون إعلانات أو بيع بيانات. تؤمن بيتواردن بحق الجميع في البقاء آمنًا على الإنترنت. توفر الباقات المميزة إمكانية الوصول إلى ميزات متقدمة. -عزز قدرات فرقك مع بتواردن -تأتي باقاتنا للفرق والمؤسسات مزودة بميزات احترافية للأعمال. من الأمثلة على ذلك تكامل SSO، والاستضافة الذاتية، وتكامل الدليل، وتوفير SCIM، والسياسات العالمية، والوصول إلى واجهة برمجة التطبيقات، وسجلات الأحداث، والمزيد. +More reasons to choose Bitwarden: -استخدم بيتواردن لتأمين فريق عملك ومشاركة المعلومات الحساسة مع زملائك. +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. -أسباب إضافية لاختيار بتواردن: +3rd-party Audits +Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. -تشفير عالمي المستوى -كلمات المرور محمية بتشفير متقدم من البداية إلى النهاية (AES-256 بت، وهاشتاج مُملح، وPBKDF2 SHA-256) لضمان أمان بياناتك وخصوصيتها. +Advanced 2FA +Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey. -عمليات تدقيق خارجية -تُجري بيتواردن بانتظام عمليات تدقيق أمنية شاملة من جهات خارجية بالتعاون مع شركات أمنية مرموقة. تشمل هذه العمليات السنوية تقييمات لشفرة المصدر واختبارات اختراق عبر عناوين IP وخوادم وتطبيقات الويب الخاصة بـبتواردن. +Bitwarden Send +Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure. -مصادقة ثنائية متقدمة -أمّن تسجيل دخولك باستخدام مُصادق خارجي، أو رموز مُرسلة عبر البريد الإلكتروني، أو بيانات اعتماد FIDO2 WebAuthn مثل مفتاح أمان الأجهزة أو كلمة المرور. +Built-in Generator +Create long, complex, and distinct passwords and unique usernames for every site you visit. Integrate with email alias providers for additional privacy. -إرسال بتواردن -انقل البيانات مباشرةً إلى الآخرين مع الحفاظ على أمان مشفّر من البداية إلى النهاية والحد من التعرض. +Global Translations +Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin. -مولد مدمج -أنشئ كلمات مرور طويلة ومعقدة ومميزة وأسماء مستخدمين فريدة لكل موقع تزوره. تكامل مع مزودي أسماء البريد الإلكتروني المستعارة لمزيد من الخصوصية. +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. -ترجمات عالمية -تتوفر ترجمات بتواردن لأكثر من 60 لغة، مترجمة من قِبل المجتمع العالمي عبر Crowdin. - -تطبيقات متعددة المنصات -أمّن بياناتك الحساسة وشاركها داخل مخزن بتواردن من أي متصفح أو جهاز محمول أو نظام تشغيل سطح مكتب، وغير ذلك الكثير. - -يؤمن بتواردن أكثر من مجرد كلمات مرور -تُمكّن حلول إدارة بيانات الاعتماد المشفرة من البداية إلى النهاية من بتواردن المؤسسات من تأمين كل شيء، بما في ذلك أسرار المطورين وتجارب مفاتيح المرور. تفضل بزيارة Bitwarden.com لمعرفة المزيد عن المدير السري لبتواردن وBitwarden Passwordless.dev! +Bitwarden secures more than just passwords +End-to-end encrypted credential management solutions from Bitwarden empower organizations to secure everything, including developer secrets and passkey experiences. Visit Bitwarden.com to learn more about Bitwarden Secrets Manager and Bitwarden Passwordless.dev! diff --git a/apps/browser/store/locales/az/copy.resx b/apps/browser/store/locales/az/copy.resx index 65c416c00d3..6a1a0c9d471 100644 --- a/apps/browser/store/locales/az/copy.resx +++ b/apps/browser/store/locales/az/copy.resx @@ -142,7 +142,7 @@ Komanda və Müəssisələr üçün planlar, professional biznes özəllikləri Bitwarden-i seçmək üçün daha çox səbəb: Dünya səviyyəli şifrələmə -Parollar, qabaqcıl ucdan uca şifrələmə (AES-256 bit, salted hashtag və PBKDF2 SHA-256) ilə qorunur, beləliklə veriləriniz güvəndə və məxfi qalır. +Parollar, qabaqcıl ucdan uca şifrələmə (AES-256 bit, salted hashing və PBKDF2 SHA-256) ilə qorunur, beləliklə veriləriniz güvəndə və məxfi qalır. 3-cü tərəf auditləri Bitwarden, müntəzəm olaraq tanınmış təhlükəsizlik firmaları ilə hərtərəfli üçüncü tərəf təhlükəsizlik auditləri keçirir. Bu illik auditlərə Bitwarden IP-ləri, serverləri və veb tətbiqləri arasında mənbə kodu qiymətləndirmələri və nüfuz testi daxildir. @@ -163,7 +163,8 @@ Bitwarden tərcümələri 60-dan çox dildə mövcuddur, Crowdin vasitəsilə ql İstənilən brauzerdən, mobil cihazdan və ya masaüstü əməliyyat sistemindən və daha çoxundan Bitwarden Seyfinizdəki həssas veriləri güvəndə saxlayın və paylaşın. Bitwarden parollardan daha çox qoruyur -Bitwarden-nin ucdan-uca şifrələnmiş kimlik məlumatlarını idarəetmə həlləri, təşkilatlara hər şeyi, o cümlədən tərtibatçı sirrlərini və keçid açarı təcrübələrini qorumaq gücü verir. Bitwarden Sirr Meneceri və Bitwarden Passwordless.dev haqqında daha ətraflı öyrənmək üçün Bitwarden.com saytını ziyarət edin! +Bitwarden-nin ucdan-uca şifrələnmiş kimlik məlumatlarını idarəetmə həlləri, təşkilatlara hər şeyi, o cümlədən tərtibatçı sirrlərini və keçid açarı təcrübələrini qorumaq gücü verir. Bitwarden Sirr Meneceri və Bitwarden Passwordless.dev haqqında daha ətraflı öyrənmək üçün Bitwarden.com saytını ziyarət edin! + Bitwarden evdə və ya işdə olarkən bütün parol, keçid açarı və həssas məlumatlarınızı asanlıqla qoruyur. diff --git a/apps/browser/store/locales/be/copy.resx b/apps/browser/store/locales/be/copy.resx index 8ac2e86232f..a30db1fd85e 100644 --- a/apps/browser/store/locales/be/copy.resx +++ b/apps/browser/store/locales/be/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/bn/copy.resx b/apps/browser/store/locales/bn/copy.resx index 1bcfb190016..3341a6f10d7 100644 --- a/apps/browser/store/locales/bn/copy.resx +++ b/apps/browser/store/locales/bn/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/bs/copy.resx b/apps/browser/store/locales/bs/copy.resx index 82e4eb1d88e..377b13e7423 100644 --- a/apps/browser/store/locales/bs/copy.resx +++ b/apps/browser/store/locales/bs/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/ca/copy.resx b/apps/browser/store/locales/ca/copy.resx index 5a06f818e3c..b20eed1e87d 100644 --- a/apps/browser/store/locales/ca/copy.resx +++ b/apps/browser/store/locales/ca/copy.resx @@ -144,7 +144,7 @@ Utilitzeu Bitwarden per protegir la vostra força de treball i compartir informa Més raons per a triar Bitwarden: Xifratge de classe mundial -Les contrasenyes estan protegides amb un xifratge avançat d'extrem a extrem (AES-256 bits, hashtag salat i PBKDF2 SHA-256) perquè les vostres dades es mantinguen segures i privades. +Les contrasenyes estan protegides amb un xifratge avançat d'extrem a extrem (AES-256 bits, hashing salat i PBKDF2 SHA-256) perquè les vostres dades es mantinguen segures i privades. Auditories de tercers Bitwarden realitza regularment auditories de seguretat exhaustives de tercers amb empreses de seguretat notables. Aquestes auditories anuals inclouen avaluacions del codi font i proves de penetració a les IP, servidors i aplicacions web de Bitwarden. diff --git a/apps/browser/store/locales/cs/copy.resx b/apps/browser/store/locales/cs/copy.resx index c3a58379dc5..f23315b0d16 100644 --- a/apps/browser/store/locales/cs/copy.resx +++ b/apps/browser/store/locales/cs/copy.resx @@ -144,7 +144,7 @@ Použijte Bitwarden k zabezpečení svých zaměstnanců a sdílení citlivých Další důvody, proč si vybrat Bitwarden: Šifrování na světové úrovni -Hesla jsou chráněna pokročilým end-to-end šifrováním (AES-256 bitů, solený hashtag a PBKDF2 SHA-256), takže Vaše data zůstanou v bezpečí a soukromí. +Hesla jsou chráněna pokročilým end-to-end šifrováním (AES-256 bitů, solený hashing a PBKDF2 SHA-256), takže Vaše data zůstanou v bezpečí a soukromí. Audity třetích stran Společnost Bitwarden pravidelně provádí komplexní bezpečnostní audity třetích stran s významnými bezpečnostními firmami. Tyto každoroční audity zahrnují posouzení zdrojového kódu a penetrační testy napříč IP adresami, servery a webovými aplikacemi společnosti Bitwarden. diff --git a/apps/browser/store/locales/cy/copy.resx b/apps/browser/store/locales/cy/copy.resx index 0cb03a8a291..e6e48ea12a5 100644 --- a/apps/browser/store/locales/cy/copy.resx +++ b/apps/browser/store/locales/cy/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/da/copy.resx b/apps/browser/store/locales/da/copy.resx index 928e54d8edd..38c96b485d2 100644 --- a/apps/browser/store/locales/da/copy.resx +++ b/apps/browser/store/locales/da/copy.resx @@ -144,7 +144,7 @@ Brug Bitwarden til at sikre arbejdsstyrken og dele sensitive oplysninger med kol Flere grunde til at vælge Bitwarden: Kryptering i verdensklasse -Adgangskoder er beskyttet med avanceret ende-til-ende-kryptering (AES-256 bit, saltet hashtag og PBKDF2 SHA-256), så dataene forbliver sikre og private. +Adgangskoder er beskyttet med avanceret ende-til-ende-kryptering (AES-256 bit, saltet hashing og PBKDF2 SHA-256), så dataene forbliver sikre og private. Tredjepartsrevisioner Bitwarden udfører regelmæssigt omfattende tredjeparts sikkerhedsrevisioner med velrenommerede sikkerhedsfirmaer. Disse årlige revisioner inkluderer kildekodevurderinger og penetrationstest på tværs af Bitwarden IP'er, servere og webapplikationer. diff --git a/apps/browser/store/locales/de/copy.resx b/apps/browser/store/locales/de/copy.resx index eb3ab2afd48..014a5b09bc9 100644 --- a/apps/browser/store/locales/de/copy.resx +++ b/apps/browser/store/locales/de/copy.resx @@ -144,7 +144,7 @@ Nutze Bitwarden, um deine Mitarbeiter abzusichern und sensible Informationen mit Weitere Gründe, Bitwarden zu wählen: Weltklasse-Verschlüsselung -Passwörter werden mit fortschrittlicher Ende-zu-Ende-Verschlüsselung (AES-256 bit, salted hashtag und PBKDF2 SHA-256) geschützt, damit deine Daten sicher und geheim bleiben. +Passwörter werden mit fortschrittlicher Ende-zu-Ende-Verschlüsselung (AES-256 bit, salted hashing und PBKDF2 SHA-256) geschützt, damit deine Daten sicher und geheim bleiben. 3rd-Party-Prüfungen Bitwarden führt regelmäßig umfassende Sicherheitsprüfungen durch Dritte von namhaften Sicherheitsfirmen durch. Diese jährlichen Prüfungen umfassen Quellcode-Bewertungen und Penetration-Tests für Bitwarden-IPs, Server und Webanwendungen. diff --git a/apps/browser/store/locales/el/copy.resx b/apps/browser/store/locales/el/copy.resx index 5c1d99de2a2..e464d6d6ee6 100644 --- a/apps/browser/store/locales/el/copy.resx +++ b/apps/browser/store/locales/el/copy.resx @@ -143,7 +143,7 @@ Περισσότεροι λόγοι για να επιλέξετε το Bitwarden: Κρυπτογράφηση Παγκόσμιας Κλάσης -Οι κωδικοί πρόσβασης προστατεύονται με προηγμένη κρυπτογράφηση από άκρο σε άκρο (AES-256 bit, salted hashtag και PBKDF2 SHA-256), ώστε τα δεδομένα σας να παραμένουν ασφαλή και ιδιωτικά. +Οι κωδικοί πρόσβασης προστατεύονται με προηγμένη κρυπτογράφηση από άκρο σε άκρο (AES-256 bit, salted hashing και PBKDF2 SHA-256), ώστε τα δεδομένα σας να παραμένουν ασφαλή και ιδιωτικά. Έλεγχοι από Τρίτους Το Bitwarden διεξάγει τακτικά ολοκληρωμένους ελέγχους ασφαλείας από τρίτους με αξιόλογες εταιρείες ασφαλείας. Αυτοί οι ετήσιοι έλεγχοι περιλαμβάνουν αξιολογήσεις πηγαίου κώδικα και δοκιμές διείσδυσης σε όλες τις IP του Bitwarden, τους διακομιστές και τις εφαρμογές ιστού. diff --git a/apps/browser/store/locales/en_GB/copy.resx b/apps/browser/store/locales/en_GB/copy.resx index 7c408ad8897..b84e733eb6d 100644 --- a/apps/browser/store/locales/en_GB/copy.resx +++ b/apps/browser/store/locales/en_GB/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-Party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/en_IN/copy.resx b/apps/browser/store/locales/en_IN/copy.resx index 31e5d2326f6..935236d7f29 100644 --- a/apps/browser/store/locales/en_IN/copy.resx +++ b/apps/browser/store/locales/en_IN/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/es/copy.resx b/apps/browser/store/locales/es/copy.resx index a17440a0d6b..34a9850168a 100644 --- a/apps/browser/store/locales/es/copy.resx +++ b/apps/browser/store/locales/es/copy.resx @@ -143,7 +143,7 @@ Utiliza Bitwarden para proteger a tu personal y compartir información confidenc Más razones para elegir Bitwarden: Encriptación de clase mundial -Las contraseñas están protegidas con cifrado avanzado de extremo a extremo (AES-256 bits, hashtag salado y PBKDF2 SHA-256) para que tus datos permanezcan seguros y privados. +Las contraseñas están protegidas con cifrado avanzado de extremo a extremo (AES-256 bits, hashing salado y PBKDF2 SHA-256) para que tus datos permanezcan seguros y privados. Auditorías de terceros Bitwarden realiza regularmente auditorías integrales de seguridad de terceros con empresas de seguridad notables. Estas auditorías anuales incluyen evaluaciones de código fuente y pruebas de penetración en las direcciones IP, los servidores y las aplicaciones web de Bitwarden. diff --git a/apps/browser/store/locales/et/copy.resx b/apps/browser/store/locales/et/copy.resx index d2a6be860ce..cfdeb28aadb 100644 --- a/apps/browser/store/locales/et/copy.resx +++ b/apps/browser/store/locales/et/copy.resx @@ -144,7 +144,7 @@ Kasuta Bitwardenit oma töötajate turvamiseks ja tundliku informatsiooni jagami Veel Põhjusi Miks Valida Bitwarden: Maailmatasemel Krüpteering -Paroolid on kaitstud tipptehnoloogilise täieliku krüpteerimisega (AES-256 bit, salted hashtag ja PBKDF2 SHA-256), nii et sinu andmed püsivad privaatsete ja turvalistena. +Paroolid on kaitstud tipptehnoloogilise täieliku krüpteerimisega (AES-256 bit, salted hashing ja PBKDF2 SHA-256), nii et sinu andmed püsivad privaatsete ja turvalistena. Põhjalikud turvatestid kolmandate firmade poolt Bitwarden korraldab regulaarselt põhjalike turvateste tuntud kolmandate firmade poolt. Need igaaastased kontrolltestid sisaldavad kogu koodibaasi ülevaatust ja test-küberrünnakuid Bitwardeni IP-de, serverite ja veebirakenduste vastu. diff --git a/apps/browser/store/locales/eu/copy.resx b/apps/browser/store/locales/eu/copy.resx index e4271e8ae37..b5225827636 100644 --- a/apps/browser/store/locales/eu/copy.resx +++ b/apps/browser/store/locales/eu/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/fil/copy.resx b/apps/browser/store/locales/fil/copy.resx index 0f68a90bfaa..56ddcefbf99 100644 --- a/apps/browser/store/locales/fil/copy.resx +++ b/apps/browser/store/locales/fil/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/gl/copy.resx b/apps/browser/store/locales/gl/copy.resx index feff0fc99e2..49055ff6511 100644 --- a/apps/browser/store/locales/gl/copy.resx +++ b/apps/browser/store/locales/gl/copy.resx @@ -144,7 +144,7 @@ Usa Bitwarden para protexer ao teu persoal e compartir información confidencial Máis razóns para escoller Bitwarden: Cifrado de clase mundial -Os contrasinais están protexidos con cifrado avanzado de extremo a extremo (AES-256 bits, hashtag salgado e PBKDF2 SHA-256) para que os teus datos permanezan seguros e privados. +Os contrasinais están protexidos con cifrado avanzado de extremo a extremo (AES-256 bits, hashing salgado e PBKDF2 SHA-256) para que os teus datos permanezan seguros e privados. Auditorías de terceiros Bitwarden realiza regularmente auditorías de seguridade completas de terceiros con importantes empresas de seguridade. Estas auditorías anuais inclúen avaliacións do código fonte e probas de penetración nas IP, servidores e aplicacións web de Bitwarden. diff --git a/apps/browser/store/locales/hi/copy.resx b/apps/browser/store/locales/hi/copy.resx index 1ea7314d529..e145772e0c1 100644 --- a/apps/browser/store/locales/hi/copy.resx +++ b/apps/browser/store/locales/hi/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/hr/copy.resx b/apps/browser/store/locales/hr/copy.resx index c71315011e6..6a7905ad73e 100644 --- a/apps/browser/store/locales/hr/copy.resx +++ b/apps/browser/store/locales/hr/copy.resx @@ -144,7 +144,7 @@ Koristi Bitwarden da osiguraš svoje zaposlenike i podijeliš osjetljive podatke Više razloga za odabir Bitwardena: Enkripcija svjetske razine -Lozinke su zaštićene naprednom end-to-end enkripcijom (AES-256 bit, salted hashtag i PBKDF2 SHA-256) tako da tvoji podaci ostaju sigurni i privatni. +Lozinke su zaštićene naprednom end-to-end enkripcijom (AES-256 bit, salted hashing i PBKDF2 SHA-256) tako da tvoji podaci ostaju sigurni i privatni. Revizije treće strane Bitwarden je redovito podložan opsežnim sigurnosnim revizijama treće strane s poznatim sigurnosnim tvrtkama. Ove godišnje revizije uključuju procjene izvornog koda i testiranje penetracije preko Bitwarden IP adresa, poslužitelja i web aplikacija. diff --git a/apps/browser/store/locales/hu/copy.resx b/apps/browser/store/locales/hu/copy.resx index 3e6b8e42d46..814ebabaada 100644 --- a/apps/browser/store/locales/hu/copy.resx +++ b/apps/browser/store/locales/hu/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/id/copy.resx b/apps/browser/store/locales/id/copy.resx index 2cd61460ccd..4e382f94861 100644 --- a/apps/browser/store/locales/id/copy.resx +++ b/apps/browser/store/locales/id/copy.resx @@ -124,48 +124,48 @@ Di rumah, di kantor, atau di perjalanan, Bitwarden mengamankan semua kata sandi, kunci sandi, dan informasi sensitif Anda dengan mudah. - Dikenal sebagai pengelola sandi terbaik oleh PCMag, WIRED, The Verge, CNET, G2, dan lainnya! + Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more! -AMANKAN KEHIDUPAN DIGITAL ANDA -Amankan kehidupan digital Anda dan dapatkan perlindungan dari peretasan data dengan membuat dan menyimpan kata sandi yang unik dan kuat untuk setiap akun. Rawat semuanya dalam brankas kata sandi terenkripsi dari ujung-ke-ujung yang hanya bisa diakses oleh Anda. +SECURE YOUR DIGITAL LIFE +Secure your digital life and protect against data breaches by generating and saving unique, strong passwords for every account. Maintain everything in an end-to-end encrypted password vault that only you can access. -AKSES DATA ANDA, DI MANA SAJA, KAPAN SAJA, DI PERANGKAT APA PUN -Kelola, simpan, amankan, dan bagikan tanpa batas dengan mudah kata sandi antar perangkat tak terbatas dan tanpa batasan. +ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE +Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions. -SETIAP ORANG HARUS MEMILIKI PERALATAN UNTUK TETAP AMAN KETIKA DARING -Gunakan Bitwarden secara gratis tanpa iklan atau menjual data. Bitwarden percaya setiap orang harus memiliki kemampuan untuk tetap aman ketika daring. Paket premium menawarkan akses ke fitur-fitur yang lebih lanjut. +EVERYONE SHOULD HAVE THE TOOLS TO STAY SAFE ONLINE +Utilize Bitwarden for free with no ads or selling data. Bitwarden believes everyone should have the ability to stay safe online. Premium plans offer access to advanced features. -BERDAYAKAN TIM ANDA DENGAN BITWARDEN -Paket untuk Teams dan Enterprise memiliki kemampuan bisnis profesional, termasuk pemaduan SSO, hosting mandiri, pemaduan direktori dan pembekalan SCIM, kebijakan global, akses API, log kejadian, dan banyak lagi. +EMPOWER YOUR TEAMS WITH BITWARDEN +Plans for Teams and Enterprise come with professional business features. Some examples include SSO integration, self-hosting, directory integration and SCIM provisioning, global policies, API access, event logs, and more. -Gunakan Bitwarden untuk mengamankan kerja Anda dan membagikan informasi sensitif kepada rekan kerja. +Use Bitwarden to secure your workforce and share sensitive information with colleagues. -Alasan lebih lanjut untuk memilih Bitwarden: +More reasons to choose Bitwarden: -Enkripsi Kelas Dunia -Semua kata sandi dilindungi dengan enkripsi ujung-ke-ujung yang lebih lanjut (AES-256 bit, tanda pagar bergaram, dan PBKDF2 SHA-256) sehingga data Anda tetap aman dan privat. +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. -Audit Pihak Ketiga -Bitwarden secara rutin melakukan audit keamanan yang dilakukan pihak ketiga secara menyeluruh dengan perusahaan keamanan terkemuka. Audit tahunan ini termasuk penilaian sumber kode dan pengujian penembusan antar IP, server, dan aplikasi web Bitwarden. +3rd-party Audits +Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. -2FA Terdepan -Amankan proses masuk Anda dengan pengotentikasi pihak ketiga, kode yang dikirim ke surel, atau pengenal WebAuthn FIDO2 seperti kunci keamanan perangkat keras atau kunci sandi. +Advanced 2FA +Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey. Bitwarden Send -Kirim data ke orang lain secara langsung sembari menjaga keamanan dari ujung-ke-ujung dan membatasi singkapan. +Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure. -Pembuat Sandi Bawaan -Buat kata sandi yang panjang, rumit, dan berbeda serta nama pengguna unik untuk setiap situs yang Anda kunjungi. Campurkan dengan nama lain surel untuk privasi lebih lanjut. +Built-in Generator +Create long, complex, and distinct passwords and unique usernames for every site you visit. Integrate with email alias providers for additional privacy. -Terjemahan Global -Terjemahan Bitwarden hadir dalam lebih dari 60 bahasa, diterjemahkan oleh komunitas global melalui Crowdin. +Global Translations +Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin. -Aplikasi Lintas Platform -Amankan dan bagikan data sensitif dalam Brankas Bitwarden Anda dari peramban apa pun, ponsel, atau sistem operasi desktop, dan lebih banyak lagi. +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. -Bitwarden mengamankan lebih dari sekedar kata sandi -Solusi pengelolaan identitas terenkripsi ujung-ke-ujung dari Bitwarden memberdayakan organisasi untuk mengamankan segalanya, termasuk rahasia pengembang dan kunci sandi. Kunjungi bitwarden.com untuk mempelajari lebih lanjut tentang Pengelola Rahasia Bitwarden dan passwordless.dev Bitwarden! +Bitwarden secures more than just passwords +End-to-end encrypted credential management solutions from Bitwarden empower organizations to secure everything, including developer secrets and passkey experiences. Visit Bitwarden.com to learn more about Bitwarden Secrets Manager and Bitwarden Passwordless.dev! diff --git a/apps/browser/store/locales/it/copy.resx b/apps/browser/store/locales/it/copy.resx index 96801c9d025..e76e78bc4ab 100644 --- a/apps/browser/store/locales/it/copy.resx +++ b/apps/browser/store/locales/it/copy.resx @@ -144,7 +144,7 @@ Utilizza Bitwarden per proteggere i tuoi dipendenti e condividere informazioni s Altri motivi per scegliere Bitwarden: Crittografia di livello mondiale -Le password sono protette con crittografia end-to-end avanzata (AES-256 bit, salted hashtag, e PBKDF2 SHA-256) in modo che i tuoi dati rimangano sicuri e privati. +Le password sono protette con crittografia end-to-end avanzata (AES-256 bit, salted hashing, e PBKDF2 SHA-256) in modo che i tuoi dati rimangano sicuri e privati. Controlli di terze parti Bitwarden conduce regolarmente controlli di sicurezza completi di terze parti con importanti società di sicurezza. Questi controlli annuali includono valutazioni del codice sorgente e test di penetrazione su IP, server, e applicazioni web di Bitwarden. diff --git a/apps/browser/store/locales/ja/copy.resx b/apps/browser/store/locales/ja/copy.resx index 3ecba765d01..c728a6307fd 100644 --- a/apps/browser/store/locales/ja/copy.resx +++ b/apps/browser/store/locales/ja/copy.resx @@ -124,47 +124,48 @@ 自宅、職場、または外出先でも、Bitwarden はすべてのパスワード、パスキー、機密情報を簡単に保護します。 - PCMag、WIRED、The Verge、CNET、G2 などから最高のパスワードマネージャーとして認められています! + Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more! -デジタルライフを守る -データ漏洩を防ぐために、各アカウントに対してユニークで強力なパスワードを生成し保存することで、デジタルライフを守りましょう。エンドツーエンドで暗号化されたパスワード保管庫にすべてを保存し、あなただけがアクセスできます。 +SECURE YOUR DIGITAL LIFE +Secure your digital life and protect against data breaches by generating and saving unique, strong passwords for every account. Maintain everything in an end-to-end encrypted password vault that only you can access. -どこでも、いつでも、どのデバイスでもデータにアクセス -デバイスやパスワード数の制限は一切なく、簡単に管理、保存、保護、共有できます。 +ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE +Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions. -誰もがオンラインで安全を保つためのツールを持つべき -Bitwarden は広告やデータ販売なしに無料で利用できます。Bitwarden は、誰もがオンラインで安全を保つ能力を持つべきだと信じています。プレミアムプランでは高度な機能にアクセスできます。 +EVERYONE SHOULD HAVE THE TOOLS TO STAY SAFE ONLINE +Utilize Bitwarden for free with no ads or selling data. Bitwarden believes everyone should have the ability to stay safe online. Premium plans offer access to advanced features. -チームを Bitwarden で強化 -チームおよびエンタープライズ向けのプランには、SSO 統合、セルフホスティング、ディレクトリ統合と SCIM プロビジョニング、グローバルポリシー、API アクセス、イベントログなどのプロフェッショナルなビジネス機能が含まれます。 +EMPOWER YOUR TEAMS WITH BITWARDEN +Plans for Teams and Enterprise come with professional business features. Some examples include SSO integration, self-hosting, directory integration and SCIM provisioning, global policies, API access, event logs, and more. -Bitwardenを使用して、従業員を保護し、同僚と機密情報を共有しましょう。 +Use Bitwarden to secure your workforce and share sensitive information with colleagues. -Bitwardenを選ぶ理由 -世界クラスの暗号化 -パスワードは、先進的なエンドツーエンド暗号化(AES-256ビット、ソルト付きハッシュタグ、PBKDF2 SHA-256)で保護され、データは安全かつプライベートに保たれます。 +More reasons to choose Bitwarden: -第三者監査 -Bitwarden は、著名なセキュリティ企業による包括的な第三者セキュリティ監査を定期的に実施しています。これらの年次監査には、ソースコードの評価や Bitwarden の IP、サーバー、ウェブアプリケーション全体にわたるペネトレーションテストが含まれます。 +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. -高度な2要素認証 -サードパーティーの認証アプリ、メールコード、またはハードウェアセキュリティキーやパスキーなどの FIDO2 WebAuthn 資格情報でログインを保護します。 +3rd-party Audits +Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. + +Advanced 2FA +Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey. Bitwarden Send -エンドツーエンドで暗号化されたセキュリティを維持しながら、他者にデータを直接送信し、データ漏洩を制限します。 +Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure. -内蔵ジェネレーター -訪問するすべてのサイトに対して、長く複雑でユニークなパスワードとユーザー名を作成できます。追加のプライバシーのためにメールエイリアスプロバイダーと統合することもできます。 +Built-in Generator +Create long, complex, and distinct passwords and unique usernames for every site you visit. Integrate with email alias providers for additional privacy. -グローバル翻訳 -Bitwarden の翻訳は、Crowdin を通じてグローバルコミュニティによって翻訳され、60以上の言語に対応しています。 +Global Translations +Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin. -クロスプラットフォームアプリケーション -任意のブラウザ、モバイルデバイス、デスクトップ OS などから、Bitwarden 保管庫内の機密データを保護し、共有できます。 +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. -Bitwarden はパスワードだけを保護するわけではありません -Bitwarden のエンドツーエンド暗号化された資格情報管理ソリューションは、組織が開発者のシークレットやパスキー体験を含むすべてを保護することを支援します。Bitwarden シークレットマネージャーや Bitwarden Passwordless.dev について詳しくは、Bitwarden.com をご覧ください。 +Bitwarden secures more than just passwords +End-to-end encrypted credential management solutions from Bitwarden empower organizations to secure everything, including developer secrets and passkey experiences. Visit Bitwarden.com to learn more about Bitwarden Secrets Manager and Bitwarden Passwordless.dev! diff --git a/apps/browser/store/locales/ka/copy.resx b/apps/browser/store/locales/ka/copy.resx index 82e4eb1d88e..377b13e7423 100644 --- a/apps/browser/store/locales/ka/copy.resx +++ b/apps/browser/store/locales/ka/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/km/copy.resx b/apps/browser/store/locales/km/copy.resx index 82e4eb1d88e..377b13e7423 100644 --- a/apps/browser/store/locales/km/copy.resx +++ b/apps/browser/store/locales/km/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/kn/copy.resx b/apps/browser/store/locales/kn/copy.resx index f68f2c25dab..09a3576a7a8 100644 --- a/apps/browser/store/locales/kn/copy.resx +++ b/apps/browser/store/locales/kn/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/ko/copy.resx b/apps/browser/store/locales/ko/copy.resx index de6ef1c370d..624ce415994 100644 --- a/apps/browser/store/locales/ko/copy.resx +++ b/apps/browser/store/locales/ko/copy.resx @@ -124,50 +124,48 @@ 집에서도, 직장에서도, 이동 중에도 Bitwarden은 비밀번호, 패스키, 민감 정보를 쉽게 보호합니다. - PCMag, WIRED, The Verge, CNET, G2 등에서 최고의 비밀번호 관리자 선정! + Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more! -디지털 라이프를 안전하게 보호하세요 -모든 계정을 위한 강력하고 고유한 비밀번호를 생성하고 저장하여, 데이터 유출로부터 안전하게 보호하세요. 오직 사용자만 접근할 수 있는 엔드투엔드 방식으로 암호화된 비밀번호 보관함에서 모든 것을 관리하세요. +SECURE YOUR DIGITAL LIFE +Secure your digital life and protect against data breaches by generating and saving unique, strong passwords for every account. Maintain everything in an end-to-end encrypted password vault that only you can access. -어디서든, 언제든, 어떤 기기에서든 접근 가능 -무제한의 비밀번호들을 관리, 저장, 보호, 공유하며 무제한의 기기에서 손쉽게 이용하세요. +ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE +Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions. -모두가 온라인 안전을 위한 도구를 가져야 합니다. -광고나 데이터 판매 없이 Bitwarden을 무료로 이용하세요. Bitwarden은 모두가 안전한 온라인 환경을 누릴 권리가 있다고 믿습니다. 프리미엄 플랜을 통해 고급 기능도 이용 가능합니다. +EVERYONE SHOULD HAVE THE TOOLS TO STAY SAFE ONLINE +Utilize Bitwarden for free with no ads or selling data. Bitwarden believes everyone should have the ability to stay safe online. Premium plans offer access to advanced features. -Bitwarden으로 팀을 강화하세요 -팀 및 사업용 플랜은 전문 비즈니스 기능을 제공합니다. 예를 들어 SSO 통합, 자체 호스팅, 디렉토리 통합 및 SCIM 프로비저닝, 글로벌 정책, API 접근, 이벤트 로그 등을 포함합니다. -(SSO: 1회 사용자 인증으로 다수의 앱, 웹에 접근, 인증할 수 있는 통합 로그인 솔루션) +EMPOWER YOUR TEAMS WITH BITWARDEN +Plans for Teams and Enterprise come with professional business features. Some examples include SSO integration, self-hosting, directory integration and SCIM provisioning, global policies, API access, event logs, and more. -Bitwarden을 사용하여 직원을 보호하고 동료들과 민감한 정보를 안전하게 공유하세요. +Use Bitwarden to secure your workforce and share sensitive information with colleagues. -Bitwarden을 선택해야 하는 이유 +More reasons to choose Bitwarden: -세계적 수준의 암호화 -고급 엔드 투 엔드 암호화(AES-256 비트, 솔팅된 해시 태그, PBKDF2 SHA-256)로 비밀번호를 보호하여 데이터의 보안과 개인 정보를 유지합니다. +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. -제3자를 통한 보안 감사 -Bitwarden은 저명한 보안 회사와 함께 정기적인 제3자 보안 감사를 수행합니다. 연례 감사에는 소스 코드 평가와 Bitwarden IP, 서버, 웹 애플리케이션에 대한 침투 테스트가 포함됩니다. +3rd-party Audits +Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. -고급 2단계 인증(2FA) -타사 인증 앱, 이메일 코드 또는 하드웨어 보안 키나 패스키와 같은 FIDO2 WebAuthn 자격 증명을 통해 로그인 보안을 강화하세요. +Advanced 2FA +Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey. -Bitwarden의 데이터 전송 방식 -엔드투엔드 암호화를 유지하면서 데이터를 직접 다른 사람에게 전송하여 노출을 최소화합니다. +Bitwarden Send +Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure. -내장된 비밀번호 및 사용자 이름 생성자 -긴, 복잡하고 고유한 비밀번호와 각 사이트에 사용할 고유 사용자 이름을 생성하세요. 이메일명 제공업체와 통합하여 추가적인 개인 정보 보호를 제공합니다. +Built-in Generator +Create long, complex, and distinct passwords and unique usernames for every site you visit. Integrate with email alias providers for additional privacy. -글로벌 번역 -Bitwarden은 Crowdin 글로벌 커뮤니티를 통해 한국어를 포함한 60개 이상의 언어로 번역되어 있습니다. +Global Translations +Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin. -크로스 플랫폼 애플리케이션 -모든 브라우저, 모바일 기기, 데스크톱 OS 등 다양한 환경에서 Bitwarden 보관함 내의 중요한 데이터를 안전하게 관리하고 공유하세요. +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. -비밀번호 이상의 보안을 제공합니다 -Bitwarden의 엔드투엔드 암호화된 신용 증명 관리 솔루션은 개발자 비밀과 패스키 경험을 포함한 모든 것을 보호하도록 조직을 지원합니다. -Bitwarden 의 Secrets Manager 및Passwordless.dev에 대해 자세히 알아보려면 Bitwarden.com 을 방문하세요! +Bitwarden secures more than just passwords +End-to-end encrypted credential management solutions from Bitwarden empower organizations to secure everything, including developer secrets and passkey experiences. Visit Bitwarden.com to learn more about Bitwarden Secrets Manager and Bitwarden Passwordless.dev! diff --git a/apps/browser/store/locales/lt/copy.resx b/apps/browser/store/locales/lt/copy.resx index d83c6ca99a5..8a11f6fdf58 100644 --- a/apps/browser/store/locales/lt/copy.resx +++ b/apps/browser/store/locales/lt/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/ml/copy.resx b/apps/browser/store/locales/ml/copy.resx index e22993d5b75..8f308181ef3 100644 --- a/apps/browser/store/locales/ml/copy.resx +++ b/apps/browser/store/locales/ml/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/mr/copy.resx b/apps/browser/store/locales/mr/copy.resx index 82e4eb1d88e..377b13e7423 100644 --- a/apps/browser/store/locales/mr/copy.resx +++ b/apps/browser/store/locales/mr/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/my/copy.resx b/apps/browser/store/locales/my/copy.resx index 82e4eb1d88e..377b13e7423 100644 --- a/apps/browser/store/locales/my/copy.resx +++ b/apps/browser/store/locales/my/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/nb/copy.resx b/apps/browser/store/locales/nb/copy.resx index 29d612906c7..a3d89e7bdc2 100644 --- a/apps/browser/store/locales/nb/copy.resx +++ b/apps/browser/store/locales/nb/copy.resx @@ -144,7 +144,7 @@ Bruk Bitwarden til å sikre arbeidsstyrken din og dele sensitiv informasjon med Flere grunner til å velge Bitwarden: Kryptering i verdensklasse -Passord er beskyttet med avansert ende-til-ende-kryptering (AES-256 bit, saltet hashtag og PBKDF2 SHA-256) slik at dataene dine forblir sikre og private. +Passord er beskyttet med avansert ende-til-ende-kryptering (AES-256 bit, saltet hashing og PBKDF2 SHA-256) slik at dataene dine forblir sikre og private. Tredjepartsrevisjoner Bitwarden gjennomfører regelmessig omfattende tredjeparts sikkerhetsrevisjoner med bemerkelsesverdige sikkerhetsfirmaer. Disse årlige revisjonene inkluderer kildekodevurderinger og penetrasjonstesting på tvers av Bitwarden IP-er, servere og webapplikasjoner. diff --git a/apps/browser/store/locales/ne/copy.resx b/apps/browser/store/locales/ne/copy.resx index 82e4eb1d88e..377b13e7423 100644 --- a/apps/browser/store/locales/ne/copy.resx +++ b/apps/browser/store/locales/ne/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/nl/copy.resx b/apps/browser/store/locales/nl/copy.resx index 17720f54f4c..fb9313e0c63 100644 --- a/apps/browser/store/locales/nl/copy.resx +++ b/apps/browser/store/locales/nl/copy.resx @@ -144,7 +144,7 @@ Gebruik Bitwarden om je medewerkers te beveiligen en gevoelige informatie te del Meer redenen om voor Bitwarden te kiezen: Encryptie van wereldklasse -Wachtwoorden worden beschermd met geavanceerde end-to-end versleuteling (AES-256 bit, salted hashtag en PBKDF2 SHA-256) zodat je gegevens veilig en privé blijven. +Wachtwoorden worden beschermd met geavanceerde end-to-end versleuteling (AES-256 bit, salted hashing en PBKDF2 SHA-256) zodat je gegevens veilig en privé blijven. Audits door derde partijen Bitwarden voert regelmatig uitgebreide beveiligingsaudits uit bij gerenommeerde beveiligingsbedrijven. Deze jaarlijkse audits omvatten broncodebeoordelingen en penetratietests voor Bitwarden IP's, servers en webapplicaties. diff --git a/apps/browser/store/locales/nn/copy.resx b/apps/browser/store/locales/nn/copy.resx index 82e4eb1d88e..377b13e7423 100644 --- a/apps/browser/store/locales/nn/copy.resx +++ b/apps/browser/store/locales/nn/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/or/copy.resx b/apps/browser/store/locales/or/copy.resx index 82e4eb1d88e..377b13e7423 100644 --- a/apps/browser/store/locales/or/copy.resx +++ b/apps/browser/store/locales/or/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/pt_BR/copy.resx b/apps/browser/store/locales/pt_BR/copy.resx index 266f4008523..edf2351c92d 100644 --- a/apps/browser/store/locales/pt_BR/copy.resx +++ b/apps/browser/store/locales/pt_BR/copy.resx @@ -143,7 +143,7 @@ Utilize o Bitwarden para proteger os seus colaboradores e compartilhar informaç Mais razões para escolher Bitwarden: Criptografia mundialmente reconhecida -Suas senhas são protegidas com avançada criptografia ponta a ponta (AES-256, salted hashtag, e PBKDF2 SHA-256) para que os seus dados estejam seguros e privados. +Suas senhas são protegidas com avançada criptografia ponta a ponta (AES-256, salted hashing, e PBKDF2 SHA-256) para que os seus dados estejam seguros e privados. Auditoria de Terceiros A Bitwarden regularmente conduz auditorias de terceiros com notáveis empresas de segurança. Essas auditorias anuais incluem qualificação do código fonte e testes de invasão contra os IPs da Bitwarden, servidores e aplicações web. diff --git a/apps/browser/store/locales/pt_PT/copy.resx b/apps/browser/store/locales/pt_PT/copy.resx index fa62a0f1d5c..ab4410a1550 100644 --- a/apps/browser/store/locales/pt_PT/copy.resx +++ b/apps/browser/store/locales/pt_PT/copy.resx @@ -144,7 +144,7 @@ Utilize o Bitwarden para proteger a sua equipa de trabalho e partilhar informaç Mais motivos para escolher o Bitwarden: Encriptação de classe mundial -As palavras-passe são protegidas com encriptação avançada ponto a ponto (AES-256 bits, salted hashtag e PBKDF2 SHA-256) para que os seus dados permaneçam seguros e privados. +As palavras-passe são protegidas com encriptação avançada ponto a ponto (AES-256 bits, salted hashing e PBKDF2 SHA-256) para que os seus dados permaneçam seguros e privados. Auditorias de terceiros O Bitwarden realiza regularmente auditorias abrangentes de segurança de terceiros com empresas de segurança notáveis. Estas auditorias anuais incluem avaliações de código-fonte e testes de penetração em IPs, servidores e aplicações Web do Bitwarden. diff --git a/apps/browser/store/locales/ro/copy.resx b/apps/browser/store/locales/ro/copy.resx index 7b0070fad22..f81094df81a 100644 --- a/apps/browser/store/locales/ro/copy.resx +++ b/apps/browser/store/locales/ro/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/si/copy.resx b/apps/browser/store/locales/si/copy.resx index 82e4eb1d88e..377b13e7423 100644 --- a/apps/browser/store/locales/si/copy.resx +++ b/apps/browser/store/locales/si/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/sl/copy.resx b/apps/browser/store/locales/sl/copy.resx index 80886de48ab..b2a95ed5689 100644 --- a/apps/browser/store/locales/sl/copy.resx +++ b/apps/browser/store/locales/sl/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/sr/copy.resx b/apps/browser/store/locales/sr/copy.resx index 2e737523856..6902ca57abf 100644 --- a/apps/browser/store/locales/sr/copy.resx +++ b/apps/browser/store/locales/sr/copy.resx @@ -144,7 +144,7 @@ Додатни разлози да изаберете Bitwarden: Енкрипција светске класе -Лозинке су заштићене са напредном потпуном енкрипцијом (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) тако да ваши подаци остају сигурни и приватни. +Лозинке су заштићене са напредном потпуном енкрипцијом (AES-256 bit, salted hashing, and PBKDF2 SHA-256) тако да ваши подаци остају сигурни и приватни. Ревизије треће стране Bitwarden редовно спроводи опсежне безбедносне ревизије трећих страна заједно са препознатим безбедносним фирмама. Ове годишње ревизије укључују процене изворног кода и тестирање пробојности Bitwarden-ових ИП адреса, сервера и веб апликација. diff --git a/apps/browser/store/locales/sv/copy.resx b/apps/browser/store/locales/sv/copy.resx index 8f3564f30c3..410bf890b16 100644 --- a/apps/browser/store/locales/sv/copy.resx +++ b/apps/browser/store/locales/sv/copy.resx @@ -144,7 +144,7 @@ Använd Bitwarden för att säkra din personalstyrka och dela känslig informati Fler anledningar att välja Bitwarden: Kryptering i världsklass -Lösenord skyddas med avancerad end-to-end-kryptering (AES-256 bit, salted hashtag och PBKDF2 SHA-256) så att dina data förblir säkra och privata. +Lösenord skyddas med avancerad end-to-end-kryptering (AES-256 bit, salted hashing och PBKDF2 SHA-256) så att dina data förblir säkra och privata. revisioner från tredje part Bitwarden genomför regelbundet omfattande tredjeparts säkerhetsrevisioner med välkända säkerhetsföretag. Dessa årliga revisioner inkluderar källkodsbedömningar och penetrationstestning över Bitwardens IP-adresser, servrar och webbapplikationer. diff --git a/apps/browser/store/locales/te/copy.resx b/apps/browser/store/locales/te/copy.resx index 82e4eb1d88e..377b13e7423 100644 --- a/apps/browser/store/locales/te/copy.resx +++ b/apps/browser/store/locales/te/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/th/copy.resx b/apps/browser/store/locales/th/copy.resx index f6b0c4b22ab..1473e24d92e 100644 --- a/apps/browser/store/locales/th/copy.resx +++ b/apps/browser/store/locales/th/copy.resx @@ -144,7 +144,7 @@ Use Bitwarden to secure your workforce and share sensitive information with coll More reasons to choose Bitwarden: World-Class Encryption -Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private. +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. 3rd-party Audits Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. diff --git a/apps/browser/store/locales/tr/copy.resx b/apps/browser/store/locales/tr/copy.resx index 6afe10ff32a..3585e50e2ac 100644 --- a/apps/browser/store/locales/tr/copy.resx +++ b/apps/browser/store/locales/tr/copy.resx @@ -143,7 +143,7 @@ Bitwarden'ı kullanarak çalışanlarınızı güvence altına alın ve hassas b Bitwarden'ı seçmek için daha fazla neden: Dünya Standartlarında Şifreleme -Şifreler, gelişmiş uçtan uca şifreleme (AES-256 bit, tuzlu hashtag ve PBKDF2 SHA-256) ile korunur, böylece verileriniz güvenli ve gizli kalır. +Şifreler, gelişmiş uçtan uca şifreleme (AES-256 bit, tuzlu hashing ve PBKDF2 SHA-256) ile korunur, böylece verileriniz güvenli ve gizli kalır. Üçüncü Taraf Denetimleri Bitwarden, tanınmış güvenlik firmalarıyla düzenli olarak kapsamlı üçüncü taraf güvenlik denetimleri gerçekleştirir. Bu yıllık denetimler, Bitwarden IP'leri, sunucuları ve web uygulamaları genelinde kaynak kodu değerlendirmeleri ve sızma testlerini içerir. @@ -164,7 +164,8 @@ Bitwarden çevirileri, Crowdin aracılığıyla küresel topluluk tarafından 60 Bitwarden Vault'unuzdaki hassas verileri herhangi bir tarayıcı, mobil cihaz, masaüstü işletim sistemi ve daha fazlasından güvenli bir şekilde paylaşın. Bitwarden, şifrelerden daha fazlasını güvence altına alır -Bitwarden'ın uçtan uca şifrelenmiş kimlik bilgisi yönetimi çözümleri, kuruluşların geliştirici sırları ve anahtar deneyimleri dahil her şeyi güvence altına almasını sağlar. Bitwarden Secrets Manager ve Bitwarden Passwordless.dev hakkında daha fazla bilgi edinmek için Bitwarden.com adresini ziyaret edin! +Bitwarden'ın uçtan uca şifrelenmiş kimlik bilgisi yönetimi çözümleri, kuruluşların geliştirici sırları ve anahtar deneyimleri dahil her şeyi güvence altına almasını sağlar. Bitwarden Secrets Manager ve Bitwarden Passwordless.dev hakkında daha fazla bilgi edinmek için Bitwarden.com adresini ziyaret edin! + İster evde ister işte veya yolda olun; Bitwarden tüm parolalarınızı, geçiş anahtarlarınızı ve hassas bilgilerinizi güvenle saklar. diff --git a/apps/browser/store/locales/vi/copy.resx b/apps/browser/store/locales/vi/copy.resx index dd3e258a7c7..48c8f483050 100644 --- a/apps/browser/store/locales/vi/copy.resx +++ b/apps/browser/store/locales/vi/copy.resx @@ -144,7 +144,7 @@ Sử dụng Bitwarden để bảo vệ nhân viên của bạn và chia sẻ th Thêm những lý do để chọn Bitwarden: Mã hóa hàng đầu thế giới -Mật khẩu được bảo vệ bằng mã hóa end-to-end tiên tiến (AES-256 bit, salted hashtag và PBKDF2 SHA-256) để dữ liệu của bạn luôn an toàn và riêng tư. +Mật khẩu được bảo vệ bằng mã hóa end-to-end tiên tiến (AES-256 bit, salted hashing và PBKDF2 SHA-256) để dữ liệu của bạn luôn an toàn và riêng tư. Kiểm toán bảo mật bởi bên thứ ba Bitwarden thường xuyên thực hiện các cuộc kiểm toán bảo mật toàn diện bởi các công ty bảo mật uy tín. Các cuộc kiểm toán hàng năm này bao gồm đánh giá mã nguồn và thử nghiệm xâm nhập trên các tài sản trí tuệ (IP), máy chủ và ứng dụng web của Bitwarden. diff --git a/apps/browser/store/locales/zh_CN/copy.resx b/apps/browser/store/locales/zh_CN/copy.resx index c66c6fdb411..dd611f4ca68 100644 --- a/apps/browser/store/locales/zh_CN/copy.resx +++ b/apps/browser/store/locales/zh_CN/copy.resx @@ -124,48 +124,49 @@ 无论是在家中、工作中还是在旅途中,Bitwarden 都可以轻松地保护您的所有密码、通行密钥和敏感信息。 - 被 PCMag、WIRED、The Verge、CNET、G2 等评为最佳的密码管理器! + Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more! -保护您的数字生活 -通过为每个账户生成并保存唯一而强大的密码,保护您的数字生活并防止数据泄露。所有内容保存在只有您可以访问的端对端加密的密码库中。 +SECURE YOUR DIGITAL LIFE +Secure your digital life and protect against data breaches by generating and saving unique, strong passwords for every account. Maintain everything in an end-to-end encrypted password vault that only you can access. -随时随地在任何设备上访问您的数据 -不受任何限制,跨无限数量的设备,轻松地管理、存储、保护和分享不限数量的密码。 +ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE +Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions. -每个人都应该拥有的保持在线安全的工具 -使用 Bitwarden 是免费的,没有广告,不会出售数据。Bitwarden 相信每个人都应该拥有保持在线安全的能力。高级计划提供了对高级功能的访问。 +EVERYONE SHOULD HAVE THE TOOLS TO STAY SAFE ONLINE +Utilize Bitwarden for free with no ads or selling data. Bitwarden believes everyone should have the ability to stay safe online. Premium plans offer access to advanced features. -使用 Bitwarden 为您的团队提供支持 -团队计划和企业计划具有专业的商业功能。例如 SSO 集成、自托管、目录集成,以及 SCIM 配置、全局策略、API 访问、事件日志等。 +EMPOWER YOUR TEAMS WITH BITWARDEN +Plans for Teams and Enterprise come with professional business features. Some examples include SSO integration, self-hosting, directory integration and SCIM provisioning, global policies, API access, event logs, and more. -使用 Bitwarden 保护您的劳动成果,并与同事共享敏感信息。 +Use Bitwarden to secure your workforce and share sensitive information with colleagues. -选择 Bitwarden 的更多理由: +More reasons to choose Bitwarden: -世界级加密 -密码受到先进的端对端加密(AES-256 位、加盐哈希标签和 PBKDF2 SHA-256)保护,使您的数据保持安全和私密。 +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. -第三方审计 -Bitwarden 定期与知名的安全公司进行全面的第三方安全审计。这些年度审计包括对 Bitwarden IP、服务器和 Web 应用程序的源代码评估和渗透测试。 +3rd-party Audits +Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. -高级 2FA -使用第三方验证器、电子邮件代码或 FIDO2 WebAuthn 凭据(例如硬件安全密钥或通行密钥)保护您的登录。 +Advanced 2FA +Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey. Bitwarden Send -直接传输数据给他人,同时保持端对端加密的安全性并防止暴露。 +Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure. -内置生成器 -为您访问的每个网站创建足够长、足够复杂且唯一的密码和用户名。与电子邮件别名提供商集成,增加隐私保护。 +Built-in Generator +Create long, complex, and distinct passwords and unique usernames for every site you visit. Integrate with email alias providers for additional privacy. -全球翻译 -Bitwarden 的翻译涵盖 60 多种语言,由全球社区使用 Crowdin 翻译。 +Global Translations +Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin. -跨平台应用程序 -从任何浏览器、移动设备或桌面操作系统中安全地访问和共享 Bitwarden 密码库中的敏感数据。 +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. -Bitwarden 保护的不仅仅是密码 -Bitwarden 的端对端加密凭据管理解决方案使组织能够保护所有内容,包括开发人员机密和通行密钥体验。访问 Bitwarden.com 进一步了解 Bitwarden Secrets Manager 和 Bitwarden Passwordless.dev! +Bitwarden secures more than just passwords +End-to-end encrypted credential management solutions from Bitwarden empower organizations to secure everything, including developer secrets and passkey experiences. Visit Bitwarden.com to learn more about Bitwarden Secrets Manager and Bitwarden Passwordless.dev! + 无论是在家中、工作中还是在旅途中,Bitwarden 都可以轻松地保护您的所有密码、通行密钥和敏感信息。 diff --git a/apps/browser/store/locales/zh_TW/copy.resx b/apps/browser/store/locales/zh_TW/copy.resx index eaac9ee8691..ad3f12ae6f0 100644 --- a/apps/browser/store/locales/zh_TW/copy.resx +++ b/apps/browser/store/locales/zh_TW/copy.resx @@ -124,48 +124,48 @@ 無論在家、在辦公或在途中,Bitwarden 都能輕易的保護你的密碼、登入金鑰和敏感資訊。 - 被 PCMag、WIRED、The Verge、CNET、G2 等認可為最佳的密碼管理器! + Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more! -保護您的數位生活 -透過為每個帳戶產生並保存唯一的強密碼,保護您的數位生活並防止資料外洩。將所有內容保存在只有您可以存取的端對端加密密碼庫中。 +SECURE YOUR DIGITAL LIFE +Secure your digital life and protect against data breaches by generating and saving unique, strong passwords for every account. Maintain everything in an end-to-end encrypted password vault that only you can access. -隨時隨地在任何裝置上存取您的數據 -不受限制地跨裝置輕鬆管理、儲存、保護和分享無限多的密碼。 +ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE +Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions. -每個人都應該擁有保持上網安全的工具 -免費使用 Bitwarden,沒有廣告或銷售資料。Bitwarden 認為每個人都應該有能力確保上網安全。進階版計劃提供對進階功能的存取。 +EVERYONE SHOULD HAVE THE TOOLS TO STAY SAFE ONLINE +Utilize Bitwarden for free with no ads or selling data. Bitwarden believes everyone should have the ability to stay safe online. Premium plans offer access to advanced features. -透過 BITWARDEN 強化您的團隊 -團隊和企業計劃具有專業的商業功能。包括 SSO 整合、自架服務、目錄整合和 SCIM 配置、全域政策、API 存取、事件日誌等。 +EMPOWER YOUR TEAMS WITH BITWARDEN +Plans for Teams and Enterprise come with professional business features. Some examples include SSO integration, self-hosting, directory integration and SCIM provisioning, global policies, API access, event logs, and more. -使用 Bitwarden 來保護您的員工並與同事分享敏感資訊。 +Use Bitwarden to secure your workforce and share sensitive information with colleagues. -選擇 Bitwarden 的其他理由: +More reasons to choose Bitwarden: -世界級的加密 -密碼受到進階端對端加密(AES-256 位元、加鹽標籤和 PBKDF2 SHA-256)的保護,因此您的資料保持安全和私密。 +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. -第三方審核 -Bitwarden 定期與知名資安公司進行全面的第三方安全稽核。這些年度稽核包括 Bitwarden IP、伺服器和 Web 應用程式的原始程式碼評估和滲透測試。 +3rd-party Audits +Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications. -進階的雙因子驗證 -使用第三方驗證器、透過電子郵件傳送的代碼或 FIDO2 WebAuthn 憑證(例如硬體安全金鑰或密碼)來保護您的登入。 +Advanced 2FA +Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey. -Bitwarden 傳送 -直接將資料傳輸給其他人,同時保持端對端加密安全性並限制暴露。 +Bitwarden Send +Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure. -內建產生器 -為您造訪的每個網站建立長、複雜且獨特的密碼和唯一的使用者名稱。與電子郵件別名提供者整合以獲得額外的隱私。 +Built-in Generator +Create long, complex, and distinct passwords and unique usernames for every site you visit. Integrate with email alias providers for additional privacy. -全球翻譯 -Bitwarden 有 60 多種語言翻譯,由全球社群透過 Crowdin 翻譯。 +Global Translations +Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin. -跨平台應用程式 -透過任何瀏覽器、行動裝置或桌面作業系統等保護和共用 Bitwarden 密碼庫中的敏感資料。 +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. -Bitwarden 保護的不僅是密碼 -Bitwarden 的端對端加密憑證管理解決方案可讓組織保護一切,包括開發人員機密和金鑰體驗。請造訪 Bitwarden.com 以了解更多有關 Bitwarden 機密管理員和 Bitwarden Passwordless.dev 的資訊! +Bitwarden secures more than just passwords +End-to-end encrypted credential management solutions from Bitwarden empower organizations to secure everything, including developer secrets and passkey experiences. Visit Bitwarden.com to learn more about Bitwarden Secrets Manager and Bitwarden Passwordless.dev! From cfa8615c289982ef992940a7f2ad4beeb2761777 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Tue, 26 Aug 2025 13:51:31 +0000 Subject: [PATCH 046/167] Autosync the updated translations (#16158) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/desktop/src/locales/he/messages.json | 182 +++++++++++----------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/apps/desktop/src/locales/he/messages.json b/apps/desktop/src/locales/he/messages.json index 7f9cb69ce00..bb5377fd12b 100644 --- a/apps/desktop/src/locales/he/messages.json +++ b/apps/desktop/src/locales/he/messages.json @@ -244,13 +244,13 @@ "message": "סוכן ה־SSH הוא שירות המיועד למפתחים שמאפשר לך לחתום בקשות SSH היישר מכספת ה־Bitwarden שלך." }, "sshAgentPromptBehavior": { - "message": "Ask for authorization when using SSH agent" + "message": "בקשת אישור בעת שימוש בסוכן SSH" }, "sshAgentPromptBehaviorDesc": { - "message": "Choose how to handle SSH-agent authorization requests." + "message": "בחר איך לטפל בבקשות אישור של סוכן SSH." }, "sshAgentPromptBehaviorHelp": { - "message": "Remember SSH authorizations" + "message": "זכור בקשות אישור של SSH" }, "sshAgentPromptBehaviorAlways": { "message": "תמיד" @@ -259,7 +259,7 @@ "message": "אף פעם" }, "sshAgentPromptBehaviorRememberUntilLock": { - "message": "Remember until vault is locked" + "message": "זכור עד שהכספת נעולה" }, "premiumRequired": { "message": "נדרש חשבון פרימיום" @@ -718,7 +718,7 @@ "message": "גודל הקובץ המירבי הוא 500 מגה." }, "legacyEncryptionUnsupported": { - "message": "Legacy encryption is no longer supported. Please contact support to recover your account." + "message": "הצפנה מהדור הקודם אינה נתמכת עוד. אנא צור קשר עם צוות התמיכה כדי לשחזר את חשבונך." }, "editedFolder": { "message": "תיקייה שנשמרה" @@ -1749,7 +1749,7 @@ "message": "מוגבל חשבון" }, "restrictCardTypeImport": { - "message": "Cannot import card item types" + "message": "לא ניתן לייבא סוגי פריטי כרטיסים" }, "restrictCardTypeImportDesc": { "message": "A policy set by 1 or more organizations prevents you from importing cards to your vaults." @@ -2534,7 +2534,7 @@ } }, "vaultTimeoutPolicyMaximumError": { - "message": "Timeout exceeds the restriction set by your organization: $HOURS$ hour(s) and $MINUTES$ minute(s) maximum", + "message": "פסק זמן חורג את ההגבלה שהוגדרה על ידי הארגון שלך: $HOURS$ שעות ו־$MINUTES$ דקות לכל היותר", "placeholders": { "hours": { "content": "$1", @@ -2574,10 +2574,10 @@ "message": "A master password is no longer required for members of the following organization. Please confirm the domain below with your organization administrator." }, "organizationName": { - "message": "Organization name" + "message": "שם הארגון" }, "keyConnectorDomain": { - "message": "Key Connector domain" + "message": "הדומיין של Key Connector" }, "leaveOrganization": { "message": "עזוב ארגון" @@ -2640,7 +2640,7 @@ } }, "exportingIndividualVaultWithAttachmentsDescription": { - "message": "Only the individual vault items including attachments associated with $EMAIL$ will be exported. Organization vault items will not be included", + "message": "רק פריטי הכספת האישיים, כולל קבצים מצורפים המשוייכים עם $EMAIL$ ייוצאו. פריטי כספת ארגוניים לא ייכללו", "placeholders": { "email": { "content": "$1", @@ -2689,7 +2689,7 @@ "message": "צור דוא\"ל" }, "usernameGenerator": { - "message": "Username generator" + "message": "מחולל שם משתמש" }, "generatePassword": { "message": "צור סיסמה" @@ -2698,16 +2698,16 @@ "message": "צור ביטוי סיסמה" }, "passwordGenerated": { - "message": "Password generated" + "message": "נוצרה סיסמה" }, "passphraseGenerated": { - "message": "Passphrase generated" + "message": "נוצר ביטוי סיסמה" }, "usernameGenerated": { - "message": "Username generated" + "message": "נוצר שם משתמש" }, "emailGenerated": { - "message": "Email generated" + "message": "נוצר דוא\"ל" }, "spinboxBoundariesHint": { "message": "הערך חייב להיות בין $MIN$ ל־$MAX$.", @@ -2766,7 +2766,7 @@ "message": "השתמש בסיסמה זו" }, "useThisPassphrase": { - "message": "Use this passphrase" + "message": "השתמש בביטוי סיסמא זה" }, "useThisUsername": { "message": "השתמש בשם משתמש זה" @@ -3037,7 +3037,7 @@ } }, "loginRequestApprovedForEmailOnDevice": { - "message": "Login request approved for $EMAIL$ on $DEVICE$", + "message": "בקשת הכניסה אושרה עבור $EMAIL$ ב־$DEVICE$", "placeholders": { "email": { "content": "$1", @@ -3050,21 +3050,21 @@ } }, "youDeniedLoginAttemptFromAnotherDevice": { - "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + "message": "דחית ניסיון כניסה ממכשיר אחר. אם זה היית אתה, נסה להיכנס עם המכשיר שוב." }, "webApp": { - "message": "Web app" + "message": "אפליקציית אינטרנט" }, "mobile": { - "message": "Mobile", + "message": "נייד", "description": "Mobile app" }, "extension": { - "message": "Extension", + "message": "הרחבה", "description": "Browser extension/addon" }, "desktop": { - "message": "Desktop", + "message": "שולחן עבודה", "description": "Desktop app" }, "cli": { @@ -3075,10 +3075,10 @@ "description": "Software Development Kit" }, "server": { - "message": "Server" + "message": "שרת" }, "loginRequest": { - "message": "Login request" + "message": "בקשת כניסה" }, "deviceType": { "message": "סוג מכשיר" @@ -3222,7 +3222,7 @@ "message": "בקש אישור מנהל" }, "unableToCompleteLogin": { - "message": "Unable to complete login" + "message": "לא ניתן להשלים את ההתחברות" }, "loginOnTrustedDeviceOrAskAdminToAssignPassword": { "message": "You need to log in on a trusted device or ask your administrator to assign you a password." @@ -3268,16 +3268,16 @@ "message": "מכשיר מהימן" }, "trustOrganization": { - "message": "Trust organization" + "message": "סמוך על הארגון" }, "trust": { - "message": "Trust" + "message": "סמוך" }, "doNotTrust": { - "message": "Do not trust" + "message": "אל תסמוך" }, "organizationNotTrusted": { - "message": "Organization is not trusted" + "message": "הארגון אינו אמין" }, "emergencyAccessTrustWarning": { "message": "For the security of your account, only confirm if you have granted emergency access to this user and their fingerprint matches what is displayed in their account" @@ -3289,7 +3289,7 @@ "message": "This organization has an Enterprise policy that will enroll you in account recovery. Enrollment will allow organization administrators to change your password. Only proceed if you recognize this organization and the fingerprint phrase displayed below matches the organization's fingerprint." }, "trustUser": { - "message": "Trust user" + "message": "סמוך על המשתמש" }, "inputRequired": { "message": "נדרש קלט." @@ -3492,10 +3492,10 @@ "message": "בחר אוסף" }, "importTargetHintCollection": { - "message": "Select this option if you want the imported file contents moved to a collection" + "message": "בחר באפשרות זו אם ברצונך להעביר את תוכן הקובץ המיובא לאוסף" }, "importTargetHintFolder": { - "message": "Select this option if you want the imported file contents moved to a folder" + "message": "בחר באפשרות זו אם ברצונך להעביר את תוכן הקובץ המיובא לתיקייה" }, "importUnassignedItemsError": { "message": "קובץ מכיל פריטים לא מוקצים." @@ -3627,15 +3627,15 @@ "description": "Content for dialog which warns a user when selecting 'starts with' matching strategy as a cipher match strategy" }, "uriMatchWarningDialogLink": { - "message": "More about match detection", + "message": "עוד על זיהוי התאמה", "description": "Link to match detection docs on warning dialog for advance match strategy" }, "uriAdvancedOption": { - "message": "Advanced options", + "message": "אפשרויות מתקדמות", "description": "Advanced option placeholder for uri option component" }, "warningCapitalized": { - "message": "Warning", + "message": "אזהרה", "description": "Warning (should maintain locale-relevant capitalization)" }, "success": { @@ -3709,14 +3709,14 @@ "message": "לא נמצאו יציאות פנויות עבור כניסת ה־sso." }, "securePasswordGenerated": { - "message": "Secure password generated! Don't forget to also update your password on the website." + "message": "סיסמה מאובטחת נוצרה! אל תשכח גם לעדכן את הסיסמה שלך באתר האינטרנט." }, "useGeneratorHelpTextPartOne": { - "message": "Use the generator", + "message": "השתמש במחולל", "description": "This will be used as part of a larger sentence, broken up to include the generator icon. The full sentence will read 'Use the generator [GENERATOR_ICON] to create a strong unique password'" }, "useGeneratorHelpTextPartTwo": { - "message": "to create a strong unique password", + "message": "כדי ליצור סיסמה חזקה וייחודית", "description": "This will be used as part of a larger sentence, broken up to include the generator icon. The full sentence will read 'Use the generator [GENERATOR_ICON] to create a strong unique password'" }, "biometricsStatusHelptextUnlockNeeded": { @@ -3744,25 +3744,25 @@ "message": "ביטול נעילה ביומטרי אינו זמין כעת מסיבה לא ידועה." }, "itemDetails": { - "message": "Item details" + "message": "פרטי הפריט" }, "itemName": { - "message": "Item name" + "message": "שם הפריט" }, "loginCredentials": { - "message": "Login credentials" + "message": "אישורי כניסה" }, "additionalOptions": { - "message": "Additional options" + "message": "אפשרויות נוספות" }, "itemHistory": { - "message": "Item history" + "message": "היסטוריית פריט" }, "lastEdited": { - "message": "Last edited" + "message": "נערך לאחרונה" }, "upload": { - "message": "Upload" + "message": "העלה" }, "authorize": { "message": "אשר" @@ -3834,7 +3834,7 @@ "message": "שנה סיסמה בסיכון" }, "cannotRemoveViewOnlyCollections": { - "message": "You cannot remove collections with View only permissions: $COLLECTIONS$", + "message": "אינך יכול להסיר אוספים עם הרשאות צפייה בלבד: $COLLECTIONS$", "placeholders": { "collections": { "content": "$1", @@ -3843,114 +3843,114 @@ } }, "move": { - "message": "Move" + "message": "העבר" }, "newFolder": { - "message": "New folder" + "message": "תיקייה חדשה" }, "folderName": { - "message": "Folder Name" + "message": "שם התיקייה" }, "folderHintText": { - "message": "Nest a folder by adding the parent folder's name followed by a “/”. Example: Social/Forums" + "message": "צור תיקייה מקוננת על ידי הוספת שם תיקיית האב ואחריו “/”. דוגמה: חברתי/פורומים" }, "sendsTitleNoItems": { - "message": "Send sensitive information safely", + "message": "שלח מידע רגיש באופן בטוח", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendsBodyNoItems": { - "message": "Share files and data securely with anyone, on any platform. Your information will remain end-to-end encrypted while limiting exposure.", + "message": "שתף קבצים ונתונים באופן מאובטח עם כל אחד, בכל פלטפורמה. המידע שלך יישאר מוצפן מקצה־לקצה תוך הגבלת חשיפה.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "generatorNudgeTitle": { - "message": "Quickly create passwords" + "message": "צור סיסמאות במהירות" }, "generatorNudgeBodyOne": { - "message": "Easily create strong and unique passwords by clicking on", + "message": "צור סיסמאות חזקות וייחודיות בקלות על ידי לחיצה על", "description": "Two part message", "example": "Easily create strong and unique passwords by clicking on {icon} to help you keep your logins secure." }, "generatorNudgeBodyTwo": { - "message": "to help you keep your logins secure.", + "message": "כדי לעזור לך לשמור על אבטחת הכניסות שלך.", "description": "Two part message", "example": "Easily create strong and unique passwords by clicking on {icon} to help you keep your logins secure." }, "generatorNudgeBodyAria": { - "message": "Easily create strong and unique passwords by clicking on the Generate password button to help you keep your logins secure.", + "message": "צור סיסמאות חזקות וייחודיות בקלות על ידי לחיצה על כפתור \"צור סיסמא\" כדי לעזור לך לשמור על אבטחת הכניסות שלך.", "description": "Aria label for the body content of the generator nudge" }, "newLoginNudgeTitle": { - "message": "Save time with autofill" + "message": "חסוך זמן עם מילוי אוטומטי" }, "newLoginNudgeBodyOne": { - "message": "Include a", + "message": "כלול", "description": "This is in multiple parts to allow for bold text in the middle of the sentence.", "example": "Include a Website so this login appears as an autofill suggestion." }, "newLoginNudgeBodyBold": { - "message": "Website", + "message": "אתר אינטרנט", "description": "This is in multiple parts to allow for bold text in the middle of the sentence.", "example": "Include a Website so this login appears as an autofill suggestion." }, "newLoginNudgeBodyTwo": { - "message": "so this login appears as an autofill suggestion.", + "message": "כדי שהכניסה הזו תופיע כהצעת מילוי אוטומטי.", "description": "This is in multiple parts to allow for bold text in the middle of the sentence.", "example": "Include a Website so this login appears as an autofill suggestion." }, "newCardNudgeTitle": { - "message": "Seamless online checkout" + "message": "תשלום מקוון חלק" }, "newCardNudgeBody": { - "message": "With cards, easily autofill payment forms securely and accurately." + "message": "עם כרטיסים, ניתן למלא טפסי תשלום באופן אוטומטי בצורה מאובטחת ומדויקת." }, "newIdentityNudgeTitle": { - "message": "Simplify creating accounts" + "message": "יצירת חשבונות בקלות" }, "newIdentityNudgeBody": { - "message": "With identities, quickly autofill long registration or contact forms." + "message": "עם זהויות, ניתן למלא באופן אוטומטי ובמהירות טפסי הרשמה או יצירת קשר ארוכים." }, "newNoteNudgeTitle": { - "message": "Keep your sensitive data safe" + "message": "שמור על הנתונים הרגישים שלך בטוחים" }, "newNoteNudgeBody": { - "message": "With notes, securely store sensitive data like banking or insurance details." + "message": "עם הערות, ניתן לאחסן בצורה מאובטחת נתונים רגישים כמו פרטי בנק או ביטוח." }, "newSshNudgeTitle": { - "message": "Developer-friendly SSH access" + "message": "גישת SSH ידידותית למפתחים" }, "newSshNudgeBodyOne": { - "message": "Store your keys and connect with the SSH agent for fast, encrypted authentication.", + "message": "אחסן את המפתחות שלך והתחבר לסוכן SSH בשביל אימות מהיר ומוצפן.", "description": "Two part message", "example": "Store your keys and connect with the SSH agent for fast, encrypted authentication. Learn more about SSH agent" }, "newSshNudgeBodyTwo": { - "message": "Learn more about SSH agent", + "message": "למד עוד על סוכן SSH", "description": "Two part message", "example": "Store your keys and connect with the SSH agent for fast, encrypted authentication. Learn more about SSH agent" }, "assignToCollections": { - "message": "Assign to collections" + "message": "הקצה לאוספים" }, "assignToTheseCollections": { - "message": "Assign to these collections" + "message": "הקצה לאוספים אלה" }, "bulkCollectionAssignmentDialogDescriptionSingular": { - "message": "Only organization members with access to these collections will be able to see the item." + "message": "רק חברי ארגון עם גישה לאוספים אלה יוכלו לראות את הפריט." }, "bulkCollectionAssignmentDialogDescriptionPlural": { - "message": "Only organization members with access to these collections will be able to see the items." + "message": "רק חברי ארגון עם גישה לאוספים אלה יוכלו לראות את הפריטים." }, "noCollectionsAssigned": { - "message": "No collections have been assigned" + "message": "לא הוקצו אוספים" }, "assign": { - "message": "Assign" + "message": "הקצה" }, "bulkCollectionAssignmentDialogDescription": { - "message": "Only organization members with access to these collections will be able to see the items." + "message": "רק חברי ארגון עם גישה לאוספים אלה יוכלו לראות את הפריטים." }, "bulkCollectionAssignmentWarning": { - "message": "You have selected $TOTAL_COUNT$ items. You cannot update $READONLY_COUNT$ of the items because you do not have edit permissions.", + "message": "בחרת ב־$TOTAL_COUNT$ פריטים. אינך יכול לעדכן $READONLY_COUNT$ מהפריטים בגלל שאין לך הרשאות עריכה.", "placeholders": { "total_count": { "content": "$1", @@ -3962,10 +3962,10 @@ } }, "selectCollectionsToAssign": { - "message": "Select collections to assign" + "message": "בחר אוספים להקצות" }, "personalItemsTransferWarning": { - "message": "$PERSONAL_ITEMS_COUNT$ will be permanently transferred to the selected organization. You will no longer own these items.", + "message": "$PERSONAL_ITEMS_COUNT$ יועברו לצמיתות לארגון הנבחר. לא תהיה יותר הבעלים של הפריטים האלה.", "placeholders": { "personal_items_count": { "content": "$1", @@ -3974,7 +3974,7 @@ } }, "personalItemsWithOrgTransferWarning": { - "message": "$PERSONAL_ITEMS_COUNT$ will be permanently transferred to $ORG$. You will no longer own these items.", + "message": "$PERSONAL_ITEMS_COUNT$ יועברו לצמיתות אל $ORG$. לא תהיה יותר הבעלים של הפריטים האלה.", "placeholders": { "personal_items_count": { "content": "$1", @@ -3987,10 +3987,10 @@ } }, "personalItemTransferWarningSingular": { - "message": "1 item will be permanently transferred to the selected organization. You will no longer own this item." + "message": "פריט 1 יועבר לצמיתות לארגון הנבחר. לא תהיה יותר הבעלים של הפריט הזה." }, "personalItemWithOrgTransferWarningSingular": { - "message": "1 item will be permanently transferred to $ORG$. You will no longer own this item.", + "message": "פריט 1 יועבר לצמיתות אל $ORG$. לא תהיה יותר הבעלים של הפריט הזה.", "placeholders": { "org": { "content": "$1", @@ -3999,13 +3999,13 @@ } }, "successfullyAssignedCollections": { - "message": "Successfully assigned collections" + "message": "אוספים הוקצו בהצלחה" }, "nothingSelected": { - "message": "You have not selected anything." + "message": "לא בחרת כלום." }, "itemsMovedToOrg": { - "message": "Items moved to $ORGNAME$", + "message": "פריטים הועברו אל $ORGNAME$", "placeholders": { "orgname": { "content": "$1", @@ -4014,7 +4014,7 @@ } }, "itemMovedToOrg": { - "message": "Item moved to $ORGNAME$", + "message": "פריט הועבר אל $ORGNAME$", "placeholders": { "orgname": { "content": "$1", @@ -4023,7 +4023,7 @@ } }, "movedItemsToOrg": { - "message": "Selected items moved to $ORGNAME$", + "message": "פריטים נבחרים הועברו אל $ORGNAME$", "placeholders": { "orgname": { "content": "$1", @@ -4063,19 +4063,19 @@ } }, "showMore": { - "message": "Show more" + "message": "הצג עוד" }, "showLess": { - "message": "Show less" + "message": "הצג פחות" }, "enableAutotype": { - "message": "Enable Autotype" + "message": "הפעל הקלדה אוטומטית" }, "enableAutotypeDescription": { "message": "Bitwarden לא מאמת את מקומות הקלט, נא לוודא שזה החלון והשדה הנכונים בטרם שימוש בקיצור הדרך." }, "moreBreadcrumbs": { - "message": "More breadcrumbs", + "message": "עוד נתיבי ניווט", "description": "This is used in the context of a breadcrumb navigation, indicating that there are more items in the breadcrumb trail that are not currently displayed." } } From 684299f0544d765eafac81a5d5103246e81657be Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 26 Aug 2025 11:18:52 -0400 Subject: [PATCH 047/167] [deps] AC: Update core-js to v3.45.0 (#16048) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Jimmy Vo --- apps/cli/package.json | 2 +- package-lock.json | 10 +++++----- package.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/cli/package.json b/apps/cli/package.json index 4964cd4e403..8c5b367cb61 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -69,7 +69,7 @@ "browser-hrtime": "1.1.8", "chalk": "4.1.2", "commander": "11.1.0", - "core-js": "3.44.0", + "core-js": "3.45.0", "form-data": "4.0.4", "https-proxy-agent": "7.0.6", "inquirer": "8.2.6", diff --git a/package-lock.json b/package-lock.json index 5f4aedffd1f..c414adb416d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "bufferutil": "4.0.9", "chalk": "4.1.2", "commander": "11.1.0", - "core-js": "3.44.0", + "core-js": "3.45.0", "form-data": "4.0.4", "https-proxy-agent": "7.0.6", "inquirer": "8.2.6", @@ -204,7 +204,7 @@ "browser-hrtime": "1.1.8", "chalk": "4.1.2", "commander": "11.1.0", - "core-js": "3.44.0", + "core-js": "3.45.0", "form-data": "4.0.4", "https-proxy-agent": "7.0.6", "inquirer": "8.2.6", @@ -18802,9 +18802,9 @@ } }, "node_modules/core-js": { - "version": "3.44.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.44.0.tgz", - "integrity": "sha512-aFCtd4l6GvAXwVEh3XbbVqJGHDJt0OZRa+5ePGx3LLwi12WfexqQxcsohb2wgsa/92xtl19Hd66G/L+TaAxDMw==", + "version": "3.45.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.0.tgz", + "integrity": "sha512-c2KZL9lP4DjkN3hk/an4pWn5b5ZefhRJnAc42n6LJ19kSnbeRbdQZE5dSeE2LBol1OwJD3X1BQvFTAsa8ReeDA==", "hasInstallScript": true, "license": "MIT", "funding": { diff --git a/package.json b/package.json index 331292b9076..bf6be11a616 100644 --- a/package.json +++ b/package.json @@ -176,7 +176,7 @@ "bufferutil": "4.0.9", "chalk": "4.1.2", "commander": "11.1.0", - "core-js": "3.44.0", + "core-js": "3.45.0", "form-data": "4.0.4", "https-proxy-agent": "7.0.6", "inquirer": "8.2.6", From 492e2b8d06ac45ca92d1da7139905e74348db643 Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Tue, 26 Aug 2025 17:27:41 +0200 Subject: [PATCH 048/167] Enable the angular check (#15210) Enables the angular check introduced by #15168. --- apps/browser/webpack.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/browser/webpack.config.js b/apps/browser/webpack.config.js index 551225231f7..e62f90354d2 100644 --- a/apps/browser/webpack.config.js +++ b/apps/browser/webpack.config.js @@ -392,7 +392,7 @@ if (manifestVersion == 2) { cache: true, }, dependencies: ["main"], - plugins: [...requiredPlugins /*new AngularCheckPlugin()*/], // TODO (PM-22630): Re-enable this plugin when angular is removed from the background script. + plugins: [...requiredPlugins, new AngularCheckPlugin()], }; // Safari's desktop build process requires a background.html and vendor.js file to exist From fb4f87958d532a8e5b848797b63142499c487e86 Mon Sep 17 00:00:00 2001 From: Miles Blackwood Date: Tue, 26 Aug 2025 11:35:23 -0400 Subject: [PATCH 049/167] Uses setTimeout to shim requestIdleCallback (#16143) * Makes inline menu handler async to resolve Safari issue. * Don't use idle callback deadline as timeout delay. * Revert "Makes inline menu handler async to resolve Safari issue." This reverts commit d3f7461cfaae440f33d5be48278c01e5d6f74dde. --------- Co-authored-by: Robyn MacCallum --- apps/browser/src/autofill/utils/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/browser/src/autofill/utils/index.ts b/apps/browser/src/autofill/utils/index.ts index 614a5b014f2..0e102dcfd99 100644 --- a/apps/browser/src/autofill/utils/index.ts +++ b/apps/browser/src/autofill/utils/index.ts @@ -37,9 +37,7 @@ export function requestIdleCallbackPolyfill( return globalThis.requestIdleCallback(() => callback(), options); } - const timeoutDelay = options?.timeout || 1; - - return globalThis.setTimeout(() => callback(), timeoutDelay); + return globalThis.setTimeout(() => callback(), 1); } /** From ad2dfe1e99c151e068c58665d75d43389aa581ea Mon Sep 17 00:00:00 2001 From: Todd Martin <106564991+trmartin4@users.noreply.github.com> Date: Tue, 26 Aug 2025 11:41:15 -0400 Subject: [PATCH 050/167] feat(notifications): [PM-19388] Enable push notifications on locked clients * Add back notifications connection on locked accounts * Updated tests. * Make sure web push connection service is started synchronously * Fixed merge conflicts. --------- Co-authored-by: Justin Baur <19896123+justindbaur@users.noreply.github.com> --- .../browser/src/background/main.background.ts | 7 +++-- .../src/services/jslib-services.module.ts | 1 + libs/common/src/enums/feature-flag.enum.ts | 2 ++ .../default-notifications.service.spec.ts | 21 +++++++------- .../default-server-notifications.service.ts | 28 ++++++++++++++----- 5 files changed, 40 insertions(+), 19 deletions(-) diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index c2c62625bb6..096bbe76e40 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -1125,6 +1125,7 @@ export default class MainBackground { new SignalRConnectionService(this.apiService, this.logService), this.authService, this.webPushConnectionService, + this.configService, ); this.fido2UserInterfaceService = new BrowserFido2UserInterfaceService(this.authService); @@ -1370,12 +1371,14 @@ export default class MainBackground { this.accountService, this.authService, ); - } - async bootstrap() { + // Synchronous startup if (this.webPushConnectionService instanceof WorkerWebPushConnectionService) { this.webPushConnectionService.start(); } + } + + async bootstrap() { this.containerService.attachToGlobal(self); await this.sdkLoadService.loadAndInit(); diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index fa7de5484d9..f62407eeafc 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -943,6 +943,7 @@ const safeProviders: SafeProvider[] = [ SignalRConnectionService, AuthServiceAbstraction, WebPushConnectionService, + ConfigService, ], }), safeProvider({ diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 7ab85139f4c..67f68e12847 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -53,6 +53,7 @@ export enum FeatureFlag { /* Platform */ IpcChannelFramework = "ipc-channel-framework", + PushNotificationsWhenLocked = "pm-19388-push-notifications-when-locked", } export type AllowedFeatureFlagTypes = boolean | number | string; @@ -112,6 +113,7 @@ export const DefaultFeatureFlagValue = { /* Platform */ [FeatureFlag.IpcChannelFramework]: FALSE, + [FeatureFlag.PushNotificationsWhenLocked]: FALSE, } satisfies Record; export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue; diff --git a/libs/common/src/platform/server-notifications/internal/default-notifications.service.spec.ts b/libs/common/src/platform/server-notifications/internal/default-notifications.service.spec.ts index 567e0fbfc3d..9f42328d573 100644 --- a/libs/common/src/platform/server-notifications/internal/default-notifications.service.spec.ts +++ b/libs/common/src/platform/server-notifications/internal/default-notifications.service.spec.ts @@ -1,5 +1,5 @@ import { mock, MockProxy } from "jest-mock-extended"; -import { BehaviorSubject, bufferCount, firstValueFrom, ObservedValueOf, Subject } from "rxjs"; +import { BehaviorSubject, bufferCount, firstValueFrom, ObservedValueOf, of, Subject } from "rxjs"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports @@ -14,6 +14,7 @@ import { NotificationType } from "../../../enums"; import { NotificationResponse } from "../../../models/response/notification.response"; import { UserId } from "../../../types/guid"; import { AppIdService } from "../../abstractions/app-id.service"; +import { ConfigService } from "../../abstractions/config/config.service"; import { Environment, EnvironmentService } from "../../abstractions/environment.service"; import { LogService } from "../../abstractions/log.service"; import { MessageSender } from "../../messaging"; @@ -38,6 +39,7 @@ describe("NotificationsService", () => { let signalRNotificationConnectionService: MockProxy; let authService: MockProxy; let webPushNotificationConnectionService: MockProxy; + let configService: MockProxy; let activeAccount: BehaviorSubject>; @@ -64,6 +66,9 @@ describe("NotificationsService", () => { signalRNotificationConnectionService = mock(); authService = mock(); webPushNotificationConnectionService = mock(); + configService = mock(); + + configService.getFeatureFlag$.mockReturnValue(of(true)); activeAccount = new BehaviorSubject>(null); accountService.activeAccount$ = activeAccount.asObservable(); @@ -104,6 +109,7 @@ describe("NotificationsService", () => { signalRNotificationConnectionService, authService, webPushNotificationConnectionService, + configService, ); }); @@ -227,10 +233,9 @@ describe("NotificationsService", () => { }); it.each([ - // Temporarily rolling back server notifications being connected while locked - // { initialStatus: AuthenticationStatus.Locked, updatedStatus: AuthenticationStatus.Unlocked }, - // { initialStatus: AuthenticationStatus.Unlocked, updatedStatus: AuthenticationStatus.Locked }, - // { initialStatus: AuthenticationStatus.Locked, updatedStatus: AuthenticationStatus.Locked }, + { initialStatus: AuthenticationStatus.Locked, updatedStatus: AuthenticationStatus.Unlocked }, + { initialStatus: AuthenticationStatus.Unlocked, updatedStatus: AuthenticationStatus.Locked }, + { initialStatus: AuthenticationStatus.Locked, updatedStatus: AuthenticationStatus.Locked }, { initialStatus: AuthenticationStatus.Unlocked, updatedStatus: AuthenticationStatus.Unlocked }, ])( "does not re-connect when the user transitions from $initialStatus to $updatedStatus", @@ -255,11 +260,7 @@ describe("NotificationsService", () => { }, ); - it.each([ - // Temporarily disabling server notifications connecting while in a locked state - // AuthenticationStatus.Locked, - AuthenticationStatus.Unlocked, - ])( + it.each([AuthenticationStatus.Locked, AuthenticationStatus.Unlocked])( "connects when a user transitions from logged out to %s", async (newStatus: AuthenticationStatus) => { emitActiveUser(mockUser1); diff --git a/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.ts b/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.ts index 4502d9663a3..d21074f5bbf 100644 --- a/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.ts +++ b/libs/common/src/platform/server-notifications/internal/default-server-notifications.service.ts @@ -14,6 +14,7 @@ import { // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports import { LogoutReason } from "@bitwarden/auth/common"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { AccountService } from "../../../auth/abstractions/account.service"; import { AuthService } from "../../../auth/abstractions/auth.service"; @@ -28,6 +29,7 @@ import { import { UserId } from "../../../types/guid"; import { SyncService } from "../../../vault/abstractions/sync/sync.service.abstraction"; import { AppIdService } from "../../abstractions/app-id.service"; +import { ConfigService } from "../../abstractions/config/config.service"; import { EnvironmentService } from "../../abstractions/environment.service"; import { LogService } from "../../abstractions/log.service"; import { MessagingService } from "../../abstractions/messaging.service"; @@ -55,6 +57,7 @@ export class DefaultServerNotificationsService implements ServerNotificationsSer private readonly signalRConnectionService: SignalRConnectionService, private readonly authService: AuthService, private readonly webPushConnectionService: WebPushConnectionService, + private readonly configService: ConfigService, ) { this.notifications$ = this.accountService.activeAccount$.pipe( map((account) => account?.id), @@ -132,14 +135,25 @@ export class DefaultServerNotificationsService implements ServerNotificationsSer ); } - // This method name is a lie currently as we also have an access token - // when locked, this is eventually where we want to be but it increases load - // on signalR so we are rolling back until we can move the load of browser to - // web push. private hasAccessToken$(userId: UserId) { - return this.authService.authStatusFor$(userId).pipe( - map((authStatus) => authStatus === AuthenticationStatus.Unlocked), - distinctUntilChanged(), + return this.configService.getFeatureFlag$(FeatureFlag.PushNotificationsWhenLocked).pipe( + switchMap((featureFlagEnabled) => { + if (featureFlagEnabled) { + return this.authService.authStatusFor$(userId).pipe( + map( + (authStatus) => + authStatus === AuthenticationStatus.Locked || + authStatus === AuthenticationStatus.Unlocked, + ), + distinctUntilChanged(), + ); + } else { + return this.authService.authStatusFor$(userId).pipe( + map((authStatus) => authStatus === AuthenticationStatus.Unlocked), + distinctUntilChanged(), + ); + } + }), ); } From 28b5a2bb5e0be182606c6127a5423e252a4d1a21 Mon Sep 17 00:00:00 2001 From: Brandon Treston Date: Tue, 26 Aug 2025 11:42:52 -0400 Subject: [PATCH 051/167] [PM-22717] Expose DefaultUserCollectionEmail to clients (#15643) * enforce restrictions based on collection type, set default collection type * fix ts strict errors * fix default collection enforcement in vault header * enforce default collection restrictions in vault collection row * enforce default collection restrictions in AC vault header * enforce default collection restriction for select all * fix ts strict error * switch to signal, fix feature flag * fix story * clean up * remove feature flag, move check for defaultCollecion to CollecitonView * fix test * remove unused configService * fix test: coerce null to undefined for collection Id * clean up leaky abstraction for default collection * fix ts-strict error * fix parens * add new property to models, update logic, refactor for ts-strict * fix type * rename defaultCollection getter * clean up * clean up * clean up, add comment, fix submit * add comment * add feature flag * check model for name * cleanup readonly logic, remove featureflag logic * wip * refactor CollectionRequest into Create and Update models * fix readonly logic * cleanup * set defaultUserCollectionEmail in decryption from Collection * split save into update/create methods * fix readonly logic * fix collections post and put requests * add defaultUserCollection email to model when submitting collection dialog --- apps/cli/src/commands/edit.command.ts | 4 +- apps/cli/src/vault/create.command.ts | 4 +- .../collections/utils/collection-utils.ts | 10 +- .../collection-dialog.component.ts | 30 +++++- apps/web/src/app/core/core.module.ts | 9 +- .../services/vault-filter.service.ts | 4 +- .../abstractions/collection-admin.service.ts | 6 +- .../models/collection-admin.view.ts | 12 +++ .../models/collection-with-id.request.ts | 15 ++- .../collections/models/collection.data.ts | 2 + .../collections/models/collection.request.ts | 48 +++++++-- .../collections/models/collection.response.ts | 2 + .../collections/models/collection.spec.ts | 6 +- .../common/collections/models/collection.ts | 2 + .../collections/models/collection.view.ts | 28 +++++- .../default-collection-admin.service.ts | 98 ++++++++++++++----- .../services/default-collection.service.ts | 2 +- libs/common/src/abstractions/api.service.ts | 7 +- libs/common/src/services/api.service.ts | 7 +- .../item-details-section.component.spec.ts | 31 +++--- 20 files changed, 248 insertions(+), 79 deletions(-) diff --git a/apps/cli/src/commands/edit.command.ts b/apps/cli/src/commands/edit.command.ts index 2e273d041d6..92674aa3dcd 100644 --- a/apps/cli/src/commands/edit.command.ts +++ b/apps/cli/src/commands/edit.command.ts @@ -2,7 +2,7 @@ // @ts-strict-ignore import { firstValueFrom, map, switchMap } from "rxjs"; -import { CollectionRequest } from "@bitwarden/admin-console/common"; +import { UpdateCollectionRequest } from "@bitwarden/admin-console/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; @@ -225,7 +225,7 @@ export class EditCommand { : req.users.map( (u) => new SelectionReadOnlyRequest(u.id, u.readOnly, u.hidePasswords, u.manage), ); - const request = new CollectionRequest({ + const request = new UpdateCollectionRequest({ name: await this.encryptService.encryptString(req.name, orgKey), externalId: req.externalId, users, diff --git a/apps/cli/src/vault/create.command.ts b/apps/cli/src/vault/create.command.ts index cbaae4d2544..0892bb42214 100644 --- a/apps/cli/src/vault/create.command.ts +++ b/apps/cli/src/vault/create.command.ts @@ -5,7 +5,7 @@ import * as path from "path"; import { firstValueFrom, map } from "rxjs"; -import { CollectionRequest } from "@bitwarden/admin-console/common"; +import { CreateCollectionRequest } from "@bitwarden/admin-console/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request"; @@ -233,7 +233,7 @@ export class CreateCommand { : req.users.map( (u) => new SelectionReadOnlyRequest(u.id, u.readOnly, u.hidePasswords, u.manage), ); - const request = new CollectionRequest({ + const request = new CreateCollectionRequest({ name: await this.encryptService.encryptString(req.name, orgKey), externalId: req.externalId, groups, diff --git a/apps/web/src/app/admin-console/organizations/collections/utils/collection-utils.ts b/apps/web/src/app/admin-console/organizations/collections/utils/collection-utils.ts index 8a0fab520e3..67cb4c7cdc8 100644 --- a/apps/web/src/app/admin-console/organizations/collections/utils/collection-utils.ts +++ b/apps/web/src/app/admin-console/organizations/collections/utils/collection-utils.ts @@ -45,9 +45,15 @@ export function cloneCollection( let cloned; if (collection instanceof CollectionAdminView) { - cloned = Object.assign(new CollectionAdminView({ ...collection }), collection); + cloned = Object.assign( + new CollectionAdminView({ ...collection, name: collection.name }), + collection, + ); } else { - cloned = Object.assign(new CollectionView({ ...collection }), collection); + cloned = Object.assign( + new CollectionView({ ...collection, name: collection.name }), + collection, + ); } return cloned; } diff --git a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts b/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts index 59d042cae52..52c418a5211 100644 --- a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts +++ b/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts @@ -398,6 +398,13 @@ export class CollectionDialogComponent implements OnInit, OnDestroy { } return; } + if ( + this.editMode && + !this.collection.canEditName(this.organization) && + this.formGroup.controls.name.dirty + ) { + throw new Error("Cannot change readonly field: Name"); + } const parent = this.formGroup.controls.parent?.value; const collectionView = new CollectionAdminView({ @@ -414,9 +421,13 @@ export class CollectionDialogComponent implements OnInit, OnDestroy { collectionView.users = this.formGroup.controls.access.value .filter((v) => v.type === AccessItemType.Member) .map(convertToSelectionView); + collectionView.defaultUserCollectionEmail = this.collection.defaultUserCollectionEmail; const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)); - const savedCollection = await this.collectionAdminService.save(collectionView, userId); + + const collectionResponse = this.editMode + ? await this.collectionAdminService.update(collectionView, userId) + : await this.collectionAdminService.create(collectionView, userId); this.toastService.showToast({ variant: "success", @@ -426,7 +437,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy { ), }); - this.close(CollectionDialogAction.Saved, savedCollection); + this.close(CollectionDialogAction.Saved, collectionResponse); }; protected delete = async () => { @@ -483,14 +494,23 @@ export class CollectionDialogComponent implements OnInit, OnDestroy { private handleFormGroupReadonly(readonly: boolean) { if (readonly) { + this.formGroup.controls.access.disable(); this.formGroup.controls.name.disable(); this.formGroup.controls.parent.disable(); - this.formGroup.controls.access.disable(); - } else { + return; + } + + this.formGroup.controls.access.enable(); + + if (!this.editMode) { this.formGroup.controls.name.enable(); this.formGroup.controls.parent.enable(); - this.formGroup.controls.access.enable(); + return; } + + const canEditName = this.collection.canEditName(this.organization); + this.formGroup.controls.name[canEditName ? "enable" : "disable"](); + this.formGroup.controls.parent[canEditName ? "enable" : "disable"](); } private close(action: CollectionDialogAction, collection?: CollectionResponse | CollectionView) { diff --git a/apps/web/src/app/core/core.module.ts b/apps/web/src/app/core/core.module.ts index cccbe26c524..22386144732 100644 --- a/apps/web/src/app/core/core.module.ts +++ b/apps/web/src/app/core/core.module.ts @@ -45,6 +45,7 @@ import { import { OrganizationIntegrationApiService } from "@bitwarden/bit-common/dirt/integrations"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; +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, @@ -317,7 +318,13 @@ const safeProviders: SafeProvider[] = [ safeProvider({ provide: CollectionAdminService, useClass: DefaultCollectionAdminService, - deps: [ApiService, KeyServiceAbstraction, EncryptService, CollectionService], + deps: [ + ApiService, + KeyServiceAbstraction, + EncryptService, + CollectionService, + OrganizationService, + ], }), safeProvider({ provide: SdkLoadService, diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts index ec77ff97a11..eeecccc87d6 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/services/vault-filter.service.ts @@ -250,7 +250,9 @@ export class VaultFilterService implements VaultFilterServiceAbstraction { } collections.forEach((c) => { - const collectionCopy = cloneCollection(new CollectionView({ ...c })) as CollectionFilter; + const collectionCopy = cloneCollection( + new CollectionView({ ...c, name: c.name }), + ) as CollectionFilter; collectionCopy.icon = "bwi-collection-shared"; const parts = c.name != null ? c.name.replace(/^\/+|\/+$/g, "").split(NestingDelimiter) : []; ServiceUtils.nestedTraverse(nodes, 0, parts, collectionCopy, null, NestingDelimiter); diff --git a/libs/admin-console/src/common/collections/abstractions/collection-admin.service.ts b/libs/admin-console/src/common/collections/abstractions/collection-admin.service.ts index b322825e5ea..9fde1b2090b 100644 --- a/libs/admin-console/src/common/collections/abstractions/collection-admin.service.ts +++ b/libs/admin-console/src/common/collections/abstractions/collection-admin.service.ts @@ -10,7 +10,11 @@ export abstract class CollectionAdminService { organizationId: string, userId: UserId, ): Observable; - abstract save( + abstract update( + collection: CollectionAdminView, + userId: UserId, + ): Promise; + abstract create( collection: CollectionAdminView, userId: UserId, ): Promise; diff --git a/libs/admin-console/src/common/collections/models/collection-admin.view.ts b/libs/admin-console/src/common/collections/models/collection-admin.view.ts index 1cec9c3d39d..fcd2be17b8d 100644 --- a/libs/admin-console/src/common/collections/models/collection-admin.view.ts +++ b/libs/admin-console/src/common/collections/models/collection-admin.view.ts @@ -101,6 +101,17 @@ export class CollectionAdminView extends CollectionView { return this.id === Unassigned; } + /** + * Returns true if the collection name can be edited. Editing the collection name is restricted for collections + * that were DefaultUserCollections but where the relevant user has been offboarded. + * When this occurs, the offboarded user's email is treated as the collection name, and cannot be edited. + * This is important for security so that the server cannot ask the client to encrypt arbitrary data. + * WARNING! This is an IMPORTANT restriction that MUST be maintained for security purposes. + * Do not edit or remove this unless you understand why. + */ + override canEditName(org: Organization): boolean { + return (this.canEdit(org) && !this.defaultUserCollectionEmail) || super.canEditName(org); + } static async fromCollectionAccessDetails( collection: CollectionAccessDetailsResponse, encryptService: EncryptService, @@ -115,6 +126,7 @@ export class CollectionAdminView extends CollectionView { view.unmanaged = collection.unmanaged; view.type = collection.type; view.externalId = collection.externalId; + view.defaultUserCollectionEmail = collection.defaultUserCollectionEmail; view.groups = collection.groups ? collection.groups.map((g) => new CollectionAccessSelectionView(g)) diff --git a/libs/admin-console/src/common/collections/models/collection-with-id.request.ts b/libs/admin-console/src/common/collections/models/collection-with-id.request.ts index f1fccda0cfa..0f7b83705ef 100644 --- a/libs/admin-console/src/common/collections/models/collection-with-id.request.ts +++ b/libs/admin-console/src/common/collections/models/collection-with-id.request.ts @@ -1,19 +1,18 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { Collection } from "./collection"; -import { CollectionRequest } from "./collection.request"; +import { BaseCollectionRequest } from "./collection.request"; -export class CollectionWithIdRequest extends CollectionRequest { +export class CollectionWithIdRequest extends BaseCollectionRequest { id: string; + name: string; - constructor(collection?: Collection) { - if (collection == null) { - return; + constructor(collection: Collection) { + if (collection == null || collection.name == null || collection.name.encryptedString == null) { + throw new Error("CollectionWithIdRequest must contain name."); } super({ - name: collection.name, externalId: collection.externalId, }); + this.name = collection.name.encryptedString; this.id = collection.id; } } diff --git a/libs/admin-console/src/common/collections/models/collection.data.ts b/libs/admin-console/src/common/collections/models/collection.data.ts index dac8f41b2ba..a783a3c9ab1 100644 --- a/libs/admin-console/src/common/collections/models/collection.data.ts +++ b/libs/admin-console/src/common/collections/models/collection.data.ts @@ -9,6 +9,7 @@ export class CollectionData { id: CollectionId; organizationId: OrganizationId; name: string; + defaultUserCollectionEmail: string | undefined; externalId: string | undefined; readOnly: boolean = false; manage: boolean = false; @@ -24,6 +25,7 @@ export class CollectionData { this.manage = response.manage; this.hidePasswords = response.hidePasswords; this.type = response.type; + this.defaultUserCollectionEmail = response.defaultUserCollectionEmail; } static fromJSON(obj: Jsonify): CollectionData | null { diff --git a/libs/admin-console/src/common/collections/models/collection.request.ts b/libs/admin-console/src/common/collections/models/collection.request.ts index 39ed03d81fa..310bb08ea72 100644 --- a/libs/admin-console/src/common/collections/models/collection.request.ts +++ b/libs/admin-console/src/common/collections/models/collection.request.ts @@ -1,23 +1,20 @@ import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request"; import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; -export class CollectionRequest { - name: string; +export abstract class BaseCollectionRequest { externalId: string | undefined; groups: SelectionReadOnlyRequest[] = []; users: SelectionReadOnlyRequest[] = []; - constructor(c: { - name: EncString; + static isUpdate = (request: BaseCollectionRequest): request is UpdateCollectionRequest => { + return request instanceof UpdateCollectionRequest; + }; + + protected constructor(c: { users?: SelectionReadOnlyRequest[]; groups?: SelectionReadOnlyRequest[]; externalId?: string; }) { - if (!c.name || !c.name.encryptedString) { - throw new Error("Name not provided for CollectionRequest."); - } - - this.name = c.name.encryptedString; this.externalId = c.externalId; if (c.groups) { @@ -28,3 +25,36 @@ export class CollectionRequest { } } } + +export class CreateCollectionRequest extends BaseCollectionRequest { + name: string; + + constructor(c: { + name: EncString; + users?: SelectionReadOnlyRequest[]; + groups?: SelectionReadOnlyRequest[]; + externalId?: string; + }) { + super(c); + + if (!c.name || !c.name.encryptedString) { + throw new Error("Name not provided for CollectionRequest."); + } + + this.name = c.name.encryptedString; + } +} + +export class UpdateCollectionRequest extends BaseCollectionRequest { + name: string | null; + + constructor(c: { + name: EncString | null; + users?: SelectionReadOnlyRequest[]; + groups?: SelectionReadOnlyRequest[]; + externalId?: string; + }) { + super(c); + this.name = c.name?.encryptedString ?? null; + } +} diff --git a/libs/admin-console/src/common/collections/models/collection.response.ts b/libs/admin-console/src/common/collections/models/collection.response.ts index ad0eed53ddf..e6722635984 100644 --- a/libs/admin-console/src/common/collections/models/collection.response.ts +++ b/libs/admin-console/src/common/collections/models/collection.response.ts @@ -8,6 +8,7 @@ export class CollectionResponse extends BaseResponse { id: CollectionId; organizationId: OrganizationId; name: string; + defaultUserCollectionEmail: string | undefined; externalId: string | undefined; type: CollectionType = CollectionTypes.SharedCollection; @@ -17,6 +18,7 @@ export class CollectionResponse extends BaseResponse { this.organizationId = this.getResponseProperty("OrganizationId"); this.name = this.getResponseProperty("Name"); this.externalId = this.getResponseProperty("ExternalId"); + this.defaultUserCollectionEmail = this.getResponseProperty("DefaultUserCollectionEmail"); this.type = this.getResponseProperty("Type") ?? CollectionTypes.SharedCollection; } } diff --git a/libs/admin-console/src/common/collections/models/collection.spec.ts b/libs/admin-console/src/common/collections/models/collection.spec.ts index 1cb1d39ed57..16066f88ce1 100644 --- a/libs/admin-console/src/common/collections/models/collection.spec.ts +++ b/libs/admin-console/src/common/collections/models/collection.spec.ts @@ -25,6 +25,7 @@ describe("Collection", () => { manage: true, hidePasswords: true, type: CollectionTypes.DefaultUserCollection, + defaultUserCollectionEmail: "defaultCollectionEmail", }), ); encService = mock(); @@ -61,6 +62,7 @@ describe("Collection", () => { manage: true, hidePasswords: true, type: CollectionTypes.DefaultUserCollection, + defaultUserCollectionEmail: "defaultCollectionEmail", }); }); @@ -75,6 +77,7 @@ describe("Collection", () => { collection.hidePasswords = false; collection.manage = true; collection.type = CollectionTypes.DefaultUserCollection; + collection.defaultUserCollectionEmail = "defaultCollectionEmail"; const key = makeSymmetricCryptoKey(); @@ -84,12 +87,13 @@ describe("Collection", () => { externalId: "extId", hidePasswords: false, id: "id", - name: "encName", + _name: "encName", organizationId: "orgId", readOnly: false, manage: true, assigned: true, type: CollectionTypes.DefaultUserCollection, + defaultUserCollectionEmail: "defaultCollectionEmail", }); }); }); diff --git a/libs/admin-console/src/common/collections/models/collection.ts b/libs/admin-console/src/common/collections/models/collection.ts index 7de4462b0c8..cf5573b8f4f 100644 --- a/libs/admin-console/src/common/collections/models/collection.ts +++ b/libs/admin-console/src/common/collections/models/collection.ts @@ -23,6 +23,7 @@ export class Collection extends Domain { hidePasswords: boolean = false; manage: boolean = false; type: CollectionType = CollectionTypes.SharedCollection; + defaultUserCollectionEmail: string | undefined; constructor(c: { id: CollectionId; name: EncString; organizationId: OrganizationId }) { super(); @@ -46,6 +47,7 @@ export class Collection extends Domain { collection.hidePasswords = obj.hidePasswords; collection.manage = obj.manage; collection.type = obj.type; + collection.defaultUserCollectionEmail = obj.defaultUserCollectionEmail; return collection; } diff --git a/libs/admin-console/src/common/collections/models/collection.view.ts b/libs/admin-console/src/common/collections/models/collection.view.ts index c4470fe13fb..d3e15806c86 100644 --- a/libs/admin-console/src/common/collections/models/collection.view.ts +++ b/libs/admin-console/src/common/collections/models/collection.view.ts @@ -16,7 +16,6 @@ export const NestingDelimiter = "/"; export class CollectionView implements View, ITreeNodeObject { id: CollectionId; organizationId: OrganizationId; - name: string; externalId: string | undefined; // readOnly applies to the items within a collection readOnly: boolean = false; @@ -24,11 +23,22 @@ export class CollectionView implements View, ITreeNodeObject { manage: boolean = false; assigned: boolean = false; type: CollectionType = CollectionTypes.SharedCollection; + defaultUserCollectionEmail: string | undefined; + + private _name: string; constructor(c: { id: CollectionId; organizationId: OrganizationId; name: string }) { this.id = c.id; this.organizationId = c.organizationId; - this.name = c.name; + this._name = c.name; + } + + set name(name: string) { + this._name = name; + } + + get name(): string { + return this.defaultUserCollectionEmail ?? this._name; } canEditItems(org: Organization): boolean { @@ -83,6 +93,18 @@ export class CollectionView implements View, ITreeNodeObject { return false; } + /** + * Returns true if the collection name can be edited. Editing the collection name is restricted for collections + * that were DefaultUserCollections but where the relevant user has been offboarded. + * When this occurs, the offboarded user's email is treated as the collection name, and cannot be edited. + * This is important for security so that the server cannot ask the client to encrypt arbitrary data. + * WARNING! This is an IMPORTANT restriction that MUST be maintained for security purposes. + * Do not edit or remove this unless you understand why. + */ + canEditName(org: Organization): boolean { + return this.canEdit(org) && !this.defaultUserCollectionEmail; + } + get isDefaultCollection() { return this.type == CollectionTypes.DefaultUserCollection; } @@ -111,6 +133,7 @@ export class CollectionView implements View, ITreeNodeObject { view.hidePasswords = collection.hidePasswords; view.manage = collection.manage; view.type = collection.type; + view.defaultUserCollectionEmail = collection.defaultUserCollectionEmail; return view; } @@ -125,6 +148,7 @@ export class CollectionView implements View, ITreeNodeObject { view.externalId = collection.externalId; view.type = collection.type; view.assigned = collection.assigned; + view.defaultUserCollectionEmail = collection.defaultUserCollectionEmail; return view; } diff --git a/libs/admin-console/src/common/collections/services/default-collection-admin.service.ts b/libs/admin-console/src/common/collections/services/default-collection-admin.service.ts index 3f7e8e31e0b..ca797a0f9ae 100644 --- a/libs/admin-console/src/common/collections/services/default-collection-admin.service.ts +++ b/libs/admin-console/src/common/collections/services/default-collection-admin.service.ts @@ -1,6 +1,10 @@ import { combineLatest, firstValueFrom, from, map, Observable, of, switchMap } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { + getOrganizationById, + OrganizationService, +} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { SelectionReadOnlyRequest } from "@bitwarden/common/admin-console/models/request/selection-read-only.request"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { CollectionId, OrganizationId, UserId } from "@bitwarden/common/types/guid"; @@ -10,13 +14,15 @@ import { KeyService } from "@bitwarden/key-management"; import { CollectionAdminService, CollectionService } from "../abstractions"; import { CollectionData, - CollectionRequest, CollectionAccessDetailsResponse, CollectionDetailsResponse, CollectionResponse, BulkCollectionAccessRequest, CollectionAccessSelectionView, CollectionAdminView, + BaseCollectionRequest, + UpdateCollectionRequest, + CreateCollectionRequest, } from "../models"; export class DefaultCollectionAdminService implements CollectionAdminService { @@ -25,6 +31,7 @@ export class DefaultCollectionAdminService implements CollectionAdminService { private keyService: KeyService, private encryptService: EncryptService, private collectionService: CollectionService, + private organizationService: OrganizationService, ) {} collectionAdminViews$(organizationId: string, userId: UserId): Observable { @@ -45,27 +52,40 @@ export class DefaultCollectionAdminService implements CollectionAdminService { ); } - async save(collection: CollectionAdminView, userId: UserId): Promise { - const request = await this.encrypt(collection, userId); - - let response: CollectionDetailsResponse; - if (collection.id == null) { - response = await this.apiService.postCollection(collection.organizationId, request); - collection.id = response.id; - } else { - response = await this.apiService.putCollection( - collection.organizationId, - collection.id, - request, - ); + async update( + collection: CollectionAdminView, + userId: UserId, + ): Promise { + const request = await this.encrypt(collection, userId, true); + if (!BaseCollectionRequest.isUpdate(request)) { + throw new Error("Cannot update collection with CreateCollectionRequest."); } - if (response.assigned) { - await this.collectionService.upsert(new CollectionData(response), userId); - } else { - await this.collectionService.delete([collection.id as CollectionId], userId); + const response = await this.apiService.putCollection( + collection.organizationId, + collection.id, + request, + ); + + await this.updateLocalCollections(response, collection, userId); + + return response; + } + + async create( + collection: CollectionAdminView, + userId: UserId, + ): Promise { + const request = await this.encrypt(collection, userId, false); + if (BaseCollectionRequest.isUpdate(request)) { + throw new Error("Cannot create collection with UpdateCollectionRequest."); } + const response = await this.apiService.postCollection(collection.organizationId, request); + collection.id = response.id; + + await this.updateLocalCollections(response, collection, userId); + return response; } @@ -73,6 +93,16 @@ export class DefaultCollectionAdminService implements CollectionAdminService { await this.apiService.deleteCollection(organizationId, collectionId); } + private async updateLocalCollections( + response: CollectionDetailsResponse, + collection: CollectionAdminView, + userId: UserId, + ) { + response.assigned + ? await this.collectionService.upsert(new CollectionData(response), userId) + : await this.collectionService.delete([collection.id as CollectionId], userId); + } + async bulkAssignAccess( organizationId: string, collectionIds: string[], @@ -118,10 +148,15 @@ export class DefaultCollectionAdminService implements CollectionAdminService { ); }); - return await Promise.all(promises); + const r = await Promise.all(promises); + return r; } - private async encrypt(model: CollectionAdminView, userId: UserId): Promise { + private async encrypt( + model: CollectionAdminView, + userId: UserId, + editMode: boolean, + ): Promise { if (!model.organizationId) { throw new Error("Collection has no organization id."); } @@ -154,14 +189,31 @@ export class DefaultCollectionAdminService implements CollectionAdminService { new SelectionReadOnlyRequest(user.id, user.readOnly, user.hidePasswords, user.manage), ); - const collectionRequest = new CollectionRequest({ + if (editMode) { + const org = await firstValueFrom( + this.organizationService + .organizations$(userId) + .pipe(getOrganizationById(model.organizationId)), + ); + if (org == null) { + throw new Error("No Organization found."); + } + return new UpdateCollectionRequest({ + name: model.canEditName(org) + ? await this.encryptService.encryptString(model.name, key) + : null, + externalId: model.externalId, + users, + groups, + }); + } + + return new CreateCollectionRequest({ name: await this.encryptService.encryptString(model.name, key), externalId: model.externalId, users, groups, }); - - return collectionRequest; } } diff --git a/libs/admin-console/src/common/collections/services/default-collection.service.ts b/libs/admin-console/src/common/collections/services/default-collection.service.ts index aa25cdfa1e7..39b3b491862 100644 --- a/libs/admin-console/src/common/collections/services/default-collection.service.ts +++ b/libs/admin-console/src/common/collections/services/default-collection.service.ts @@ -216,7 +216,7 @@ export class DefaultCollectionService implements CollectionService { getAllNested(collections: CollectionView[]): TreeNode[] { const nodes: TreeNode[] = []; collections.forEach((c) => { - const collectionCopy = Object.assign(new CollectionView({ ...c }), c); + const collectionCopy = Object.assign(new CollectionView({ ...c, name: c.name }), c); const parts = c.name != null ? c.name.replace(/^\/+|\/+$/g, "").split(NestingDelimiter) : []; ServiceUtils.nestedTraverse(nodes, 0, parts, collectionCopy, undefined, NestingDelimiter); diff --git a/libs/common/src/abstractions/api.service.ts b/libs/common/src/abstractions/api.service.ts index d8b8c1c429f..726b04534ad 100644 --- a/libs/common/src/abstractions/api.service.ts +++ b/libs/common/src/abstractions/api.service.ts @@ -3,8 +3,9 @@ import { CollectionAccessDetailsResponse, CollectionDetailsResponse, - CollectionRequest, CollectionResponse, + CreateCollectionRequest, + UpdateCollectionRequest, } from "@bitwarden/admin-console/common"; import { OrganizationConnectionType } from "../admin-console/enums"; @@ -270,12 +271,12 @@ export abstract class ApiService { ): Promise>; abstract postCollection( organizationId: string, - request: CollectionRequest, + request: CreateCollectionRequest, ): Promise; abstract putCollection( organizationId: string, id: string, - request: CollectionRequest, + request: UpdateCollectionRequest, ): Promise; abstract deleteCollection(organizationId: string, id: string): Promise; abstract deleteManyCollections(organizationId: string, collectionIds: string[]): Promise; diff --git a/libs/common/src/services/api.service.ts b/libs/common/src/services/api.service.ts index e48b941d4a0..6a670368b1f 100644 --- a/libs/common/src/services/api.service.ts +++ b/libs/common/src/services/api.service.ts @@ -7,8 +7,9 @@ import { firstValueFrom } from "rxjs"; import { CollectionAccessDetailsResponse, CollectionDetailsResponse, - CollectionRequest, CollectionResponse, + CreateCollectionRequest, + UpdateCollectionRequest, } from "@bitwarden/admin-console/common"; // This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. // eslint-disable-next-line no-restricted-imports @@ -727,7 +728,7 @@ export class ApiService implements ApiServiceAbstraction { async postCollection( organizationId: string, - request: CollectionRequest, + request: CreateCollectionRequest, ): Promise { const r = await this.send( "POST", @@ -742,7 +743,7 @@ export class ApiService implements ApiServiceAbstraction { async putCollection( organizationId: string, id: string, - request: CollectionRequest, + request: UpdateCollectionRequest, ): Promise { const r = await this.send( "PUT", diff --git a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.spec.ts b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.spec.ts index 6aa7175d373..e3d863a0af3 100644 --- a/libs/vault/src/cipher-form/components/item-details/item-details-section.component.spec.ts +++ b/libs/vault/src/cipher-form/components/item-details/item-details-section.component.spec.ts @@ -33,23 +33,24 @@ const createMockCollection = ( readOnly = false, canEdit = true, ): CollectionView => { - return { - id: id as CollectionId, + const cv = new CollectionView({ name, organizationId: organizationId as OrganizationId, - externalId: "", - readOnly, - hidePasswords: false, - manage: true, - assigned: true, - type: CollectionTypes.DefaultUserCollection, - isDefaultCollection: true, - canEditItems: jest.fn().mockReturnValue(canEdit), - canEdit: jest.fn(), - canDelete: jest.fn(), - canViewCollectionInfo: jest.fn(), - encrypt: jest.fn(), - }; + id: id as CollectionId, + }); + cv.readOnly = readOnly; + cv.manage = true; + cv.type = CollectionTypes.DefaultUserCollection; + cv.externalId = ""; + cv.hidePasswords = false; + cv.assigned = true; + cv.canEditName = jest.fn().mockReturnValue(true); + cv.canEditItems = jest.fn().mockReturnValue(canEdit); + cv.canEdit = jest.fn(); + cv.canDelete = jest.fn(); + cv.canViewCollectionInfo = jest.fn(); + + return cv; }; describe("ItemDetailsSectionComponent", () => { From 34cd41988a5612d041fe56d4c239577a60b3f7ec Mon Sep 17 00:00:00 2001 From: neuronull <9162534+neuronull@users.noreply.github.com> Date: Tue, 26 Aug 2025 12:44:08 -0600 Subject: [PATCH 052/167] Remove `EnableNewCardCombinedExpiryAutofill` feature flag (#16131) --- .../services/autofill.service.spec.ts | 48 +----- .../src/autofill/services/autofill.service.ts | 157 +----------------- libs/common/src/enums/feature-flag.enum.ts | 2 - 3 files changed, 2 insertions(+), 205 deletions(-) diff --git a/apps/browser/src/autofill/services/autofill.service.spec.ts b/apps/browser/src/autofill/services/autofill.service.spec.ts index 80cce5228d3..f9430387c83 100644 --- a/apps/browser/src/autofill/services/autofill.service.spec.ts +++ b/apps/browser/src/autofill/services/autofill.service.spec.ts @@ -14,7 +14,7 @@ import { UserNotificationSettingsServiceAbstraction } from "@bitwarden/common/au import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { EventType } from "@bitwarden/common/enums"; -import { FeatureFlag, FeatureFlagValueType } from "@bitwarden/common/enums/feature-flag.enum"; +import { FeatureFlagValueType } from "@bitwarden/common/enums/feature-flag.enum"; import { UriMatchStrategy } from "@bitwarden/common/models/domain/domain-service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -2987,12 +2987,6 @@ describe("AutofillService", () => { options.cipher.card.expMonth = "5"; } - const enableNewCardCombinedExpiryAutofill = await configService.getFeatureFlag( - FeatureFlag.EnableNewCardCombinedExpiryAutofill, - ); - - expect(enableNewCardCombinedExpiryAutofill).toEqual(false); - const value = await autofillService["generateCardFillScript"]( fillScript, pageDetails, @@ -3003,23 +2997,6 @@ describe("AutofillService", () => { expect(value.script[2]).toStrictEqual(["fill_by_opid", "expirationDate", dateFormat[1]]); }); }); - - it("returns an expiration date format matching `yyyy-mm` if no valid format can be identified", async () => { - const value = await autofillService["generateCardFillScript"]( - fillScript, - pageDetails, - filledFields, - options, - ); - - const enableNewCardCombinedExpiryAutofill = await configService.getFeatureFlag( - FeatureFlag.EnableNewCardCombinedExpiryAutofill, - ); - - expect(enableNewCardCombinedExpiryAutofill).toEqual(false); - - expect(value.script[2]).toStrictEqual(["fill_by_opid", "expirationDate", "2024-05"]); - }); }); const extraExpectedDateFormats = [ @@ -3092,12 +3069,6 @@ describe("AutofillService", () => { options.cipher.card.expMonth = "05"; } - const enableNewCardCombinedExpiryAutofill = await configService.getFeatureFlag( - FeatureFlag.EnableNewCardCombinedExpiryAutofill, - ); - - expect(enableNewCardCombinedExpiryAutofill).toEqual(true); - const value = await autofillService["generateCardFillScript"]( fillScript, pageDetails, @@ -3108,23 +3079,6 @@ describe("AutofillService", () => { expect(value.script[2]).toStrictEqual(["fill_by_opid", "expirationDate", dateFormat[1]]); }); }); - - it("feature-flagged logic returns an expiration date format matching `mm/yy` if no valid format can be identified", async () => { - const value = await autofillService["generateCardFillScript"]( - fillScript, - pageDetails, - filledFields, - options, - ); - - const enableNewCardCombinedExpiryAutofill = await configService.getFeatureFlag( - FeatureFlag.EnableNewCardCombinedExpiryAutofill, - ); - - expect(enableNewCardCombinedExpiryAutofill).toEqual(true); - - expect(value.script[2]).toStrictEqual(["fill_by_opid", "expirationDate", "05/24"]); - }); }); }); diff --git a/apps/browser/src/autofill/services/autofill.service.ts b/apps/browser/src/autofill/services/autofill.service.ts index fd707ef96b3..51c0dd3f247 100644 --- a/apps/browser/src/autofill/services/autofill.service.ts +++ b/apps/browser/src/autofill/services/autofill.service.ts @@ -29,7 +29,6 @@ import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types"; import { normalizeExpiryYearFormat } from "@bitwarden/common/autofill/utils"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { EventType } from "@bitwarden/common/enums"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { UriMatchStrategySetting, UriMatchStrategy, @@ -1212,161 +1211,7 @@ export default class AutofillService implements AutofillServiceInterface { AutofillService.hasValue(card.expMonth) && AutofillService.hasValue(card.expYear) ) { - let combinedExpiryFillValue = null; - - const enableNewCardCombinedExpiryAutofill = await this.configService.getFeatureFlag( - FeatureFlag.EnableNewCardCombinedExpiryAutofill, - ); - - if (enableNewCardCombinedExpiryAutofill) { - combinedExpiryFillValue = this.generateCombinedExpiryValue(card, fillFields.exp); - } else { - const fullMonth = ("0" + card.expMonth).slice(-2); - - let fullYear: string = card.expYear; - let partYear: string = null; - if (fullYear.length === 2) { - partYear = fullYear; - fullYear = normalizeExpiryYearFormat(fullYear); - } else if (fullYear.length === 4) { - partYear = fullYear.substr(2, 2); - } - - for (let i = 0; i < CreditCardAutoFillConstants.MonthAbbr.length; i++) { - if ( - // mm/yyyy - this.fieldAttrsContain( - fillFields.exp, - CreditCardAutoFillConstants.MonthAbbr[i] + - "/" + - CreditCardAutoFillConstants.YearAbbrLong[i], - ) - ) { - combinedExpiryFillValue = fullMonth + "/" + fullYear; - } else if ( - // mm/yy - this.fieldAttrsContain( - fillFields.exp, - CreditCardAutoFillConstants.MonthAbbr[i] + - "/" + - CreditCardAutoFillConstants.YearAbbrShort[i], - ) && - partYear != null - ) { - combinedExpiryFillValue = fullMonth + "/" + partYear; - } else if ( - // yyyy/mm - this.fieldAttrsContain( - fillFields.exp, - CreditCardAutoFillConstants.YearAbbrLong[i] + - "/" + - CreditCardAutoFillConstants.MonthAbbr[i], - ) - ) { - combinedExpiryFillValue = fullYear + "/" + fullMonth; - } else if ( - // yy/mm - this.fieldAttrsContain( - fillFields.exp, - CreditCardAutoFillConstants.YearAbbrShort[i] + - "/" + - CreditCardAutoFillConstants.MonthAbbr[i], - ) && - partYear != null - ) { - combinedExpiryFillValue = partYear + "/" + fullMonth; - } else if ( - // mm-yyyy - this.fieldAttrsContain( - fillFields.exp, - CreditCardAutoFillConstants.MonthAbbr[i] + - "-" + - CreditCardAutoFillConstants.YearAbbrLong[i], - ) - ) { - combinedExpiryFillValue = fullMonth + "-" + fullYear; - } else if ( - // mm-yy - this.fieldAttrsContain( - fillFields.exp, - CreditCardAutoFillConstants.MonthAbbr[i] + - "-" + - CreditCardAutoFillConstants.YearAbbrShort[i], - ) && - partYear != null - ) { - combinedExpiryFillValue = fullMonth + "-" + partYear; - } else if ( - // yyyy-mm - this.fieldAttrsContain( - fillFields.exp, - CreditCardAutoFillConstants.YearAbbrLong[i] + - "-" + - CreditCardAutoFillConstants.MonthAbbr[i], - ) - ) { - combinedExpiryFillValue = fullYear + "-" + fullMonth; - } else if ( - // yy-mm - this.fieldAttrsContain( - fillFields.exp, - CreditCardAutoFillConstants.YearAbbrShort[i] + - "-" + - CreditCardAutoFillConstants.MonthAbbr[i], - ) && - partYear != null - ) { - combinedExpiryFillValue = partYear + "-" + fullMonth; - } else if ( - // yyyymm - this.fieldAttrsContain( - fillFields.exp, - CreditCardAutoFillConstants.YearAbbrLong[i] + - CreditCardAutoFillConstants.MonthAbbr[i], - ) - ) { - combinedExpiryFillValue = fullYear + fullMonth; - } else if ( - // yymm - this.fieldAttrsContain( - fillFields.exp, - CreditCardAutoFillConstants.YearAbbrShort[i] + - CreditCardAutoFillConstants.MonthAbbr[i], - ) && - partYear != null - ) { - combinedExpiryFillValue = partYear + fullMonth; - } else if ( - // mmyyyy - this.fieldAttrsContain( - fillFields.exp, - CreditCardAutoFillConstants.MonthAbbr[i] + - CreditCardAutoFillConstants.YearAbbrLong[i], - ) - ) { - combinedExpiryFillValue = fullMonth + fullYear; - } else if ( - // mmyy - this.fieldAttrsContain( - fillFields.exp, - CreditCardAutoFillConstants.MonthAbbr[i] + - CreditCardAutoFillConstants.YearAbbrShort[i], - ) && - partYear != null - ) { - combinedExpiryFillValue = fullMonth + partYear; - } - - if (combinedExpiryFillValue != null) { - break; - } - } - - // If none of the previous cases applied, set as default - if (combinedExpiryFillValue == null) { - combinedExpiryFillValue = fullYear + "-" + fullMonth; - } - } + const combinedExpiryFillValue = this.generateCombinedExpiryValue(card, fillFields.exp); this.makeScriptActionWithValue( fillScript, diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 67f68e12847..cd9bbfc54c3 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -17,7 +17,6 @@ export enum FeatureFlag { PM14938_BrowserExtensionLoginApproval = "pm-14938-browser-extension-login-approvals", /* Autofill */ - EnableNewCardCombinedExpiryAutofill = "enable-new-card-combined-expiry-autofill", NotificationRefresh = "notification-refresh", UseTreeWalkerApiForPageDetailsCollection = "use-tree-walker-api-for-page-details-collection", MacOsNativeCredentialSync = "macos-native-credential-sync", @@ -74,7 +73,6 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.CreateDefaultLocation]: FALSE, /* Autofill */ - [FeatureFlag.EnableNewCardCombinedExpiryAutofill]: FALSE, [FeatureFlag.NotificationRefresh]: FALSE, [FeatureFlag.UseTreeWalkerApiForPageDetailsCollection]: FALSE, [FeatureFlag.MacOsNativeCredentialSync]: FALSE, From c72fdebfd934d823ed19b4313afa13a92ac991c2 Mon Sep 17 00:00:00 2001 From: Github Actions Date: Tue, 26 Aug 2025 22:55:29 +0000 Subject: [PATCH 053/167] Bumped Desktop client to 2025.8.2 --- apps/desktop/package.json | 2 +- apps/desktop/src/package-lock.json | 4 ++-- apps/desktop/src/package.json | 2 +- package-lock.json | 3 ++- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 42eb7017e03..ff958c0d8e6 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@bitwarden/desktop", "description": "A secure and free password manager for all of your devices.", - "version": "2025.8.1", + "version": "2025.8.2", "keywords": [ "bitwarden", "password", diff --git a/apps/desktop/src/package-lock.json b/apps/desktop/src/package-lock.json index 6daff35e115..4be839e28c2 100644 --- a/apps/desktop/src/package-lock.json +++ b/apps/desktop/src/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bitwarden/desktop", - "version": "2025.8.1", + "version": "2025.8.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bitwarden/desktop", - "version": "2025.8.1", + "version": "2025.8.2", "license": "GPL-3.0", "dependencies": { "@bitwarden/desktop-napi": "file:../desktop_native/napi" diff --git a/apps/desktop/src/package.json b/apps/desktop/src/package.json index ea2e8affda2..77b1f186171 100644 --- a/apps/desktop/src/package.json +++ b/apps/desktop/src/package.json @@ -2,7 +2,7 @@ "name": "@bitwarden/desktop", "productName": "Bitwarden", "description": "A secure and free password manager for all of your devices.", - "version": "2025.8.1", + "version": "2025.8.2", "author": "Bitwarden Inc. (https://bitwarden.com)", "homepage": "https://bitwarden.com", "license": "GPL-3.0", diff --git a/package-lock.json b/package-lock.json index c414adb416d..842480f56da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -277,7 +277,7 @@ }, "apps/desktop": { "name": "@bitwarden/desktop", - "version": "2025.8.1", + "version": "2025.8.2", "hasInstallScript": true, "license": "GPL-3.0" }, @@ -403,6 +403,7 @@ "license": "GPL-3.0" }, "libs/state-internal": { + "name": "@bitwarden/state-internal", "version": "0.0.1", "license": "GPL-3.0" }, From 4f09ae52abb8a83bc26c33e584f48b7215d72225 Mon Sep 17 00:00:00 2001 From: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Date: Wed, 27 Aug 2025 22:10:32 +1000 Subject: [PATCH 054/167] [PM-25203] Resolve circular dependencies through LooseComponentsModule (#16157) * Update modules to not import loose-components Instead they should import their dependencies directly. Only OssModule imports loose-components.module.ts. * Remove unused imports and exports --- .../organizations/collections/vault.module.ts | 2 - .../organizations/members/members.module.ts | 4 +- .../organizations/organization.module.ts | 4 +- .../organizations/policies/policies.module.ts | 5 ++- .../organization-reporting.module.ts | 9 +--- .../settings/organization-settings.module.ts | 9 +++- .../two-factor/two-factor-setup.component.ts | 5 ++- .../organization-billing.module.ts | 4 +- apps/web/src/app/oss.module.ts | 7 ++- apps/web/src/app/shared/index.ts | 1 - .../src/app/shared/loose-components.module.ts | 44 +------------------ .../app/tools/import/org-import.component.ts | 5 ++- .../org-vault-export.component.ts | 5 ++- .../vault/individual-vault/vault.module.ts | 3 +- .../device-approvals.component.ts | 4 +- .../organizations/organizations.module.ts | 4 +- 16 files changed, 38 insertions(+), 77 deletions(-) diff --git a/apps/web/src/app/admin-console/organizations/collections/vault.module.ts b/apps/web/src/app/admin-console/organizations/collections/vault.module.ts index 037a27cd781..1a093ff8352 100644 --- a/apps/web/src/app/admin-console/organizations/collections/vault.module.ts +++ b/apps/web/src/app/admin-console/organizations/collections/vault.module.ts @@ -1,6 +1,5 @@ import { NgModule } from "@angular/core"; -import { LooseComponentsModule } from "../../../shared/loose-components.module"; import { SharedModule } from "../../../shared/shared.module"; import { OrganizationBadgeModule } from "../../../vault/individual-vault/organization-badge/organization-badge.module"; import { ViewComponent } from "../../../vault/individual-vault/view.component"; @@ -15,7 +14,6 @@ import { VaultComponent } from "./vault.component"; imports: [ VaultRoutingModule, SharedModule, - LooseComponentsModule, GroupBadgeModule, CollectionNameBadgeComponent, OrganizationBadgeModule, diff --git a/apps/web/src/app/admin-console/organizations/members/members.module.ts b/apps/web/src/app/admin-console/organizations/members/members.module.ts index efc091cb335..e5bc5f29a3b 100644 --- a/apps/web/src/app/admin-console/organizations/members/members.module.ts +++ b/apps/web/src/app/admin-console/organizations/members/members.module.ts @@ -6,7 +6,7 @@ import { PasswordCalloutComponent } from "@bitwarden/auth/angular"; import { ScrollLayoutDirective } from "@bitwarden/components"; import { OrganizationFreeTrialWarningComponent } from "@bitwarden/web-vault/app/billing/organizations/warnings/components"; -import { LooseComponentsModule } from "../../../shared"; +import { HeaderModule } from "../../../layouts/header/header.module"; import { SharedOrganizationModule } from "../shared"; import { BulkConfirmDialogComponent } from "./components/bulk/bulk-confirm-dialog.component"; @@ -22,10 +22,10 @@ import { MembersComponent } from "./members.component"; @NgModule({ imports: [ SharedOrganizationModule, - LooseComponentsModule, MembersRoutingModule, UserDialogModule, PasswordCalloutComponent, + HeaderModule, ScrollingModule, PasswordStrengthV2Component, ScrollLayoutDirective, diff --git a/apps/web/src/app/admin-console/organizations/organization.module.ts b/apps/web/src/app/admin-console/organizations/organization.module.ts index d956174149b..2f0077d313e 100644 --- a/apps/web/src/app/admin-console/organizations/organization.module.ts +++ b/apps/web/src/app/admin-console/organizations/organization.module.ts @@ -4,7 +4,7 @@ import { NgModule } from "@angular/core"; import { ScrollLayoutDirective } from "@bitwarden/components"; import { OrganizationWarningsModule } from "@bitwarden/web-vault/app/billing/organizations/warnings/organization-warnings.module"; -import { LooseComponentsModule } from "../../shared"; +import { HeaderModule } from "../../layouts/header/header.module"; import { CoreOrganizationModule } from "./core"; import { GroupAddEditComponent } from "./manage/group-add-edit.component"; @@ -19,7 +19,7 @@ import { AccessSelectorModule } from "./shared/components/access-selector"; AccessSelectorModule, CoreOrganizationModule, OrganizationsRoutingModule, - LooseComponentsModule, + HeaderModule, ScrollingModule, ScrollLayoutDirective, OrganizationWarningsModule, diff --git a/apps/web/src/app/admin-console/organizations/policies/policies.module.ts b/apps/web/src/app/admin-console/organizations/policies/policies.module.ts index 3999f36ecad..95b22497eba 100644 --- a/apps/web/src/app/admin-console/organizations/policies/policies.module.ts +++ b/apps/web/src/app/admin-console/organizations/policies/policies.module.ts @@ -1,6 +1,7 @@ import { NgModule } from "@angular/core"; -import { LooseComponentsModule, SharedModule } from "../../../shared"; +import { HeaderModule } from "../../../layouts/header/header.module"; +import { SharedModule } from "../../../shared"; import { DisableSendPolicyComponent } from "./disable-send.component"; import { MasterPasswordPolicyComponent } from "./master-password.component"; @@ -17,7 +18,7 @@ import { SingleOrgPolicyComponent } from "./single-org.component"; import { TwoFactorAuthenticationPolicyComponent } from "./two-factor-authentication.component"; @NgModule({ - imports: [SharedModule, LooseComponentsModule], + imports: [SharedModule, HeaderModule], declarations: [ DisableSendPolicyComponent, MasterPasswordPolicyComponent, diff --git a/apps/web/src/app/admin-console/organizations/reporting/organization-reporting.module.ts b/apps/web/src/app/admin-console/organizations/reporting/organization-reporting.module.ts index 22c3edcf240..46599d7da46 100644 --- a/apps/web/src/app/admin-console/organizations/reporting/organization-reporting.module.ts +++ b/apps/web/src/app/admin-console/organizations/reporting/organization-reporting.module.ts @@ -1,19 +1,14 @@ import { NgModule } from "@angular/core"; import { ReportsSharedModule } from "../../../dirt/reports"; -import { LooseComponentsModule } from "../../../shared"; +import { HeaderModule } from "../../../layouts/header/header.module"; import { SharedModule } from "../../../shared/shared.module"; import { OrganizationReportingRoutingModule } from "./organization-reporting-routing.module"; import { ReportsHomeComponent } from "./reports-home.component"; @NgModule({ - imports: [ - SharedModule, - ReportsSharedModule, - OrganizationReportingRoutingModule, - LooseComponentsModule, - ], + imports: [SharedModule, ReportsSharedModule, OrganizationReportingRoutingModule, HeaderModule], declarations: [ReportsHomeComponent], }) export class OrganizationReportingModule {} diff --git a/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts b/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts index bfff3b2aa2e..9b0c3035e98 100644 --- a/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts +++ b/apps/web/src/app/admin-console/organizations/settings/organization-settings.module.ts @@ -2,8 +2,11 @@ import { NgModule } from "@angular/core"; import { ItemModule } from "@bitwarden/components"; -import { LooseComponentsModule, SharedModule } from "../../../shared"; +import { DangerZoneComponent } from "../../../auth/settings/account/danger-zone.component"; +import { HeaderModule } from "../../../layouts/header/header.module"; +import { SharedModule } from "../../../shared"; import { AccountFingerprintComponent } from "../../../shared/components/account-fingerprint/account-fingerprint.component"; +import { PremiumBadgeComponent } from "../../../vault/components/premium-badge.component"; import { PoliciesModule } from "../../organizations/policies"; import { AccountComponent } from "./account.component"; @@ -13,10 +16,12 @@ import { TwoFactorSetupComponent } from "./two-factor-setup.component"; @NgModule({ imports: [ SharedModule, - LooseComponentsModule, PoliciesModule, OrganizationSettingsRoutingModule, AccountFingerprintComponent, + DangerZoneComponent, + HeaderModule, + PremiumBadgeComponent, ItemModule, ], declarations: [AccountComponent, TwoFactorSetupComponent], diff --git a/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.ts b/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.ts index 7259c3f0fe8..e538e72a77e 100644 --- a/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.ts +++ b/apps/web/src/app/auth/settings/two-factor/two-factor-setup.component.ts @@ -33,8 +33,9 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { DialogRef, DialogService, ItemModule } from "@bitwarden/components"; -import { LooseComponentsModule } from "../../../shared/loose-components.module"; +import { HeaderModule } from "../../../layouts/header/header.module"; import { SharedModule } from "../../../shared/shared.module"; +import { PremiumBadgeComponent } from "../../../vault/components/premium-badge.component"; import { TwoFactorRecoveryComponent } from "./two-factor-recovery.component"; import { TwoFactorSetupAuthenticatorComponent } from "./two-factor-setup-authenticator.component"; @@ -47,7 +48,7 @@ import { TwoFactorVerifyComponent } from "./two-factor-verify.component"; @Component({ selector: "app-two-factor-setup", templateUrl: "two-factor-setup.component.html", - imports: [ItemModule, LooseComponentsModule, SharedModule], + imports: [ItemModule, HeaderModule, PremiumBadgeComponent, SharedModule], }) export class TwoFactorSetupComponent implements OnInit, OnDestroy { organizationId: string; diff --git a/apps/web/src/app/billing/organizations/organization-billing.module.ts b/apps/web/src/app/billing/organizations/organization-billing.module.ts index d8f4b7393aa..707a854de02 100644 --- a/apps/web/src/app/billing/organizations/organization-billing.module.ts +++ b/apps/web/src/app/billing/organizations/organization-billing.module.ts @@ -4,7 +4,7 @@ import { NgModule } from "@angular/core"; // eslint-disable-next-line no-restricted-imports import { BannerModule } from "../../../../../../libs/components/src/banner/banner.module"; import { UserVerificationModule } from "../../auth/shared/components/user-verification"; -import { LooseComponentsModule } from "../../shared"; +import { HeaderModule } from "../../layouts/header/header.module"; import { BillingSharedModule } from "../shared"; import { AdjustSubscription } from "./adjust-subscription.component"; @@ -29,7 +29,7 @@ import { SubscriptionStatusComponent } from "./subscription-status.component"; UserVerificationModule, BillingSharedModule, OrganizationPlansComponent, - LooseComponentsModule, + HeaderModule, BannerModule, ], declarations: [ diff --git a/apps/web/src/app/oss.module.ts b/apps/web/src/app/oss.module.ts index d5fe718412a..4e04910246f 100644 --- a/apps/web/src/app/oss.module.ts +++ b/apps/web/src/app/oss.module.ts @@ -3,7 +3,9 @@ import { NgModule } from "@angular/core"; import { AuthModule } from "./auth"; import { LoginModule } from "./auth/login/login.module"; import { TrialInitiationModule } from "./billing/trial-initiation/trial-initiation.module"; -import { LooseComponentsModule, SharedModule } from "./shared"; +import { HeaderModule } from "./layouts/header/header.module"; +import { SharedModule } from "./shared"; +import { LooseComponentsModule } from "./shared/loose-components.module"; import { AccessComponent } from "./tools/send/send-access/access.component"; import { OrganizationBadgeModule } from "./vault/individual-vault/organization-badge/organization-badge.module"; import { VaultFilterModule } from "./vault/individual-vault/vault-filter/vault-filter.module"; @@ -15,6 +17,7 @@ import "./shared/locales"; imports: [ SharedModule, LooseComponentsModule, + HeaderModule, TrialInitiationModule, VaultFilterModule, OrganizationBadgeModule, @@ -24,7 +27,7 @@ import "./shared/locales"; ], exports: [ SharedModule, - LooseComponentsModule, + HeaderModule, TrialInitiationModule, VaultFilterModule, OrganizationBadgeModule, diff --git a/apps/web/src/app/shared/index.ts b/apps/web/src/app/shared/index.ts index 7defcdedfda..7a1160c4105 100644 --- a/apps/web/src/app/shared/index.ts +++ b/apps/web/src/app/shared/index.ts @@ -1,2 +1 @@ export * from "./shared.module"; -export * from "./loose-components.module"; diff --git a/apps/web/src/app/shared/loose-components.module.ts b/apps/web/src/app/shared/loose-components.module.ts index d7dbdbc4ae5..f7f3aa3bfee 100644 --- a/apps/web/src/app/shared/loose-components.module.ts +++ b/apps/web/src/app/shared/loose-components.module.ts @@ -1,18 +1,7 @@ import { NgModule } from "@angular/core"; -import { - PasswordCalloutComponent, - UserVerificationFormInputComponent, - VaultTimeoutInputComponent, -} from "@bitwarden/auth/angular"; -import { LayoutComponent, NavigationModule } from "@bitwarden/components"; - -import { OrganizationLayoutComponent } from "../admin-console/organizations/layouts/organization-layout.component"; -import { VerifyRecoverDeleteOrgComponent } from "../admin-console/organizations/manage/verify-recover-delete-org.component"; import { RecoverDeleteComponent } from "../auth/recover-delete.component"; import { RecoverTwoFactorComponent } from "../auth/recover-two-factor.component"; -import { DangerZoneComponent } from "../auth/settings/account/danger-zone.component"; -import { UserVerificationModule } from "../auth/shared/components/user-verification"; import { VerifyEmailTokenComponent } from "../auth/verify-email-token.component"; import { VerifyRecoverDeleteComponent } from "../auth/verify-recover-delete.component"; import { FreeBitwardenFamiliesComponent } from "../billing/members/free-bitwarden-families.component"; @@ -30,33 +19,15 @@ import { UnsecuredWebsitesReportComponent as OrgUnsecuredWebsitesReportComponent import { WeakPasswordsReportComponent as OrgWeakPasswordsReportComponent } from "../dirt/reports/pages/organizations/weak-passwords-report.component"; import { RemovePasswordComponent } from "../key-management/key-connector/remove-password.component"; import { HeaderModule } from "../layouts/header/header.module"; -import { PremiumBadgeComponent } from "../vault/components/premium-badge.component"; import { OrganizationBadgeModule } from "../vault/individual-vault/organization-badge/organization-badge.module"; import { PipesModule } from "../vault/individual-vault/pipes/pipes.module"; -import { AccountFingerprintComponent } from "./components/account-fingerprint/account-fingerprint.component"; import { SharedModule } from "./shared.module"; // Please do not add to this list of declarations - we should refactor these into modules when doing so makes sense until there are none left. // If you are building new functionality, please create or extend a feature module instead. @NgModule({ - imports: [ - SharedModule, - UserVerificationModule, - AccountFingerprintComponent, - OrganizationBadgeModule, - PipesModule, - PasswordCalloutComponent, - UserVerificationFormInputComponent, - DangerZoneComponent, - LayoutComponent, - NavigationModule, - HeaderModule, - OrganizationLayoutComponent, - VerifyRecoverDeleteOrgComponent, - VaultTimeoutInputComponent, - PremiumBadgeComponent, - ], + imports: [SharedModule, HeaderModule, OrganizationBadgeModule, PipesModule], declarations: [ OrgExposedPasswordsReportComponent, OrgInactiveTwoFactorReportComponent, @@ -73,25 +44,12 @@ import { SharedModule } from "./shared.module"; VerifyRecoverDeleteComponent, ], exports: [ - UserVerificationModule, - PremiumBadgeComponent, - OrganizationLayoutComponent, - OrgExposedPasswordsReportComponent, - OrgInactiveTwoFactorReportComponent, - OrgReusedPasswordsReportComponent, - OrgUnsecuredWebsitesReportComponent, - OrgWeakPasswordsReportComponent, - PremiumBadgeComponent, RecoverDeleteComponent, RecoverTwoFactorComponent, RemovePasswordComponent, SponsoredFamiliesComponent, - FreeBitwardenFamiliesComponent, - SponsoringOrgRowComponent, VerifyEmailTokenComponent, VerifyRecoverDeleteComponent, - HeaderModule, - DangerZoneComponent, ], }) export class LooseComponentsModule {} diff --git a/apps/web/src/app/tools/import/org-import.component.ts b/apps/web/src/app/tools/import/org-import.component.ts index fd833f3a698..8fb5a582b1a 100644 --- a/apps/web/src/app/tools/import/org-import.component.ts +++ b/apps/web/src/app/tools/import/org-import.component.ts @@ -14,13 +14,14 @@ import { getUserId } from "@bitwarden/common/auth/services/account.service"; import { ImportCollectionServiceAbstraction } from "@bitwarden/importer-core"; import { ImportComponent } from "@bitwarden/importer-ui"; -import { LooseComponentsModule, SharedModule } from "../../shared"; +import { HeaderModule } from "../../layouts/header/header.module"; +import { SharedModule } from "../../shared"; import { ImportCollectionAdminService } from "./import-collection-admin.service"; @Component({ templateUrl: "org-import.component.html", - imports: [SharedModule, ImportComponent, LooseComponentsModule], + imports: [SharedModule, ImportComponent, HeaderModule], providers: [ { provide: ImportCollectionServiceAbstraction, diff --git a/apps/web/src/app/tools/vault-export/org-vault-export.component.ts b/apps/web/src/app/tools/vault-export/org-vault-export.component.ts index 94cc9bf18f7..a1de4814a13 100644 --- a/apps/web/src/app/tools/vault-export/org-vault-export.component.ts +++ b/apps/web/src/app/tools/vault-export/org-vault-export.component.ts @@ -5,11 +5,12 @@ import { ActivatedRoute } from "@angular/router"; import { ExportComponent } from "@bitwarden/vault-export-ui"; -import { LooseComponentsModule, SharedModule } from "../../shared"; +import { HeaderModule } from "../../layouts/header/header.module"; +import { SharedModule } from "../../shared"; @Component({ templateUrl: "org-vault-export.component.html", - imports: [SharedModule, ExportComponent, LooseComponentsModule], + imports: [SharedModule, ExportComponent, HeaderModule], }) export class OrganizationVaultExportComponent implements OnInit { protected routeOrgId: string = null; diff --git a/apps/web/src/app/vault/individual-vault/vault.module.ts b/apps/web/src/app/vault/individual-vault/vault.module.ts index 57d3df30df7..573eceef64a 100644 --- a/apps/web/src/app/vault/individual-vault/vault.module.ts +++ b/apps/web/src/app/vault/individual-vault/vault.module.ts @@ -3,7 +3,7 @@ import { NgModule } from "@angular/core"; import { CollectionNameBadgeComponent } from "../../admin-console/organizations/collections"; import { GroupBadgeModule } from "../../admin-console/organizations/collections/group-badge/group-badge.module"; import { CollectionDialogComponent } from "../../admin-console/organizations/shared/components/collection-dialog"; -import { LooseComponentsModule, SharedModule } from "../../shared"; +import { SharedModule } from "../../shared"; import { BulkDialogsModule } from "./bulk-action-dialogs/bulk-dialogs.module"; import { OrganizationBadgeModule } from "./organization-badge/organization-badge.module"; @@ -20,7 +20,6 @@ import { ViewComponent } from "./view.component"; CollectionNameBadgeComponent, PipesModule, SharedModule, - LooseComponentsModule, BulkDialogsModule, CollectionDialogComponent, VaultComponent, diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts index f41b91261f7..bd62d972500 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts @@ -21,7 +21,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { TableDataSource, NoItemsModule, ToastService } from "@bitwarden/components"; import { KeyService } from "@bitwarden/key-management"; -import { LooseComponentsModule } from "@bitwarden/web-vault/app/shared"; +import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.module"; import { SharedModule } from "@bitwarden/web-vault/app/shared/shared.module"; @Component({ @@ -43,7 +43,7 @@ import { SharedModule } from "@bitwarden/web-vault/app/shared/shared.module"; ], }), ] satisfies SafeProvider[], - imports: [SharedModule, NoItemsModule, LooseComponentsModule], + imports: [SharedModule, NoItemsModule, HeaderModule], }) export class DeviceApprovalsComponent implements OnInit, OnDestroy { tableDataSource = new TableDataSource(); diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations.module.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations.module.ts index e19d028b007..9fce712e325 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations.module.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations.module.ts @@ -1,6 +1,6 @@ import { NgModule } from "@angular/core"; -import { LooseComponentsModule } from "@bitwarden/web-vault/app/shared"; +import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.module"; import { SharedModule } from "@bitwarden/web-vault/app/shared/shared.module"; import { SsoComponent } from "../../auth/sso/sso.component"; @@ -11,7 +11,7 @@ import { ScimComponent } from "./manage/scim.component"; import { OrganizationsRoutingModule } from "./organizations-routing.module"; @NgModule({ - imports: [SharedModule, OrganizationsRoutingModule, LooseComponentsModule], + imports: [SharedModule, OrganizationsRoutingModule, HeaderModule], declarations: [ SsoComponent, ScimComponent, From 7ccb94d0a22dadde6c3d83b361301d0d067c2c1c Mon Sep 17 00:00:00 2001 From: Brandon Treston Date: Wed, 27 Aug 2025 09:25:36 -0400 Subject: [PATCH 055/167] fix missing null check (#16180) --- .../components/collection-dialog/collection-dialog.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts b/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts index 52c418a5211..5b207b5a688 100644 --- a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts +++ b/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts @@ -421,7 +421,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy { collectionView.users = this.formGroup.controls.access.value .filter((v) => v.type === AccessItemType.Member) .map(convertToSelectionView); - collectionView.defaultUserCollectionEmail = this.collection.defaultUserCollectionEmail; + collectionView.defaultUserCollectionEmail = this.collection?.defaultUserCollectionEmail; const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)); From fcc2bc96d1779110fa8b16e374f9ace6dcbaf038 Mon Sep 17 00:00:00 2001 From: Nick Krantz <125900171+nick-livefront@users.noreply.github.com> Date: Wed, 27 Aug 2025 09:03:44 -0500 Subject: [PATCH 056/167] [PM-21024] Use Server for Password Change URLs (#14912) * migrate change login password service to use bitwarden server rather than fetch directly - avoids CSP entirely * add `HelpUsersUpdatePasswords` policy to policy type * add `HelpUsersUpdatePasswordsPolicy` components * allow list description override for policy description * add `HelpUsersUpdatePasswordsPolicy` when the feature flag is enabled * apply `HelpUsersUpdatePasswords` to everyone in an org * use policy to guard the well known password API * fix tests * refactor to use `policyAppliesToUser$` * remove policy work for change password - this was removed from scope * update copy for show favicon setting - it now handles both favicons and change password urls * remove favicon setting description - no longer needed * only call change password service when the setting is enabled * add popover for permitting cipher details * import permit popover directly into the settings component * replace `nativeFetch` with `fetch` * use string literal to construct URL rather than `URL` class - The `getIconsUrl` can return with an appended path which the new URL constructor will strip when passed as the base parameter * use string literal to construct URL rather than `URL` class instance (#16045) - The `getIconsUrl` can return with an appended path which the new URL constructor will strip when passed as the base parameter * [PM-24716] UI changes for Change URI work (#16043) * use platform service to launch the URI - this allows desktop to open a separate browser instance rather than use electron * fix spacing on web app * add bitLink for focus/hover states * remove spacing around links --- apps/browser/src/_locales/en/messages.json | 18 +-- .../settings/appearance-v2.component.html | 5 +- .../popup/settings/appearance-v2.component.ts | 2 + .../src/app/accounts/settings.component.html | 7 +- .../src/app/accounts/settings.component.ts | 2 + apps/desktop/src/app/app.module.ts | 1 - apps/desktop/src/locales/en/messages.json | 13 +- .../app/settings/preferences.component.html | 28 ++-- .../src/app/settings/preferences.component.ts | 8 +- apps/web/src/locales/en/messages.json | 13 +- .../response/change-password-uri.response.ts | 10 ++ ...rmit-cipher-details-popover.component.html | 22 +++ ...permit-cipher-details-popover.component.ts | 19 +++ libs/vault/src/index.ts | 1 + ...ault-change-login-password.service.spec.ts | 143 ++++++++---------- .../default-change-login-password.service.ts | 93 +++++------- 16 files changed, 205 insertions(+), 180 deletions(-) create mode 100644 libs/common/src/vault/models/response/change-password-uri.response.ts create mode 100644 libs/vault/src/components/permit-cipher-details-popover/permit-cipher-details-popover.component.html create mode 100644 libs/vault/src/components/permit-cipher-details-popover/permit-cipher-details-popover.component.ts diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 8390bc59633..00e83004016 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -1760,14 +1760,8 @@ "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." - }, - "faviconDescAlt": { - "message": "Show a recognizable image next to each login. Applies to all logged in accounts." + "showIconsChangePasswordUrls": { + "message": "Show website icons and retrieve change password URLs" }, "enableBadgeCounter": { "message": "Show badge counter" @@ -4376,7 +4370,7 @@ }, "uriMatchDefaultStrategyHint": { "message": "URI match detection is how Bitwarden identifies autofill suggestions.", - "description": "Explains to the user that URI match detection determines how Bitwarden suggests autofill options, and clarifies that this default strategy applies when no specific match detection is set for a login item." + "description": "Explains to the user that URI match detection determines how Bitwarden suggests autofill options, and clarifies that this default strategy applies when no specific match detection is set for a login item." }, "regExAdvancedOptionWarning": { "message": "\"Regular expression\" is an advanced option with increased risk of exposing credentials.", @@ -5563,6 +5557,12 @@ "message": "Easily create strong and unique passwords by clicking on the Generate password button to help you keep your logins secure.", "description": "Aria label for the body content of the generator nudge" }, + "aboutThisSetting": { + "message": "About this setting" + }, + "permitCipherDetailsDescription": { + "message": "Bitwarden will use saved login URIs to identify which icon or change password URL should be used to improve your experience. No information is collected or saved when you use this service." + }, "noPermissionsViewPage": { "message": "You do not have permissions to view this page. Try logging in with a different account." }, diff --git a/apps/browser/src/vault/popup/settings/appearance-v2.component.html b/apps/browser/src/vault/popup/settings/appearance-v2.component.html index 4f7f2757e0e..c9598c76db0 100644 --- a/apps/browser/src/vault/popup/settings/appearance-v2.component.html +++ b/apps/browser/src/vault/popup/settings/appearance-v2.component.html @@ -45,7 +45,10 @@ - {{ "enableFavicon" | i18n }} + + {{ "showIconsChangePasswordUrls" | i18n }} + + diff --git a/apps/browser/src/vault/popup/settings/appearance-v2.component.ts b/apps/browser/src/vault/popup/settings/appearance-v2.component.ts index d998ef846d2..23a609bd008 100644 --- a/apps/browser/src/vault/popup/settings/appearance-v2.component.ts +++ b/apps/browser/src/vault/popup/settings/appearance-v2.component.ts @@ -23,6 +23,7 @@ import { Option, SelectModule, } from "@bitwarden/components"; +import { PermitCipherDetailsPopoverComponent } from "@bitwarden/vault"; import { PopupWidthOption } from "../../../platform/browser/browser-popup-utils"; import { PopOutComponent } from "../../../platform/popup/components/pop-out.component"; @@ -46,6 +47,7 @@ import { VaultPopupCopyButtonsService } from "../services/vault-popup-copy-butto ReactiveFormsModule, CheckboxModule, BadgeModule, + PermitCipherDetailsPopoverComponent, ], }) export class AppearanceV2Component implements OnInit { diff --git a/apps/desktop/src/app/accounts/settings.component.html b/apps/desktop/src/app/accounts/settings.component.html index a9fdcd2f088..091864e59ae 100644 --- a/apps/desktop/src/app/accounts/settings.component.html +++ b/apps/desktop/src/app/accounts/settings.component.html @@ -162,14 +162,15 @@ - {{ "enableFavicon" | i18n }} + {{ "showIconsChangePasswordUrls" | i18n }} +
+ +
- {{ "faviconDesc" | i18n }}
diff --git a/apps/desktop/src/app/accounts/settings.component.ts b/apps/desktop/src/app/accounts/settings.component.ts index fd17873a4b1..a6948c689cd 100644 --- a/apps/desktop/src/app/accounts/settings.component.ts +++ b/apps/desktop/src/app/accounts/settings.component.ts @@ -52,6 +52,7 @@ import { TypographyModule, } from "@bitwarden/components"; import { KeyService, BiometricStateService, BiometricsStatus } from "@bitwarden/key-management"; +import { PermitCipherDetailsPopoverComponent } from "@bitwarden/vault"; import { SetPinComponent } from "../../auth/components/set-pin.component"; import { SshAgentPromptType } from "../../autofill/models/ssh-agent-setting"; @@ -81,6 +82,7 @@ import { NativeMessagingManifestService } from "../services/native-messaging-man SelectModule, TypographyModule, VaultTimeoutInputComponent, + PermitCipherDetailsPopoverComponent, ], }) export class SettingsComponent implements OnInit, OnDestroy { diff --git a/apps/desktop/src/app/app.module.ts b/apps/desktop/src/app/app.module.ts index 014e29555e8..4f53e587994 100644 --- a/apps/desktop/src/app/app.module.ts +++ b/apps/desktop/src/app/app.module.ts @@ -31,7 +31,6 @@ import { SharedModule } from "./shared/shared.module"; @NgModule({ imports: [ BrowserAnimationsModule, - SharedModule, AppRoutingModule, VaultFilterModule, diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index eaa5f7f0f1e..c805096189b 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -1305,11 +1305,8 @@ "message": "Automatically clear copied values from your clipboard.", "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, - "enableFavicon": { - "message": "Show website icons" - }, - "faviconDesc": { - "message": "Show a recognizable image next to each login." + "showIconsChangePasswordUrls": { + "message": "Show website icons and retrieve change password URLs" }, "enableMinToTray": { "message": "Minimize to tray icon" @@ -3928,6 +3925,12 @@ "description": "Two part message", "example": "Store your keys and connect with the SSH agent for fast, encrypted authentication. Learn more about SSH agent" }, + "aboutThisSetting": { + "message": "About this setting" + }, + "permitCipherDetailsDescription": { + "message": "Bitwarden will use saved login URIs to identify which icon or change password URL should be used to improve your experience. No information is collected or saved when you use this service." + }, "assignToCollections": { "message": "Assign to collections" }, diff --git a/apps/web/src/app/settings/preferences.component.html b/apps/web/src/app/settings/preferences.component.html index 80261ecccb7..050d7395caf 100644 --- a/apps/web/src/app/settings/preferences.component.html +++ b/apps/web/src/app/settings/preferences.component.html @@ -67,23 +67,17 @@ {{ "languageDesc" | i18n }} - - - {{ "enableFavicon" | i18n }} - - - - - {{ "faviconDesc" | i18n }} - +
+ + + + {{ "showIconsChangePasswordUrls" | i18n }} + + +
+ +
+
{{ "theme" | i18n }} diff --git a/apps/web/src/app/settings/preferences.component.ts b/apps/web/src/app/settings/preferences.component.ts index e6cc35903a7..58a072ce76a 100644 --- a/apps/web/src/app/settings/preferences.component.ts +++ b/apps/web/src/app/settings/preferences.component.ts @@ -34,6 +34,7 @@ import { Theme, ThemeTypes } from "@bitwarden/common/platform/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service"; import { DialogService } from "@bitwarden/components"; +import { PermitCipherDetailsPopoverComponent } from "@bitwarden/vault"; import { HeaderModule } from "../layouts/header/header.module"; import { SharedModule } from "../shared"; @@ -41,7 +42,12 @@ import { SharedModule } from "../shared"; @Component({ selector: "app-preferences", templateUrl: "preferences.component.html", - imports: [SharedModule, HeaderModule, VaultTimeoutInputComponent], + imports: [ + SharedModule, + HeaderModule, + VaultTimeoutInputComponent, + PermitCipherDetailsPopoverComponent, + ], }) export class PreferencesComponent implements OnInit, OnDestroy { // For use in template diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index af80433fce7..e3856e7d645 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -2103,11 +2103,8 @@ "languageDesc": { "message": "Change the language used by the web vault." }, - "enableFavicon": { - "message": "Show website icons" - }, - "faviconDesc": { - "message": "Show a recognizable image next to each login." + "showIconsChangePasswordUrls": { + "message": "Show website icons and retrieve change password URLs" }, "default": { "message": "Default" @@ -10986,6 +10983,12 @@ "message": "Billing address required to add credit.", "description": "Error message shown when trying to add credit to a trialing organization without a billing address." }, + "aboutThisSetting": { + "message": "About this setting" + }, + "permitCipherDetailsDescription": { + "message": "Bitwarden will use saved login URIs to identify which icon or change password URL should be used to improve your experience. No information is collected or saved when you use this service." + }, "billingAddress": { "message": "Billing address" }, diff --git a/libs/common/src/vault/models/response/change-password-uri.response.ts b/libs/common/src/vault/models/response/change-password-uri.response.ts new file mode 100644 index 00000000000..1ff3424a269 --- /dev/null +++ b/libs/common/src/vault/models/response/change-password-uri.response.ts @@ -0,0 +1,10 @@ +import { BaseResponse } from "../../../models/response/base.response"; + +export class ChangePasswordUriResponse extends BaseResponse { + uri: string | null; + + constructor(response: any) { + super(response); + this.uri = this.getResponseProperty("uri"); + } +} diff --git a/libs/vault/src/components/permit-cipher-details-popover/permit-cipher-details-popover.component.html b/libs/vault/src/components/permit-cipher-details-popover/permit-cipher-details-popover.component.html new file mode 100644 index 00000000000..1833a148616 --- /dev/null +++ b/libs/vault/src/components/permit-cipher-details-popover/permit-cipher-details-popover.component.html @@ -0,0 +1,22 @@ + + + +

+ {{ "permitCipherDetailsDescription" | i18n }} +

+ +
diff --git a/libs/vault/src/components/permit-cipher-details-popover/permit-cipher-details-popover.component.ts b/libs/vault/src/components/permit-cipher-details-popover/permit-cipher-details-popover.component.ts new file mode 100644 index 00000000000..8e80ddf7810 --- /dev/null +++ b/libs/vault/src/components/permit-cipher-details-popover/permit-cipher-details-popover.component.ts @@ -0,0 +1,19 @@ +import { Component, inject } from "@angular/core"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { LinkModule, PopoverModule } from "@bitwarden/components"; + +@Component({ + selector: "vault-permit-cipher-details-popover", + templateUrl: "./permit-cipher-details-popover.component.html", + imports: [PopoverModule, JslibModule, LinkModule], +}) +export class PermitCipherDetailsPopoverComponent { + private platformUtilService = inject(PlatformUtilsService); + + openLearnMore(e: Event) { + e.preventDefault(); + this.platformUtilService.launchUri("https://bitwarden.com/help/website-icons/"); + } +} diff --git a/libs/vault/src/index.ts b/libs/vault/src/index.ts index f3925ac3379..efaefc77ade 100644 --- a/libs/vault/src/index.ts +++ b/libs/vault/src/index.ts @@ -20,6 +20,7 @@ export { openPasswordHistoryDialog } from "./components/password-history/passwor export * from "./components/add-edit-folder-dialog/add-edit-folder-dialog.component"; export * from "./components/carousel"; export * from "./components/new-cipher-menu/new-cipher-menu.component"; +export * from "./components/permit-cipher-details-popover/permit-cipher-details-popover.component"; export { DefaultSshImportPromptService } from "./services/default-ssh-import-prompt.service"; export { SshImportPromptService } from "./services/ssh-import-prompt.service"; diff --git a/libs/vault/src/services/default-change-login-password.service.spec.ts b/libs/vault/src/services/default-change-login-password.service.spec.ts index c9628797f4d..42242f2e4a8 100644 --- a/libs/vault/src/services/default-change-login-password.service.spec.ts +++ b/libs/vault/src/services/default-change-login-password.service.spec.ts @@ -4,10 +4,14 @@ */ import { mock } from "jest-mock-extended"; +import { BehaviorSubject, of } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { ClientType } from "@bitwarden/common/enums"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; +import { + Environment, + EnvironmentService, +} from "@bitwarden/common/platform/abstractions/environment.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view"; @@ -18,37 +22,30 @@ import { DefaultChangeLoginPasswordService } from "./default-change-login-passwo describe("DefaultChangeLoginPasswordService", () => { let service: DefaultChangeLoginPasswordService; - let mockShouldNotExistResponse: Response; - let mockWellKnownResponse: Response; - - const getClientType = jest.fn(() => ClientType.Browser); - const mockApiService = mock(); - const platformUtilsService = mock({ - getClientType, - }); + const mockDomainSettingsService = mock(); + + const showFavicons$ = new BehaviorSubject(true); beforeEach(() => { - mockApiService.nativeFetch.mockClear(); + mockApiService.fetch.mockClear(); + mockApiService.fetch.mockImplementation(() => + Promise.resolve({ ok: true, json: () => Promise.resolve({ uri: null }) } as Response), + ); - // Default responses to success state - mockShouldNotExistResponse = new Response("Not Found", { status: 404 }); - mockWellKnownResponse = new Response("OK", { status: 200 }); + mockDomainSettingsService.showFavicons$ = showFavicons$; - mockApiService.nativeFetch.mockImplementation((request) => { - if ( - request.url.endsWith("resource-that-should-not-exist-whose-status-code-should-not-be-200") - ) { - return Promise.resolve(mockShouldNotExistResponse); - } + const mockEnvironmentService = { + environment$: of({ + getIconsUrl: () => "https://icons.bitwarden.com", + } as Environment), + } as EnvironmentService; - if (request.url.endsWith(".well-known/change-password")) { - return Promise.resolve(mockWellKnownResponse); - } - - throw new Error("Unexpected request"); - }); - service = new DefaultChangeLoginPasswordService(mockApiService, platformUtilsService); + service = new DefaultChangeLoginPasswordService( + mockApiService, + mockEnvironmentService, + mockDomainSettingsService, + ); }); it("should return null for non-login ciphers", async () => { @@ -85,7 +82,7 @@ describe("DefaultChangeLoginPasswordService", () => { expect(url).toBeNull(); }); - it("should check the origin for a reliable status code", async () => { + it("should call the icons url endpoint", async () => { const cipher = { type: CipherType.Login, login: Object.assign(new LoginView(), { @@ -95,35 +92,42 @@ describe("DefaultChangeLoginPasswordService", () => { await service.getChangePasswordUrl(cipher); - expect(mockApiService.nativeFetch).toHaveBeenCalledWith( + expect(mockApiService.fetch).toHaveBeenCalledWith( expect.objectContaining({ - url: "https://example.com/.well-known/resource-that-should-not-exist-whose-status-code-should-not-be-200", + url: "https://icons.bitwarden.com/change-password-uri?uri=https%3A%2F%2Fexample.com%2F", }), ); }); - it("should attempt to fetch the well-known change password URL", async () => { + it("should return the original URI when unable to verify the response", async () => { + mockApiService.fetch.mockImplementation(() => + Promise.resolve({ ok: true, json: () => Promise.resolve({ uri: null }) } as Response), + ); + const cipher = { type: CipherType.Login, login: Object.assign(new LoginView(), { - uris: [{ uri: "https://example.com" }], + uris: [{ uri: "https://example.com/" }], }), } as CipherView; - await service.getChangePasswordUrl(cipher); + const url = await service.getChangePasswordUrl(cipher); - expect(mockApiService.nativeFetch).toHaveBeenCalledWith( - expect.objectContaining({ - url: "https://example.com/.well-known/change-password", - }), - ); + expect(url).toBe("https://example.com/"); }); - it("should return the well-known change password URL when successful at verifying the response", async () => { + it("should return the well known change url from the response", async () => { + mockApiService.fetch.mockImplementation(() => { + return Promise.resolve({ + ok: true, + json: () => Promise.resolve({ uri: "https://example.com/.well-known/change-password" }), + } as Response); + }); + const cipher = { type: CipherType.Login, login: Object.assign(new LoginView(), { - uris: [{ uri: "https://example.com" }], + uris: [{ uri: "https://example.com/" }, { uri: "https://working.com/" }], }), } as CipherView; @@ -132,49 +136,20 @@ describe("DefaultChangeLoginPasswordService", () => { expect(url).toBe("https://example.com/.well-known/change-password"); }); - it("should return the original URI when unable to verify the response", async () => { - mockShouldNotExistResponse = new Response("Ok", { status: 200 }); - - const cipher = { - type: CipherType.Login, - login: Object.assign(new LoginView(), { - uris: [{ uri: "https://example.com/" }], - }), - } as CipherView; - - const url = await service.getChangePasswordUrl(cipher); - - expect(url).toBe("https://example.com/"); - }); - - it("should return the original URI when the well-known URL is not found", async () => { - mockWellKnownResponse = new Response("Not Found", { status: 404 }); - - const cipher = { - type: CipherType.Login, - login: Object.assign(new LoginView(), { - uris: [{ uri: "https://example.com/" }], - }), - } as CipherView; - - const url = await service.getChangePasswordUrl(cipher); - - expect(url).toBe("https://example.com/"); - }); - it("should try the next URI if the first one fails", async () => { - mockApiService.nativeFetch.mockImplementation((request) => { - if ( - request.url.endsWith("resource-that-should-not-exist-whose-status-code-should-not-be-200") - ) { - return Promise.resolve(mockShouldNotExistResponse); + mockApiService.fetch.mockImplementation((request) => { + if (request.url.includes("no-wellknown.com")) { + return Promise.resolve({ + ok: true, + json: () => Promise.resolve({ uri: null }), + } as Response); } - if (request.url.endsWith(".well-known/change-password")) { - if (request.url.includes("working.com")) { - return Promise.resolve(mockWellKnownResponse); - } - return Promise.resolve(new Response("Not Found", { status: 404 })); + if (request.url.includes("working.com")) { + return Promise.resolve({ + ok: true, + json: () => Promise.resolve({ uri: "https://working.com/.well-known/change-password" }), + } as Response); } throw new Error("Unexpected request"); @@ -192,19 +167,19 @@ describe("DefaultChangeLoginPasswordService", () => { expect(url).toBe("https://working.com/.well-known/change-password"); }); - it("should return the first URI when the client type is not browser", async () => { - getClientType.mockReturnValue(ClientType.Web); + it("returns the first URI when `showFavicons$` setting is disabled", async () => { + showFavicons$.next(false); const cipher = { type: CipherType.Login, login: Object.assign(new LoginView(), { - uris: [{ uri: "https://example.com/" }, { uri: "https://example-2.com/" }], + uris: [{ uri: "https://example.com/" }, { uri: "https://another.com/" }], }), } as CipherView; const url = await service.getChangePasswordUrl(cipher); - expect(mockApiService.nativeFetch).not.toHaveBeenCalled(); expect(url).toBe("https://example.com/"); + expect(mockApiService.fetch).not.toHaveBeenCalled(); }); }); diff --git a/libs/vault/src/services/default-change-login-password.service.ts b/libs/vault/src/services/default-change-login-password.service.ts index a0b5646c5a9..929f5819c02 100644 --- a/libs/vault/src/services/default-change-login-password.service.ts +++ b/libs/vault/src/services/default-change-login-password.service.ts @@ -1,9 +1,12 @@ import { Injectable } from "@angular/core"; +import { firstValueFrom } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; +import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CipherType } from "@bitwarden/common/vault/enums"; +import { ChangePasswordUriResponse } from "@bitwarden/common/vault/models/response/change-password-uri.response"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { ChangeLoginPasswordService } from "../abstractions/change-login-password.service"; @@ -12,7 +15,8 @@ import { ChangeLoginPasswordService } from "../abstractions/change-login-passwor export class DefaultChangeLoginPasswordService implements ChangeLoginPasswordService { constructor( private apiService: ApiService, - private platformUtilsService: PlatformUtilsService, + private environmentService: EnvironmentService, + private domainSettingsService: DomainSettingsService, ) {} /** @@ -33,24 +37,19 @@ export class DefaultChangeLoginPasswordService implements ChangeLoginPasswordSer return null; } - // CSP policies on the web and desktop restrict the application from making - // cross-origin requests, breaking the below .well-known URL checks. - // For those platforms, this will short circuit and return the first URL. - // PM-21024 will build a solution for the server side to handle this. - if (this.platformUtilsService.getClientType() !== "browser") { + const enableFaviconChangePassword = await firstValueFrom( + this.domainSettingsService.showFavicons$, + ); + + // When the setting is not enabled, return the first URL + if (!enableFaviconChangePassword) { return urls[0].href; } for (const url of urls) { - const [reliable, wellKnownChangeUrl] = await Promise.all([ - this.hasReliableHttpStatusCode(url.origin), - this.getWellKnownChangePasswordUrl(url.origin), - ]); + const wellKnownChangeUrl = await this.fetchWellKnownChangePasswordUri(url.href); - // Some servers return a 200 OK for a resource that should not exist - // Which means we cannot trust the well-known URL is valid, so we skip it - // to avoid potentially sending users to a 404 page - if (reliable && wellKnownChangeUrl != null) { + if (wellKnownChangeUrl) { return wellKnownChangeUrl; } } @@ -60,55 +59,41 @@ export class DefaultChangeLoginPasswordService implements ChangeLoginPasswordSer } /** - * Checks if the server returns a non-200 status code for a resource that should not exist. - * See https://w3c.github.io/webappsec-change-password-url/response-code-reliability.html#semantics - * @param urlOrigin The origin of the URL to check + * Fetches the well-known change-password-uri for the given URL. + * @returns The full URL to the change password page, or null if it could not be found. */ - private async hasReliableHttpStatusCode(urlOrigin: string): Promise { - try { - const url = new URL( - "./.well-known/resource-that-should-not-exist-whose-status-code-should-not-be-200", - urlOrigin, - ); + private async fetchWellKnownChangePasswordUri(url: string): Promise { + const getChangePasswordUriRequest = await this.buildChangePasswordUriRequest(url); - const request = new Request(url, { - method: "GET", - mode: "same-origin", - credentials: "omit", - cache: "no-store", - redirect: "follow", - }); + const response = await this.apiService.fetch(getChangePasswordUriRequest); - const response = await this.apiService.nativeFetch(request); - return !response.ok; - } catch { - return false; + if (!response.ok) { + return null; } + + const data = await response.json(); + + const { uri } = new ChangePasswordUriResponse(data); + + return uri; } /** - * Builds a well-known change password URL for the given origin. Attempts to fetch the URL to ensure a valid response - * is returned. Returns null if the request throws or the response is not 200 OK. - * See https://w3c.github.io/webappsec-change-password-url/ - * @param urlOrigin The origin of the URL to check + * Construct the request for the change-password-uri endpoint. */ - private async getWellKnownChangePasswordUrl(urlOrigin: string): Promise { - try { - const url = new URL("./.well-known/change-password", urlOrigin); + private async buildChangePasswordUriRequest(cipherUri: string): Promise { + const searchParams = new URLSearchParams(); + searchParams.set("uri", cipherUri); - const request = new Request(url, { - method: "GET", - mode: "same-origin", - credentials: "omit", - cache: "no-store", - redirect: "follow", - }); + // The change-password-uri endpoint lives within the icons service + // as it uses decrypted cipher data. + const env = await firstValueFrom(this.environmentService.environment$); + const iconsUrl = env.getIconsUrl(); - const response = await this.apiService.nativeFetch(request); + const url = new URL(`${iconsUrl}/change-password-uri?${searchParams.toString()}`); - return response.ok ? url.toString() : null; - } catch { - return null; - } + return new Request(url, { + method: "GET", + }); } } From 4c960906fa2a3d18cd43a7875082ad6ce6665cda Mon Sep 17 00:00:00 2001 From: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> Date: Wed, 27 Aug 2025 16:32:18 +0200 Subject: [PATCH 057/167] Account Recovery with Key Connector enabled not working prior to removal of Master Password (#15616) --- libs/angular/src/auth/guards/auth.guard.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/libs/angular/src/auth/guards/auth.guard.ts b/libs/angular/src/auth/guards/auth.guard.ts index 8e8e70a6d29..37c464a804d 100644 --- a/libs/angular/src/auth/guards/auth.guard.ts +++ b/libs/angular/src/auth/guards/auth.guard.ts @@ -74,13 +74,6 @@ export const authGuard: CanActivateFn = async ( return router.createUrlTree(["lock"], { queryParams: { promptBiometric: true } }); } - if ( - !routerState.url.includes("remove-password") && - (await firstValueFrom(keyConnectorService.convertAccountRequired$)) - ) { - return router.createUrlTree(["/remove-password"]); - } - // Handle cases where a user needs to set a password when they don't already have one: // - TDE org user has been given "manage account recovery" permission // - TDE offboarding on a trusted device, where we have access to their encryption key wrap with their new password @@ -106,5 +99,14 @@ export const authGuard: CanActivateFn = async ( return router.createUrlTree([route]); } + // Remove password when Key Connector is enabled + if ( + forceSetPasswordReason == ForceSetPasswordReason.None && + !routerState.url.includes("remove-password") && + (await firstValueFrom(keyConnectorService.convertAccountRequired$)) + ) { + return router.createUrlTree(["/remove-password"]); + } + return true; }; From 5f7c0ae999970dbbb05a111d074eb20a7258da15 Mon Sep 17 00:00:00 2001 From: Addison Beck Date: Wed, 27 Aug 2025 11:56:42 -0400 Subject: [PATCH 058/167] build: ensure new libraries are added to the root jest.config (#16166) * Add missing libs to jest.config.js Added 15 missing libraries to the jest projects array: - libs/assets - libs/client-type - libs/core-test-utils - libs/dirt/card - libs/guid - libs/logging - libs/messaging-internal - libs/messaging - libs/serialization - libs/state-test-utils - libs/state - libs/storage-core - libs/storage-test-utils - libs/tools/export/vault-export/vault-export-ui - libs/user-core This ensures all existing libraries with jest.config.js files are included in CI test runs. * Update basic-lib generator to add new libs to jest.config.js - Added updateJestConfig function that automatically adds new libraries to jest.config.js - Function finds the appropriate alphabetical position for the new library - Added comprehensive tests for the new functionality - Ensures new libraries are included in CI test runs from creation This prevents the issue where new libraries are created but their tests are not run in CI because they are missing from the jest configuration. * Fix import statements in state-definitions and deserialization-helpers tests - Fixed ClientLocations import in state-definitions.spec.ts to use @bitwarden/storage-core instead of relative import - Simplified deserialization-helpers.spec.ts import to use library root @bitwarden/serialization --- jest.config.js | 25 +++++-- .../src/generators/basic-lib.spec.ts | 41 ++++++++++++ libs/nx-plugin/src/generators/basic-lib.ts | 65 +++++++++++++++++++ .../src/deserialization-helpers.spec.ts | 2 +- libs/state/src/core/state-definitions.spec.ts | 4 +- 5 files changed, 130 insertions(+), 7 deletions(-) diff --git a/jest.config.js b/jest.config.js index b0ffd2382ca..3e4fb665a8c 100644 --- a/jest.config.js +++ b/jest.config.js @@ -26,24 +26,39 @@ module.exports = { "/libs/admin-console/jest.config.js", "/libs/angular/jest.config.js", + "/libs/assets/jest.config.js", "/libs/auth/jest.config.js", "/libs/billing/jest.config.js", + "/libs/client-type/jest.config.js", "/libs/common/jest.config.js", "/libs/components/jest.config.js", + "/libs/core-test-utils/jest.config.js", + "/libs/dirt/card/jest.config.js", "/libs/eslint/jest.config.js", + "/libs/guid/jest.config.js", + "/libs/importer/jest.config.js", + "/libs/key-management/jest.config.js", + "/libs/key-management-ui/jest.config.js", + "/libs/logging/jest.config.js", + "/libs/messaging-internal/jest.config.js", + "/libs/messaging/jest.config.js", + "/libs/node/jest.config.js", + "/libs/platform/jest.config.js", + "/libs/serialization/jest.config.js", + "/libs/state-test-utils/jest.config.js", + "/libs/state/jest.config.js", + "/libs/storage-core/jest.config.js", + "/libs/storage-test-utils/jest.config.js", "/libs/tools/export/vault-export/vault-export-core/jest.config.js", + "/libs/tools/export/vault-export/vault-export-ui/jest.config.js", "/libs/tools/generator/core/jest.config.js", "/libs/tools/generator/components/jest.config.js", "/libs/tools/generator/extensions/history/jest.config.js", "/libs/tools/generator/extensions/legacy/jest.config.js", "/libs/tools/generator/extensions/navigation/jest.config.js", "/libs/tools/send/send-ui/jest.config.js", - "/libs/importer/jest.config.js", - "/libs/platform/jest.config.js", - "/libs/node/jest.config.js", + "/libs/user-core/jest.config.js", "/libs/vault/jest.config.js", - "/libs/key-management/jest.config.js", - "/libs/key-management-ui/jest.config.js", ], // Workaround for a memory leak that crashes tests in CI: diff --git a/libs/nx-plugin/src/generators/basic-lib.spec.ts b/libs/nx-plugin/src/generators/basic-lib.spec.ts index a0357ca1751..9fd7a702375 100644 --- a/libs/nx-plugin/src/generators/basic-lib.spec.ts +++ b/libs/nx-plugin/src/generators/basic-lib.spec.ts @@ -83,3 +83,44 @@ describe("basic-lib generator", () => { expect(tree.exists(`libs/test/src/test.spec.ts`)).toBeTruthy(); }); }); + +it("should update jest.config.js with new library", async () => { + // Create a mock jest.config.js with existing libs + const existingJestConfig = `module.exports = { + projects: [ + "/apps/browser/jest.config.js", + "/libs/admin-console/jest.config.js", + "/libs/auth/jest.config.js", + "/libs/vault/jest.config.js", + ], +};`; + tree.write("jest.config.js", existingJestConfig); + + await basicLibGenerator(tree, options); + + const jestConfigContent = tree.read("jest.config.js"); + expect(jestConfigContent).not.toBeNull(); + const jestConfig = jestConfigContent?.toString(); + + // Should contain the new library in alphabetical order + expect(jestConfig).toContain('"/libs/test/jest.config.js",'); + + // Should be in the right alphabetical position (after auth, before vault) + const authIndex = jestConfig?.indexOf('"/libs/auth/jest.config.js"'); + const testIndex = jestConfig?.indexOf('"/libs/test/jest.config.js"'); + const vaultIndex = jestConfig?.indexOf('"/libs/vault/jest.config.js"'); + + expect(authIndex).toBeDefined(); + expect(testIndex).toBeDefined(); + expect(vaultIndex).toBeDefined(); + expect(authIndex! < testIndex!).toBeTruthy(); + expect(testIndex! < vaultIndex!).toBeTruthy(); +}); + +it("should handle missing jest.config.js file gracefully", async () => { + const consoleSpy = jest.spyOn(console, "warn").mockImplementation(); + // Don't create jest.config.js file + await basicLibGenerator(tree, options); + expect(consoleSpy).toHaveBeenCalledWith("jest.config.js file not found at root"); + consoleSpy.mockRestore(); +}); diff --git a/libs/nx-plugin/src/generators/basic-lib.ts b/libs/nx-plugin/src/generators/basic-lib.ts index 6b214d18921..4f2f542ac89 100644 --- a/libs/nx-plugin/src/generators/basic-lib.ts +++ b/libs/nx-plugin/src/generators/basic-lib.ts @@ -53,6 +53,9 @@ export async function basicLibGenerator( // Update CODEOWNERS with the new lib updateCodeowners(tree, options.directory, options.name, options.team); + // Update jest.config.js with the new lib + updateJestConfig(tree, options.directory, options.name); + // Format all new files with prettier await formatFiles(tree); @@ -124,4 +127,66 @@ function updateCodeowners(tree: Tree, directory: string, name: string, team: str tree.write(codeownersPath, content + newLine); } +/** + * Updates the jest.config.js file to include the new library + * This ensures the library's tests are included in CI runs + * + * @param {Tree} tree - The virtual file system tree + * @param {string} directory - Directory where the library is created + * @param {string} name - The library name + */ +function updateJestConfig(tree: Tree, directory: string, name: string) { + const jestConfigPath = "jest.config.js"; + + if (!tree.exists(jestConfigPath)) { + console.warn("jest.config.js file not found at root"); + return; + } + + const content = tree.read(jestConfigPath)?.toString() || ""; + const libJestPath = `"/${directory}/${name}/jest.config.js",`; + + // Find the libs section and insert the new library in alphabetical order + const lines = content.split("\n"); + let insertIndex = -1; + let foundLibsSection = false; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + + // Check if we're in the libs section + if (line.includes('"/libs/')) { + foundLibsSection = true; + + // Extract the lib name for comparison + const match = line.match(/"libs([^"]+)/); + if (match) { + const existingLibName = match[1]; + + // If the new lib should come before this existing lib alphabetically + if (name < existingLibName) { + insertIndex = i; + break; + } + } + } + // If we were in libs section but hit a non-libs line, insert at end of libs + else if (foundLibsSection && !line.includes('"/libs/')) { + insertIndex = i; + break; + } + } + + if (insertIndex === -1) { + console.warn(`Could not find appropriate location to insert ${name} in jest.config.js`); + return; + } + + // Insert the new library line + lines.splice(insertIndex, 0, ` ${libJestPath}`); + + // Write back the updated content + tree.write(jestConfigPath, lines.join("\n")); +} + export default basicLibGenerator; diff --git a/libs/serialization/src/deserialization-helpers.spec.ts b/libs/serialization/src/deserialization-helpers.spec.ts index 1918673c8d2..0c4bd2f06eb 100644 --- a/libs/serialization/src/deserialization-helpers.spec.ts +++ b/libs/serialization/src/deserialization-helpers.spec.ts @@ -1,4 +1,4 @@ -import { record } from "@bitwarden/serialization/deserialization-helpers"; +import { record } from "@bitwarden/serialization"; describe("deserialization helpers", () => { describe("record", () => { diff --git a/libs/state/src/core/state-definitions.spec.ts b/libs/state/src/core/state-definitions.spec.ts index d0e6eb3082e..92b3f049a0c 100644 --- a/libs/state/src/core/state-definitions.spec.ts +++ b/libs/state/src/core/state-definitions.spec.ts @@ -1,4 +1,6 @@ -import { ClientLocations, StateDefinition } from "./state-definition"; +import { ClientLocations } from "@bitwarden/storage-core"; + +import { StateDefinition } from "./state-definition"; import * as stateDefinitionsRecord from "./state-definitions"; describe.each(["web", "cli", "desktop", "browser"])( From 38f62a01499b46d4ba9d9ddfeeffce2695645d12 Mon Sep 17 00:00:00 2001 From: Vicki League Date: Wed, 27 Aug 2025 12:40:16 -0400 Subject: [PATCH 059/167] [PM-25222] Fix svg alignment issues caused by new preflight defaults (#16181) --- libs/components/src/tw-theme-preflight.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libs/components/src/tw-theme-preflight.css b/libs/components/src/tw-theme-preflight.css index 3c38eba3bd3..e5f35885993 100644 --- a/libs/components/src/tw-theme-preflight.css +++ b/libs/components/src/tw-theme-preflight.css @@ -65,4 +65,9 @@ select { appearance: none; } + + /* overriding preflight since the apps were built assuming svgs are inline */ + svg { + display: inline; + } } From 4dd7e0cafa0b71ddc741c7191e7d51557fc2fe25 Mon Sep 17 00:00:00 2001 From: Alex <55413326+AlexRubik@users.noreply.github.com> Date: Wed, 27 Aug 2025 09:41:42 -0700 Subject: [PATCH 060/167] Messages: unmark critical (#16146) * Unmark as critical * Revert "Unmark as critical" This reverts commit 3fa79fc4988efefb9e2749ab04a4a60c75930246. * rename unmarkAsCriticalApp -> unmarkAsCritical --- apps/web/src/locales/en/messages.json | 4 ++-- .../app-table-row-scrollable.component.html | 4 ++-- .../access-intelligence/app-table-row-scrollable.component.ts | 2 +- .../access-intelligence/critical-applications.component.html | 2 +- .../access-intelligence/critical-applications.component.ts | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index e3856e7d645..7de7f119e3b 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -176,8 +176,8 @@ "totalApplications": { "message": "Total applications" }, - "unmarkAsCriticalApp": { - "message": "Unmark as critical app" + "unmarkAsCritical": { + "message": "Unmark as critical" }, "criticalApplicationSuccessfullyUnmarked": { "message": "Critical application successfully unmarked" diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/app-table-row-scrollable.component.html b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/app-table-row-scrollable.component.html index 8e48b5e107d..eb7544faf05 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/app-table-row-scrollable.component.html +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/app-table-row-scrollable.component.html @@ -88,8 +88,8 @@ > - diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/app-table-row-scrollable.component.ts b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/app-table-row-scrollable.component.ts index a729f21158f..c6923bf5c77 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/app-table-row-scrollable.component.ts +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/app-table-row-scrollable.component.ts @@ -19,6 +19,6 @@ export class AppTableRowScrollableComponent { @Input() selectedUrls: Set = new Set(); @Input() isDrawerIsOpenForThisRecord!: (applicationName: string) => boolean; @Input() showAppAtRiskMembers!: (applicationName: string) => void; - @Input() unmarkAsCriticalApp!: (applicationName: string) => void; + @Input() unmarkAsCritical!: (applicationName: string) => void; @Input() checkboxChange!: (applicationName: string, $event: Event) => void; } diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.html b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.html index ffef3f3b0b9..17967ccef0e 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.html +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.html @@ -83,6 +83,6 @@ [showRowMenuForCriticalApps]="true" [isDrawerIsOpenForThisRecord]="isDrawerOpenForTableRow" [showAppAtRiskMembers]="showAppAtRiskMembers" - [unmarkAsCriticalApp]="unmarkAsCriticalApp" + [unmarkAsCritical]="unmarkAsCritical" > diff --git a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.ts b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.ts index 531adc003c7..58e0f648749 100644 --- a/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.ts +++ b/bitwarden_license/bit-web/src/app/dirt/access-intelligence/critical-applications.component.ts @@ -106,7 +106,7 @@ export class CriticalApplicationsComponent implements OnInit { ); }; - unmarkAsCriticalApp = async (hostname: string) => { + unmarkAsCritical = async (hostname: string) => { try { await this.criticalAppsService.dropCriticalApp( this.organizationId as OrganizationId, From 1d5115f19050d81d58723b435581188928809bf0 Mon Sep 17 00:00:00 2001 From: cd-bitwarden <106776772+cd-bitwarden@users.noreply.github.com> Date: Wed, 27 Aug 2025 13:51:02 -0400 Subject: [PATCH 061/167] Making accessing a project only use one api call to getbyprojectid (#15854) --- .../guards/project-access.guard.spec.ts | 135 ------------------ .../projects/guards/project-access.guard.ts | 33 ----- .../project/project-secrets.component.html | 8 +- .../project/project-secrets.component.ts | 33 +---- .../projects/project/project.component.html | 2 +- .../projects/projects-routing.module.ts | 2 - 6 files changed, 12 insertions(+), 201 deletions(-) delete mode 100644 bitwarden_license/bit-web/src/app/secrets-manager/projects/guards/project-access.guard.spec.ts delete mode 100644 bitwarden_license/bit-web/src/app/secrets-manager/projects/guards/project-access.guard.ts diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/projects/guards/project-access.guard.spec.ts b/bitwarden_license/bit-web/src/app/secrets-manager/projects/guards/project-access.guard.spec.ts deleted file mode 100644 index 7523fa14a21..00000000000 --- a/bitwarden_license/bit-web/src/app/secrets-manager/projects/guards/project-access.guard.spec.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { Component } from "@angular/core"; -import { TestBed } from "@angular/core/testing"; -import { Router } from "@angular/router"; -import { RouterTestingModule } from "@angular/router/testing"; -import { MockProxy, mock } from "jest-mock-extended"; -import { of } from "rxjs"; - -import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec"; -import { UserId } from "@bitwarden/common/types/guid"; -import { ToastService } from "@bitwarden/components"; -import { RouterService } from "@bitwarden/web-vault/app/core"; - -import { ProjectView } from "../../models/view/project.view"; -import { ProjectService } from "../project.service"; - -import { projectAccessGuard } from "./project-access.guard"; - -@Component({ - template: "", - standalone: false, -}) -export class GuardedRouteTestComponent {} - -@Component({ - template: "", - standalone: false, -}) -export class RedirectTestComponent {} - -describe("Project Redirect Guard", () => { - let organizationService: MockProxy; - let routerService: MockProxy; - let projectServiceMock: MockProxy; - let i18nServiceMock: MockProxy; - let toastService: MockProxy; - let router: Router; - let accountService: FakeAccountService; - const userId = Utils.newGuid() as UserId; - - const smOrg1 = { id: "123", canAccessSecretsManager: true } as Organization; - const projectView = { - id: "123", - organizationId: "123", - name: "project-name", - creationDate: Date.now.toString(), - revisionDate: Date.now.toString(), - read: true, - write: true, - } as ProjectView; - - beforeEach(async () => { - organizationService = mock(); - routerService = mock(); - projectServiceMock = mock(); - i18nServiceMock = mock(); - toastService = mock(); - accountService = mockAccountServiceWith(userId); - - TestBed.configureTestingModule({ - imports: [ - RouterTestingModule.withRoutes([ - { - path: "sm/:organizationId/projects/:projectId", - component: GuardedRouteTestComponent, - canActivate: [projectAccessGuard], - }, - { - path: "sm", - component: RedirectTestComponent, - }, - { - path: "sm/:organizationId/projects", - component: RedirectTestComponent, - }, - ]), - ], - providers: [ - { provide: OrganizationService, useValue: organizationService }, - { provide: AccountService, useValue: accountService }, - { provide: RouterService, useValue: routerService }, - { provide: ProjectService, useValue: projectServiceMock }, - { provide: I18nService, useValue: i18nServiceMock }, - { provide: ToastService, useValue: toastService }, - ], - }); - - router = TestBed.inject(Router); - }); - - it("redirects to sm/{orgId}/projects/{projectId} if project exists", async () => { - // Arrange - organizationService.organizations$.mockReturnValue(of([smOrg1])); - projectServiceMock.getByProjectId.mockReturnValue(Promise.resolve(projectView)); - - // Act - await router.navigateByUrl("sm/123/projects/123"); - - // Assert - expect(router.url).toBe("/sm/123/projects/123"); - }); - - it("redirects to sm/projects if project does not exist", async () => { - // Arrange - organizationService.organizations$.mockReturnValue(of([smOrg1])); - - // Act - await router.navigateByUrl("sm/123/projects/124"); - - // Assert - expect(router.url).toBe("/sm/123/projects"); - }); - - it("redirects to sm/123/projects if exception occurs while looking for Project", async () => { - // Arrange - jest.spyOn(projectServiceMock, "getByProjectId").mockImplementation(() => { - throw new Error("Test error"); - }); - jest.spyOn(i18nServiceMock, "t").mockReturnValue("Project not found"); - - // Act - await router.navigateByUrl("sm/123/projects/123"); - // Assert - expect(toastService.showToast).toHaveBeenCalledWith({ - variant: "error", - title: null, - message: "Project not found", - }); - expect(router.url).toBe("/sm/123/projects"); - }); -}); diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/projects/guards/project-access.guard.ts b/bitwarden_license/bit-web/src/app/secrets-manager/projects/guards/project-access.guard.ts deleted file mode 100644 index 2c6723a56a2..00000000000 --- a/bitwarden_license/bit-web/src/app/secrets-manager/projects/guards/project-access.guard.ts +++ /dev/null @@ -1,33 +0,0 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore -import { inject } from "@angular/core"; -import { ActivatedRouteSnapshot, CanActivateFn, createUrlTreeFromSnapshot } from "@angular/router"; - -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { ToastService } from "@bitwarden/components"; - -import { ProjectService } from "../project.service"; - -/** - * Redirects to projects list if the user doesn't have access to project. - */ -export const projectAccessGuard: CanActivateFn = async (route: ActivatedRouteSnapshot) => { - const projectService = inject(ProjectService); - const toastService = inject(ToastService); - const i18nService = inject(I18nService); - - try { - const project = await projectService.getByProjectId(route.params.projectId); - if (project) { - return true; - } - } catch { - toastService.showToast({ - variant: "error", - title: null, - message: i18nService.t("notFound", i18nService.t("project")), - }); - return createUrlTreeFromSnapshot(route, ["/sm", route.params.organizationId, "projects"]); - } - return createUrlTreeFromSnapshot(route, ["/sm", route.params.organizationId, "projects"]); -}; diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project-secrets.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project-secrets.component.html index d9919ef6bac..7a2968cfb2c 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project-secrets.component.html +++ b/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project-secrets.component.html @@ -1,7 +1,7 @@ - - + +
; private organizationEnabled: boolean; + protected project = inject(ROUTER_OUTLET_DATA) as Signal; + readonly writeAccess = computed(() => this.project().write); + readonly projectExists = computed(() => !!this.project()); constructor( private route: ActivatedRoute, - private projectService: ProjectService, private secretService: SecretService, private dialogService: DialogService, private platformUtilsService: PlatformUtilsService, @@ -68,21 +61,9 @@ export class ProjectSecretsComponent implements OnInit { ) {} ngOnInit() { - // Refresh list if project is edited - const currentProjectEdited = this.projectService.project$.pipe( - filter((p) => p?.id === this.projectId), - startWith(null), - ); - - this.project$ = combineLatest([this.route.params, currentProjectEdited]).pipe( - switchMap(([params, _]) => { - return this.projectService.getByProjectId(params.projectId); - }), - ); - this.secrets$ = this.secretService.secret$.pipe( startWith(null), - combineLatestWith(this.route.params, currentProjectEdited), + combineLatestWith(this.route.params), switchMap(async ([_, params]) => { this.organizationId = params.organizationId; this.projectId = params.projectId; diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.html index d44d7898cac..ef7c8ff1275 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.html +++ b/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.html @@ -36,4 +36,4 @@ {{ "editProject" | i18n }} - + diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/projects/projects-routing.module.ts b/bitwarden_license/bit-web/src/app/secrets-manager/projects/projects-routing.module.ts index 231486703c9..6078520989a 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/projects/projects-routing.module.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/projects/projects-routing.module.ts @@ -1,7 +1,6 @@ import { NgModule } from "@angular/core"; import { RouterModule, Routes } from "@angular/router"; -import { projectAccessGuard } from "./guards/project-access.guard"; import { ProjectPeopleComponent } from "./project/project-people.component"; import { ProjectSecretsComponent } from "./project/project-secrets.component"; import { ProjectServiceAccountsComponent } from "./project/project-service-accounts.component"; @@ -16,7 +15,6 @@ const routes: Routes = [ { path: ":projectId", component: ProjectComponent, - canActivate: [projectAccessGuard], children: [ { path: "", From cde4890e5eba782d46a8adc05323c72629d17c73 Mon Sep 17 00:00:00 2001 From: Daniel Riera Date: Wed, 27 Aug 2025 15:34:35 -0400 Subject: [PATCH 062/167] PM-24791 [Defect] White box behind Save login notification UI (#16112) * PM-24791 * update snapshots --- .../overlay-notifications-content.service.spec.ts.snap | 2 +- .../content/overlay-notifications-content.service.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/browser/src/autofill/overlay/notifications/content/__snapshots__/overlay-notifications-content.service.spec.ts.snap b/apps/browser/src/autofill/overlay/notifications/content/__snapshots__/overlay-notifications-content.service.spec.ts.snap index 18c3baa876c..7bdde2560d0 100644 --- a/apps/browser/src/autofill/overlay/notifications/content/__snapshots__/overlay-notifications-content.service.spec.ts.snap +++ b/apps/browser/src/autofill/overlay/notifications/content/__snapshots__/overlay-notifications-content.service.spec.ts.snap @@ -8,7 +8,7 @@ exports[`OverlayNotificationsContentService opening the notification bar creates