diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index bd70ef57c98..a2e8e553d9a 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -92,6 +92,7 @@ import { BrowserStateService as StateServiceAbstraction } from "../services/abst import AutofillService from "../services/autofill.service"; import { BrowserEnvironmentService } from "../services/browser-environment.service"; import { BrowserFolderService } from "../services/browser-folder.service"; +import BrowserI18nServiceImplementation from "../services/browser-i18n.service.implementation"; import { BrowserOrganizationService } from "../services/browser-organization.service"; import { BrowserPolicyService } from "../services/browser-policy.service"; import { BrowserSettingsService } from "../services/browser-settings.service"; @@ -101,7 +102,6 @@ import BrowserLocalStorageService from "../services/browserLocalStorage.service" import BrowserMessagingService from "../services/browserMessaging.service"; import BrowserMessagingPrivateModeBackgroundService from "../services/browserMessagingPrivateModeBackground.service"; import BrowserPlatformUtilsService from "../services/browserPlatformUtils.service"; -import I18nService from "../services/i18n.service"; import { KeyGenerationService } from "../services/keyGeneration.service"; import { LocalBackedSessionStorageService } from "../services/localBackedSessionStorage.service"; import { VaultFilterService } from "../services/vaultFilter.service"; @@ -260,7 +260,7 @@ export default class MainBackground { }, window ); - this.i18nService = new I18nService(BrowserApi.getUILanguage(window)); + this.i18nService = new BrowserI18nServiceImplementation(BrowserApi.getUILanguage(window)); this.encryptService = flagEnabled("multithreadDecryption") ? new MultithreadEncryptServiceImplementation( this.cryptoFunctionService, @@ -566,7 +566,7 @@ export default class MainBackground { await this.stateService.init(); await (this.vaultTimeoutService as VaultTimeoutService).init(true); - await (this.i18nService as I18nService).init(); + await (this.i18nService as BrowserI18nServiceImplementation).init(); await (this.eventUploadService as EventUploadService).init(true); await this.runtimeBackground.init(); await this.notificationBackground.init(); diff --git a/apps/browser/src/background/service_factories/i18n-service.factory.ts b/apps/browser/src/background/service_factories/i18n-service.factory.ts index 1ba61d70b34..4b040caa4df 100644 --- a/apps/browser/src/background/service_factories/i18n-service.factory.ts +++ b/apps/browser/src/background/service_factories/i18n-service.factory.ts @@ -1,7 +1,7 @@ -import { I18nService as AbstractI18nService } from "@bitwarden/common/abstractions/i18n.service"; -import { I18nService as BaseI18nService } from "@bitwarden/common/services/i18n.service"; +import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; +import { I18nServiceImplementation } from "@bitwarden/common/services/i18n.service.implementation"; -import I18nService from "../../services/i18n.service"; +import BrowserI18nServiceImplementation from "../../services/browser-i18n.service.implementation"; import { FactoryOptions, CachedServices, factory } from "./factory-options"; @@ -14,17 +14,17 @@ type I18nServiceFactoryOptions = FactoryOptions & { export type I18nServiceInitOptions = I18nServiceFactoryOptions; export async function i18nServiceFactory( - cache: { i18nService?: AbstractI18nService } & CachedServices, + cache: { i18nService?: I18nService } & CachedServices, opts: I18nServiceInitOptions -): Promise { +): Promise { const service = await factory( cache, "i18nService", opts, - () => new I18nService(opts.i18nServiceOptions.systemLanguage) + () => new BrowserI18nServiceImplementation(opts.i18nServiceOptions.systemLanguage) ); - if (!(service as BaseI18nService as any).inited) { - await (service as BaseI18nService).init(); + if (!(service as I18nServiceImplementation as any).inited) { + await (service as I18nServiceImplementation).init(); } return service; } diff --git a/apps/browser/src/services/i18n.service.ts b/apps/browser/src/services/browser-i18n.service.implementation.ts similarity index 90% rename from apps/browser/src/services/i18n.service.ts rename to apps/browser/src/services/browser-i18n.service.implementation.ts index eddd2559a1a..f530fecd1e8 100644 --- a/apps/browser/src/services/i18n.service.ts +++ b/apps/browser/src/services/browser-i18n.service.implementation.ts @@ -1,6 +1,6 @@ -import { I18nService as BaseI18nService } from "@bitwarden/common/services/i18n.service"; +import { I18nServiceImplementation } from "@bitwarden/common/services/i18n.service.implementation"; -export default class I18nService extends BaseI18nService { +export default class BrowserI18nServiceImplementation extends I18nServiceImplementation { constructor(systemLanguage: string) { super(systemLanguage, null, async (formattedLocale: string) => { // Deprecated diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts index 4395d935ce2..b51d4872868 100644 --- a/apps/cli/src/bw.ts +++ b/apps/cli/src/bw.ts @@ -55,9 +55,9 @@ import { NodeCryptoFunctionService } from "@bitwarden/node/services/node-crypto- import { Program } from "./program"; import { SendProgram } from "./send.program"; +import { CliI18nServiceImplementation } from "./services/cli-i18n.service.implementation"; import { CliPlatformUtilsService } from "./services/cli-platform-utils.service"; import { ConsoleLogService } from "./services/console-log.service"; -import { I18nService } from "./services/i18n.service"; import { LowdbStorageService } from "./services/lowdb-storage.service"; import { NodeApiService } from "./services/node-api.service"; import { NodeEnvSecureStorageService } from "./services/node-env-secure-storage.service"; @@ -74,7 +74,7 @@ export class Main { storageService: LowdbStorageService; secureStorageService: NodeEnvSecureStorageService; memoryStorageService: MemoryStorageService; - i18nService: I18nService; + i18nService: CliI18nServiceImplementation; platformUtilsService: CliPlatformUtilsService; cryptoService: CryptoService; tokenService: TokenService; @@ -136,7 +136,7 @@ export class Main { p = path.join(process.env.HOME, ".config/Bitwarden CLI"); } - this.i18nService = new I18nService("en", "./locales"); + this.i18nService = new CliI18nServiceImplementation("en", "./locales"); this.platformUtilsService = new CliPlatformUtilsService(ClientType.Cli, packageJson); this.logService = new ConsoleLogService( this.platformUtilsService.isDev(), diff --git a/apps/cli/src/services/i18n.service.ts b/apps/cli/src/services/cli-i18n.service.implementation.ts similarity index 76% rename from apps/cli/src/services/i18n.service.ts rename to apps/cli/src/services/cli-i18n.service.implementation.ts index f3e6eabc609..d96da00b468 100644 --- a/apps/cli/src/services/i18n.service.ts +++ b/apps/cli/src/services/cli-i18n.service.implementation.ts @@ -1,9 +1,9 @@ import * as fs from "fs"; import * as path from "path"; -import { I18nService as BaseI18nService } from "@bitwarden/common/services/i18n.service"; +import { I18nServiceImplementation } from "@bitwarden/common/services/i18n.service.implementation"; -export class I18nService extends BaseI18nService { +export class CliI18nServiceImplementation extends I18nServiceImplementation { constructor(systemLanguage: string, localesDirectory: string) { super(systemLanguage, localesDirectory, (formattedLocale: string) => { const filePath = path.join( diff --git a/apps/desktop/src/app/services/init.service.ts b/apps/desktop/src/app/services/init.service.ts index fd29631ab4b..91703592f09 100644 --- a/apps/desktop/src/app/services/init.service.ts +++ b/apps/desktop/src/app/services/init.service.ts @@ -17,7 +17,7 @@ import { ContainerService } from "@bitwarden/common/services/container.service"; import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; import { VaultTimeoutService } from "@bitwarden/common/services/vaultTimeout/vaultTimeout.service"; -import { I18nService } from "../../services/i18n.service"; +import { DesktopI18nServiceImplementation } from "../../services/desktop-i18n.service.implementation"; import { NativeMessagingService } from "../../services/native-messaging.service"; @Injectable() @@ -47,7 +47,7 @@ export class InitService { this.syncService.fullSync(true); (this.vaultTimeoutService as VaultTimeoutService).init(true); const locale = await this.stateService.getLocale(); - await (this.i18nService as I18nService).init(locale); + await (this.i18nService as DesktopI18nServiceImplementation).init(locale); (this.eventUploadService as EventUploadService).init(true); this.twoFactorService.init(); setTimeout(() => this.notificationsService.init(), 3000); diff --git a/apps/desktop/src/app/services/services.module.ts b/apps/desktop/src/app/services/services.module.ts index 28d27a9ce22..53d6a6e12fa 100644 --- a/apps/desktop/src/app/services/services.module.ts +++ b/apps/desktop/src/app/services/services.module.ts @@ -41,6 +41,7 @@ import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.s import { SystemService } from "@bitwarden/common/services/system.service"; import { Account } from "../../models/account"; +import { DesktopI18nServiceImplementation } from "../../services/desktop-i18n.service.implementation"; import { ElectronCryptoService } from "../../services/electron-crypto.service"; import { ElectronLogService } from "../../services/electron-log.service"; import { ElectronPlatformUtilsService } from "../../services/electron-platform-utils.service"; @@ -48,7 +49,6 @@ import { ElectronRendererMessagingService } from "../../services/electron-render import { ElectronRendererSecureStorageService } from "../../services/electron-renderer-secure-storage.service"; import { ElectronRendererStorageService } from "../../services/electron-renderer-storage.service"; import { EncryptedMessageHandlerService } from "../../services/encrypted-message-handler.service"; -import { I18nService } from "../../services/i18n.service"; import { NativeMessageHandlerService } from "../../services/native-message-handler.service"; import { NativeMessagingService } from "../../services/native-messaging.service"; import { PasswordRepromptService } from "../../services/password-reprompt.service"; @@ -101,7 +101,7 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK"); }, { provide: I18nServiceAbstraction, - useClass: I18nService, + useClass: DesktopI18nServiceImplementation, deps: [SYSTEM_LANGUAGE, LOCALES_DIRECTORY], }, { diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index f5a078cdcc5..6e4450ff38b 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -17,14 +17,14 @@ import { TrayMain } from "./main/tray.main"; import { UpdaterMain } from "./main/updater.main"; import { WindowMain } from "./main/window.main"; import { Account } from "./models/account"; +import { DesktopI18nServiceImplementation } from "./services/desktop-i18n.service.implementation"; import { ElectronLogService } from "./services/electron-log.service"; import { ElectronMainMessagingService } from "./services/electron-main-messaging.service"; import { ElectronStorageService } from "./services/electron-storage.service"; -import { I18nService } from "./services/i18n.service"; export class Main { logService: ElectronLogService; - i18nService: I18nService; + i18nService: DesktopI18nServiceImplementation; storageService: ElectronStorageService; memoryStorageService: MemoryStorageService; messagingService: ElectronMainMessagingService; @@ -73,7 +73,7 @@ export class Main { } this.logService = new ElectronLogService(null, app.getPath("userData")); - this.i18nService = new I18nService("en", "./locales/"); + this.i18nService = new DesktopI18nServiceImplementation("en", "./locales/"); const storageDefaults: any = {}; // Default vault timeout to "on restart", and action to "lock" diff --git a/apps/desktop/src/services/i18n.service.ts b/apps/desktop/src/services/desktop-i18n.service.implementation.ts similarity index 88% rename from apps/desktop/src/services/i18n.service.ts rename to apps/desktop/src/services/desktop-i18n.service.implementation.ts index e36af04c181..6eaf62ad04e 100644 --- a/apps/desktop/src/services/i18n.service.ts +++ b/apps/desktop/src/services/desktop-i18n.service.implementation.ts @@ -1,9 +1,9 @@ import * as fs from "fs"; import * as path from "path"; -import { I18nService as BaseI18nService } from "@bitwarden/common/services/i18n.service"; +import { I18nServiceImplementation } from "@bitwarden/common/services/i18n.service.implementation"; -export class I18nService extends BaseI18nService { +export class DesktopI18nServiceImplementation extends I18nServiceImplementation { constructor(systemLanguage: string, localesDirectory: string) { super(systemLanguage, localesDirectory, (formattedLocale: string) => { const filePath = path.join( diff --git a/apps/web/src/app/components/nested-checkbox.component.ts b/apps/web/src/app/components/nested-checkbox.component.ts index eebd01e25d1..24645b41a5b 100644 --- a/apps/web/src/app/components/nested-checkbox.component.ts +++ b/apps/web/src/app/components/nested-checkbox.component.ts @@ -2,13 +2,15 @@ import { Component, EventEmitter, Input, Output } from "@angular/core"; import { Utils } from "@bitwarden/common/misc/utils"; +import { WebI18nKey } from "../core/web-i18n.service.implementation"; + @Component({ selector: "app-nested-checkbox", templateUrl: "nested-checkbox.component.html", }) export class NestedCheckboxComponent { - @Input() parentId: string; - @Input() checkboxes: { id: string; get: () => boolean; set: (v: boolean) => void }[]; + @Input() parentId: WebI18nKey; + @Input() checkboxes: { id: WebI18nKey; get: () => boolean; set: (v: boolean) => void }[]; @Output() onSavedUser = new EventEmitter(); @Output() onDeletedUser = new EventEmitter(); diff --git a/apps/web/src/app/core/core.module.ts b/apps/web/src/app/core/core.module.ts index 8a37e5f44ac..46f64982eac 100644 --- a/apps/web/src/app/core/core.module.ts +++ b/apps/web/src/app/core/core.module.ts @@ -12,7 +12,7 @@ import { import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module"; import { ModalService as ModalServiceAbstraction } from "@bitwarden/angular/services/modal.service"; import { FileDownloadService } from "@bitwarden/common/abstractions/fileDownload/fileDownload.service"; -import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service"; +import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LoginService as LoginServiceAbstraction } from "@bitwarden/common/abstractions/login.service"; import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/abstractions/messaging.service"; import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@bitwarden/common/abstractions/passwordReprompt.service"; @@ -27,7 +27,6 @@ import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.s import { BroadcasterMessagingService } from "./broadcaster-messaging.service"; import { EventService } from "./event.service"; import { HtmlStorageService } from "./html-storage.service"; -import { I18nService } from "./i18n.service"; import { InitService } from "./init.service"; import { ModalService } from "./modal.service"; import { PasswordRepromptService } from "./password-reprompt.service"; @@ -36,6 +35,7 @@ import { RouterService } from "./router.service"; import { Account, GlobalState, StateService } from "./state"; import { StateMigrationService } from "./state-migration.service"; import { WebFileDownloadService } from "./web-file-download.service"; +import { WebI18nServiceImplementation } from "./web-i18n.service.implementation"; import { WebPlatformUtilsService } from "./web-platform-utils.service"; @NgModule({ @@ -46,6 +46,7 @@ import { WebPlatformUtilsService } from "./web-platform-utils.service"; RouterService, EventService, PolicyListService, + WebI18nServiceImplementation, { provide: APP_INITIALIZER, useFactory: (initService: InitService) => initService.init(), @@ -61,8 +62,8 @@ import { WebPlatformUtilsService } from "./web-platform-utils.service"; useValue: false, }, { - provide: I18nServiceAbstraction, - useClass: I18nService, + provide: I18nService, + useClass: WebI18nServiceImplementation, deps: [SYSTEM_LANGUAGE, LOCALES_DIRECTORY], }, { provide: AbstractStorageService, useClass: HtmlStorageService }, diff --git a/apps/web/src/app/core/init.service.ts b/apps/web/src/app/core/init.service.ts index 8baa7c0ddc6..fb93991214e 100644 --- a/apps/web/src/app/core/init.service.ts +++ b/apps/web/src/app/core/init.service.ts @@ -9,7 +9,7 @@ import { Urls, } from "@bitwarden/common/abstractions/environment.service"; import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service"; -import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/abstractions/i18n.service"; +import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service"; import { StateService as StateServiceAbstraction } from "@bitwarden/common/abstractions/state.service"; import { TwoFactorService as TwoFactorServiceAbstraction } from "@bitwarden/common/abstractions/twoFactor.service"; @@ -18,7 +18,7 @@ import { ContainerService } from "@bitwarden/common/services/container.service"; import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; import { VaultTimeoutService as VaultTimeoutService } from "@bitwarden/common/services/vaultTimeout/vaultTimeout.service"; -import { I18nService } from "./i18n.service"; +import { WebI18nServiceImplementation } from "./web-i18n.service.implementation"; @Injectable() export class InitService { @@ -27,7 +27,7 @@ export class InitService { private environmentService: EnvironmentServiceAbstraction, private notificationsService: NotificationsServiceAbstraction, private vaultTimeoutService: VaultTimeoutServiceAbstraction, - private i18nService: I18nServiceAbstraction, + private i18nService: I18nService, private eventUploadService: EventUploadServiceAbstraction, private twoFactorService: TwoFactorServiceAbstraction, private stateService: StateServiceAbstraction, @@ -47,7 +47,7 @@ export class InitService { setTimeout(() => this.notificationsService.init(), 3000); (this.vaultTimeoutService as VaultTimeoutService).init(true); const locale = await this.stateService.getLocale(); - await (this.i18nService as I18nService).init(locale); + await (this.i18nService as WebI18nServiceImplementation).init(locale); (this.eventUploadService as EventUploadService).init(true); this.twoFactorService.init(); const htmlEl = this.win.document.documentElement; diff --git a/apps/web/src/app/core/web-i18n.pipe.ts b/apps/web/src/app/core/web-i18n.pipe.ts new file mode 100644 index 00000000000..65b90c1fe5e --- /dev/null +++ b/apps/web/src/app/core/web-i18n.pipe.ts @@ -0,0 +1,10 @@ +import { Pipe } from "@angular/core"; + +import { I18nPipe } from "@bitwarden/angular/pipes/i18n.pipe"; + +import { WebI18nKey } from "./web-i18n.service.implementation"; + +@Pipe({ + name: "i18n", +}) +export class WebI18nPipe extends I18nPipe {} diff --git a/apps/web/src/app/core/i18n.service.ts b/apps/web/src/app/core/web-i18n.service.implementation.ts similarity index 78% rename from apps/web/src/app/core/i18n.service.ts rename to apps/web/src/app/core/web-i18n.service.implementation.ts index 843bb322919..ab1f1dc774a 100644 --- a/apps/web/src/app/core/i18n.service.ts +++ b/apps/web/src/app/core/web-i18n.service.implementation.ts @@ -1,6 +1,13 @@ -import { I18nService as BaseI18nService } from "@bitwarden/common/services/i18n.service"; +import { Injectable } from "@angular/core"; -export class I18nService extends BaseI18nService { +import { I18nServiceImplementation } from "@bitwarden/common/services/i18n.service.implementation"; + +import type eng from "../../locales/en/messages.json"; + +export type WebI18nKey = keyof typeof eng; + +@Injectable() +export class WebI18nServiceImplementation extends I18nServiceImplementation { constructor(systemLanguage: string, localesDirectory: string) { super(systemLanguage || "en-US", localesDirectory, async (formattedLocale: string) => { const filePath = diff --git a/apps/web/src/app/organizations/billing/adjust-subscription.component.ts b/apps/web/src/app/organizations/billing/adjust-subscription.component.ts index 00dd0cce30b..c7b43e9e52a 100644 --- a/apps/web/src/app/organizations/billing/adjust-subscription.component.ts +++ b/apps/web/src/app/organizations/billing/adjust-subscription.component.ts @@ -15,7 +15,7 @@ export class AdjustSubscription { @Input() maxAutoscaleSeats: number; @Input() currentSeatCount: number; @Input() seatPrice = 0; - @Input() interval = "year"; + @Input() interval: "month" | "year" = "year"; @Output() onAdjusted = new EventEmitter(); formPromise: Promise; diff --git a/apps/web/src/app/organizations/components/access-selector/access-selector.component.ts b/apps/web/src/app/organizations/components/access-selector/access-selector.component.ts index 98a49d5c3ab..833e0fcfc76 100644 --- a/apps/web/src/app/organizations/components/access-selector/access-selector.component.ts +++ b/apps/web/src/app/organizations/components/access-selector/access-selector.component.ts @@ -6,6 +6,8 @@ import { FormSelectionList } from "@bitwarden/angular/utils/form-selection-list" import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { SelectItemView } from "@bitwarden/components/src/multi-select/models/select-item-view"; +import { WebI18nKey } from "../../../core/web-i18n.service.implementation"; + import { AccessItemType, AccessItemValue, @@ -83,7 +85,7 @@ export class AccessSelectorComponent implements ControlValueAccessor, OnInit, On }); protected itemType = AccessItemType; - protected permissionList = [ + protected permissionList: { perm: CollectionPermission; labelId: WebI18nKey }[] = [ { perm: CollectionPermission.View, labelId: "canView" }, { perm: CollectionPermission.ViewExceptPass, labelId: "canViewExceptPass" }, { perm: CollectionPermission.Edit, labelId: "canEdit" }, diff --git a/apps/web/src/app/organizations/layouts/organization-layout.component.ts b/apps/web/src/app/organizations/layouts/organization-layout.component.ts index d8f2fdd8a33..f7768fe0d84 100644 --- a/apps/web/src/app/organizations/layouts/organization-layout.component.ts +++ b/apps/web/src/app/organizations/layouts/organization-layout.component.ts @@ -14,6 +14,8 @@ import { } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { Organization } from "@bitwarden/common/models/domain/organization"; +import { WebI18nKey } from "../../core/web-i18n.service.implementation"; + @Component({ selector: "app-organization-layout", templateUrl: "organization-layout.component.html", @@ -69,7 +71,7 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy { return canAccessBillingTab(organization); } - getReportTabLabel(organization: Organization): string { + getReportTabLabel(organization: Organization): WebI18nKey { return organization.useEvents ? "reporting" : "reports"; } } diff --git a/apps/web/src/app/organizations/manage/user-add-edit.component.ts b/apps/web/src/app/organizations/manage/user-add-edit.component.ts index b4cb7065f5e..5cfd3af3f92 100644 --- a/apps/web/src/app/organizations/manage/user-add-edit.component.ts +++ b/apps/web/src/app/organizations/manage/user-add-edit.component.ts @@ -20,6 +20,10 @@ import { SelectionReadOnlyRequest } from "@bitwarden/common/models/request/selec import { CollectionDetailsResponse } from "@bitwarden/common/models/response/collection.response"; import { CollectionView } from "@bitwarden/common/models/view/collection.view"; +import { WebI18nKey } from "../../core/web-i18n.service.implementation"; + +type NestedCheckbox = { id: WebI18nKey; get: () => boolean; set: (v: boolean) => boolean }; + @Component({ selector: "app-user-add-edit", templateUrl: "user-add-edit.component.html", @@ -49,7 +53,7 @@ export class UserAddEditComponent implements OnInit { organizationUserType = OrganizationUserType; canUseCustomPermissions: boolean; - manageAllCollectionsCheckboxes = [ + manageAllCollectionsCheckboxes: NestedCheckbox[] = [ { id: "createNewCollections", get: () => this.permissions.createNewCollections, @@ -67,7 +71,7 @@ export class UserAddEditComponent implements OnInit { }, ]; - manageAssignedCollectionsCheckboxes = [ + manageAssignedCollectionsCheckboxes: NestedCheckbox[] = [ { id: "editAssignedCollections", get: () => this.permissions.editAssignedCollections, diff --git a/apps/web/src/app/organizations/policies/base-policy.component.ts b/apps/web/src/app/organizations/policies/base-policy.component.ts index ef9635acb69..9abff55beed 100644 --- a/apps/web/src/app/organizations/policies/base-policy.component.ts +++ b/apps/web/src/app/organizations/policies/base-policy.component.ts @@ -6,9 +6,11 @@ import { Organization } from "@bitwarden/common/models/domain/organization"; import { PolicyRequest } from "@bitwarden/common/models/request/policy.request"; import { PolicyResponse } from "@bitwarden/common/models/response/policy.response"; +import { WebI18nKey } from "../../core/web-i18n.service.implementation"; + export abstract class BasePolicy { - abstract name: string; - abstract description: string; + abstract name: WebI18nKey; + abstract description: WebI18nKey; abstract type: PolicyType; abstract component: any; diff --git a/apps/web/src/app/organizations/policies/disable-send.component.ts b/apps/web/src/app/organizations/policies/disable-send.component.ts index 346627e7039..80aef6cee1d 100644 --- a/apps/web/src/app/organizations/policies/disable-send.component.ts +++ b/apps/web/src/app/organizations/policies/disable-send.component.ts @@ -5,8 +5,8 @@ import { PolicyType } from "@bitwarden/common/enums/policyType"; import { BasePolicy, BasePolicyComponent } from "./base-policy.component"; export class DisableSendPolicy extends BasePolicy { - name = "disableSend"; - description = "disableSendPolicyDesc"; + readonly name = "disableSend"; + readonly description = "disableSendPolicyDesc"; type = PolicyType.DisableSend; component = DisableSendPolicyComponent; } diff --git a/apps/web/src/app/organizations/policies/master-password.component.ts b/apps/web/src/app/organizations/policies/master-password.component.ts index a28a08ce9fd..b64b2679f94 100644 --- a/apps/web/src/app/organizations/policies/master-password.component.ts +++ b/apps/web/src/app/organizations/policies/master-password.component.ts @@ -8,8 +8,8 @@ import { PolicyType } from "@bitwarden/common/enums/policyType"; import { BasePolicy, BasePolicyComponent } from "./base-policy.component"; export class MasterPasswordPolicy extends BasePolicy { - name = "masterPassPolicyTitle"; - description = "masterPassPolicyDesc"; + readonly name = "masterPassPolicyTitle"; + readonly description = "masterPassPolicyDesc"; type = PolicyType.MasterPassword; component = MasterPasswordPolicyComponent; } diff --git a/apps/web/src/app/organizations/policies/password-generator.component.ts b/apps/web/src/app/organizations/policies/password-generator.component.ts index f975aae3ef9..da37c63c826 100644 --- a/apps/web/src/app/organizations/policies/password-generator.component.ts +++ b/apps/web/src/app/organizations/policies/password-generator.component.ts @@ -7,8 +7,8 @@ import { PolicyType } from "@bitwarden/common/enums/policyType"; import { BasePolicy, BasePolicyComponent } from "./base-policy.component"; export class PasswordGeneratorPolicy extends BasePolicy { - name = "passwordGenerator"; - description = "passwordGeneratorPolicyDesc"; + readonly name = "passwordGenerator"; + readonly description = "passwordGeneratorPolicyDesc"; type = PolicyType.PasswordGenerator; component = PasswordGeneratorPolicyComponent; } diff --git a/apps/web/src/app/organizations/policies/personal-ownership.component.ts b/apps/web/src/app/organizations/policies/personal-ownership.component.ts index 2caeaf168de..1778d6926ff 100644 --- a/apps/web/src/app/organizations/policies/personal-ownership.component.ts +++ b/apps/web/src/app/organizations/policies/personal-ownership.component.ts @@ -5,8 +5,8 @@ import { PolicyType } from "@bitwarden/common/enums/policyType"; import { BasePolicy, BasePolicyComponent } from "./base-policy.component"; export class PersonalOwnershipPolicy extends BasePolicy { - name = "personalOwnership"; - description = "personalOwnershipPolicyDesc"; + readonly name = "personalOwnership"; + readonly description = "personalOwnershipPolicyDesc"; type = PolicyType.PersonalOwnership; component = PersonalOwnershipPolicyComponent; } diff --git a/apps/web/src/app/organizations/policies/require-sso.component.ts b/apps/web/src/app/organizations/policies/require-sso.component.ts index a56f36c7f73..ecd19d5f32d 100644 --- a/apps/web/src/app/organizations/policies/require-sso.component.ts +++ b/apps/web/src/app/organizations/policies/require-sso.component.ts @@ -8,8 +8,8 @@ import { PolicyRequest } from "@bitwarden/common/models/request/policy.request"; import { BasePolicy, BasePolicyComponent } from "./base-policy.component"; export class RequireSsoPolicy extends BasePolicy { - name = "requireSso"; - description = "requireSsoPolicyDesc"; + readonly name = "requireSso"; + readonly description = "requireSsoPolicyDesc"; type = PolicyType.RequireSso; component = RequireSsoPolicyComponent; diff --git a/apps/web/src/app/organizations/policies/reset-password.component.ts b/apps/web/src/app/organizations/policies/reset-password.component.ts index 6f7fb26551b..a4762aefcf2 100644 --- a/apps/web/src/app/organizations/policies/reset-password.component.ts +++ b/apps/web/src/app/organizations/policies/reset-password.component.ts @@ -8,8 +8,8 @@ import { Organization } from "@bitwarden/common/models/domain/organization"; import { BasePolicy, BasePolicyComponent } from "./base-policy.component"; export class ResetPasswordPolicy extends BasePolicy { - name = "resetPasswordPolicy"; - description = "resetPasswordPolicyDescription"; + readonly name = "resetPasswordPolicy"; + readonly description = "resetPasswordPolicyDescription"; type = PolicyType.ResetPassword; component = ResetPasswordPolicyComponent; diff --git a/apps/web/src/app/organizations/policies/send-options.component.ts b/apps/web/src/app/organizations/policies/send-options.component.ts index 21e07e478cc..015ec51f588 100644 --- a/apps/web/src/app/organizations/policies/send-options.component.ts +++ b/apps/web/src/app/organizations/policies/send-options.component.ts @@ -6,8 +6,8 @@ import { PolicyType } from "@bitwarden/common/enums/policyType"; import { BasePolicy, BasePolicyComponent } from "./base-policy.component"; export class SendOptionsPolicy extends BasePolicy { - name = "sendOptions"; - description = "sendOptionsPolicyDesc"; + readonly name = "sendOptions"; + readonly description = "sendOptionsPolicyDesc"; type = PolicyType.SendOptions; component = SendOptionsPolicyComponent; } diff --git a/apps/web/src/app/organizations/policies/single-org.component.ts b/apps/web/src/app/organizations/policies/single-org.component.ts index 8b34d132df8..4f5d5527d1f 100644 --- a/apps/web/src/app/organizations/policies/single-org.component.ts +++ b/apps/web/src/app/organizations/policies/single-org.component.ts @@ -7,8 +7,8 @@ import { PolicyRequest } from "@bitwarden/common/models/request/policy.request"; import { BasePolicy, BasePolicyComponent } from "./base-policy.component"; export class SingleOrgPolicy extends BasePolicy { - name = "singleOrg"; - description = "singleOrgDesc"; + readonly name = "singleOrg"; + readonly description = "singleOrgDesc"; type = PolicyType.SingleOrg; component = SingleOrgPolicyComponent; } diff --git a/apps/web/src/app/organizations/policies/two-factor-authentication.component.ts b/apps/web/src/app/organizations/policies/two-factor-authentication.component.ts index d1c4df60d42..fbdeb66b572 100644 --- a/apps/web/src/app/organizations/policies/two-factor-authentication.component.ts +++ b/apps/web/src/app/organizations/policies/two-factor-authentication.component.ts @@ -5,8 +5,8 @@ import { PolicyType } from "@bitwarden/common/enums/policyType"; import { BasePolicy, BasePolicyComponent } from "./base-policy.component"; export class TwoFactorAuthenticationPolicy extends BasePolicy { - name = "twoStepLoginPolicyTitle"; - description = "twoStepLoginPolicyDesc"; + readonly name = "twoStepLoginPolicyTitle"; + readonly description = "twoStepLoginPolicyDesc"; type = PolicyType.TwoFactorAuthentication; component = TwoFactorAuthenticationPolicyComponent; } diff --git a/apps/web/src/app/organizations/settings/delete-organization.component.ts b/apps/web/src/app/organizations/settings/delete-organization.component.ts index 1857a94f4c9..b73f38a8e46 100644 --- a/apps/web/src/app/organizations/settings/delete-organization.component.ts +++ b/apps/web/src/app/organizations/settings/delete-organization.component.ts @@ -12,15 +12,17 @@ import { Utils } from "@bitwarden/common/misc/utils"; import { CipherView } from "@bitwarden/common/models/view/cipher.view"; import { Verification } from "@bitwarden/common/types/verification"; +import { WebI18nKey } from "../../core/web-i18n.service.implementation"; + class CountBasedLocalizationKey { - singular: string; - plural: string; + singular: WebI18nKey; + plural: WebI18nKey; getKey(count: number) { return count == 1 ? this.singular : this.plural; } - constructor(singular: string, plural: string) { + constructor(singular: WebI18nKey, plural: WebI18nKey) { this.singular = singular; this.plural = plural; } @@ -28,7 +30,7 @@ class CountBasedLocalizationKey { class OrganizationContentSummaryItem { count: number; - get localizationKey(): string { + get localizationKey() { return this.localizationKeyOptions.getKey(this.count); } private localizationKeyOptions: CountBasedLocalizationKey; @@ -126,6 +128,9 @@ export class DeleteOrganizationComponent implements OnInit { } private getOrganizationItemLocalizationKeysByType(type: string): CountBasedLocalizationKey { - return new CountBasedLocalizationKey(`type${type}`, `type${type}Plural`); + return new CountBasedLocalizationKey( + `type${type}` as WebI18nKey, + `type${type}Plural` as WebI18nKey + ); } } diff --git a/apps/web/src/app/reports/pages/weak-passwords-report.component.ts b/apps/web/src/app/reports/pages/weak-passwords-report.component.ts index b6a2278285f..d65238bdd18 100644 --- a/apps/web/src/app/reports/pages/weak-passwords-report.component.ts +++ b/apps/web/src/app/reports/pages/weak-passwords-report.component.ts @@ -10,6 +10,8 @@ import { CipherType } from "@bitwarden/common/enums/cipherType"; import { CipherView } from "@bitwarden/common/models/view/cipher.view"; import { BadgeTypes } from "@bitwarden/components"; +import { WebI18nKey } from "../../core/web-i18n.service.implementation"; + import { CipherReportComponent } from "./cipher-report.component"; @Component({ @@ -17,7 +19,7 @@ import { CipherReportComponent } from "./cipher-report.component"; templateUrl: "weak-passwords-report.component.html", }) export class WeakPasswordsReportComponent extends CipherReportComponent implements OnInit { - passwordStrengthMap = new Map(); + passwordStrengthMap = new Map(); private passwordStrengthCache = new Map(); @@ -111,7 +113,7 @@ export class WeakPasswordsReportComponent extends CipherReportComponent implemen return true; } - private scoreKey(score: number): [string, BadgeTypes] { + private scoreKey(score: number): [WebI18nKey, BadgeTypes] { switch (score) { case 4: return ["strong", "success"]; diff --git a/apps/web/src/app/reports/shared/models/report-entry.ts b/apps/web/src/app/reports/shared/models/report-entry.ts index d4da4e36763..deb0a03ba04 100644 --- a/apps/web/src/app/reports/shared/models/report-entry.ts +++ b/apps/web/src/app/reports/shared/models/report-entry.ts @@ -1,10 +1,12 @@ import { Icon } from "@bitwarden/components"; +import { WebI18nKey } from "../../../core/web-i18n.service.implementation"; + import { ReportVariant } from "./report-variant"; export type ReportEntry = { - title: string; - description: string; + title: WebI18nKey; + description: WebI18nKey; route: string; icon: Icon; variant: ReportVariant; diff --git a/apps/web/src/app/settings/adjust-storage.component.ts b/apps/web/src/app/settings/adjust-storage.component.ts index 20c93ced41c..7b25db60b6d 100644 --- a/apps/web/src/app/settings/adjust-storage.component.ts +++ b/apps/web/src/app/settings/adjust-storage.component.ts @@ -19,7 +19,7 @@ export class AdjustStorageComponent { @Input() storageGbPrice = 0; @Input() add = true; @Input() organizationId: string; - @Input() interval = "year"; + @Input() interval: "month" | "year" = "year"; @Output() onAdjusted = new EventEmitter(); @Output() onCanceled = new EventEmitter(); diff --git a/apps/web/src/app/settings/api-key.component.ts b/apps/web/src/app/settings/api-key.component.ts index ae376ffd69c..be76e35c22a 100644 --- a/apps/web/src/app/settings/api-key.component.ts +++ b/apps/web/src/app/settings/api-key.component.ts @@ -6,6 +6,8 @@ import { SecretVerificationRequest } from "@bitwarden/common/models/request/secr import { ApiKeyResponse } from "@bitwarden/common/models/response/api-key.response"; import { Verification } from "@bitwarden/common/types/verification"; +import { WebI18nKey } from "../core/web-i18n.service.implementation"; + @Component({ selector: "app-api-key", templateUrl: "api-key.component.html", @@ -17,9 +19,9 @@ export class ApiKeyComponent { entityId: string; scope: string; grantType: string; - apiKeyTitle: string; - apiKeyWarning: string; - apiKeyDescription: string; + apiKeyTitle: WebI18nKey; + apiKeyWarning: WebI18nKey; + apiKeyDescription: WebI18nKey; masterPassword: Verification; formPromise: Promise; diff --git a/apps/web/src/app/settings/billing-history.component.html b/apps/web/src/app/settings/billing-history.component.html index 27fd038a3b5..6f82a186ded 100644 --- a/apps/web/src/app/settings/billing-history.component.html +++ b/apps/web/src/app/settings/billing-history.component.html @@ -53,10 +53,7 @@ > {{ t.details }} - + {{ t.amount | currency: "$" }} diff --git a/apps/web/src/app/shared/shared.module.ts b/apps/web/src/app/shared/shared.module.ts index 1c84dff9f4e..e894b943534 100644 --- a/apps/web/src/app/shared/shared.module.ts +++ b/apps/web/src/app/shared/shared.module.ts @@ -27,6 +27,7 @@ import { // Register the locales for the application import "./locales"; +import { WebI18nPipe } from "../core/web-i18n.pipe"; /** * This NgModule should contain the most basic shared directives, pipes, and components. They @@ -65,6 +66,7 @@ import "./locales"; // Web specific ], + declarations: [WebI18nPipe], exports: [ CommonModule, DragDropModule, @@ -93,6 +95,7 @@ import "./locales"; ColorPasswordModule, // Web specific + WebI18nPipe, ], providers: [DatePipe], bootstrap: [], diff --git a/apps/web/src/app/tests/preloaded-english-i18n.module.ts b/apps/web/src/app/tests/preloaded-english-i18n.module.ts index e51fafc28f4..203a96b7f8f 100644 --- a/apps/web/src/app/tests/preloaded-english-i18n.module.ts +++ b/apps/web/src/app/tests/preloaded-english-i18n.module.ts @@ -1,11 +1,11 @@ import { APP_INITIALIZER, NgModule } from "@angular/core"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; -import { I18nService as BaseI18nService } from "@bitwarden/common/services/i18n.service"; +import { I18nServiceImplementation } from "@bitwarden/common/services/i18n.service.implementation"; import eng from "../../locales/en/messages.json"; -class PreloadedEnglishI18nService extends BaseI18nService { +class PreloadedEnglishI18nService extends I18nServiceImplementation { constructor() { super("en", "", () => { return Promise.resolve(eng); diff --git a/apps/web/src/app/vault/shared/vault.service.ts b/apps/web/src/app/vault/shared/vault.service.ts index 757261c859b..f2485d34fba 100644 --- a/apps/web/src/app/vault/shared/vault.service.ts +++ b/apps/web/src/app/vault/shared/vault.service.ts @@ -1,7 +1,9 @@ import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model"; +import { WebI18nKey } from "../../core/web-i18n.service.implementation"; + export class VaultService { - calculateSearchBarLocalizationString(vaultFilter: VaultFilter): string { + calculateSearchBarLocalizationString(vaultFilter: VaultFilter): WebI18nKey { if (vaultFilter.status === "favorites") { return "searchFavorites"; } diff --git a/apps/web/src/app/vault/vault-filter/vault-filter.component.ts b/apps/web/src/app/vault/vault-filter/vault-filter.component.ts index aaa2c839a9f..db57d691f23 100644 --- a/apps/web/src/app/vault/vault-filter/vault-filter.component.ts +++ b/apps/web/src/app/vault/vault-filter/vault-filter.component.ts @@ -2,6 +2,8 @@ import { Component, EventEmitter, Output } from "@angular/core"; import { VaultFilterComponent as BaseVaultFilterComponent } from "@bitwarden/angular/vault/vault-filter/components/vault-filter.component"; +import { WebI18nKey } from "../../core/web-i18n.service.implementation"; + import { VaultFilterService } from "./shared/vault-filter.service"; @Component({ @@ -12,7 +14,7 @@ import { VaultFilterService } from "./shared/vault-filter.service"; export class VaultFilterComponent extends BaseVaultFilterComponent { @Output() onSearchTextChanged = new EventEmitter(); - searchPlaceholder: string; + searchPlaceholder: WebI18nKey; searchText = ""; constructor(protected vaultFilterService: VaultFilterService) { diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 7960c6febbd..66b50bef0f0 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -5783,6 +5783,18 @@ "memberAccessAll": { "message": "This member can access and modify all items." }, + "searchMyVault": { + "message": "Search My Vault" + }, + "searchOrganization": { + "message": "Search organization" + }, + "noClientsInList": { + "message": "No clients in list" + }, + "copy": { + "messages": "Copy" + }, "freeOrgInvLimitReachedManageBilling": { "message": "Free organizations may have up to $SEATCOUNT$ members. Upgrade to a paid plan to invite more members.", "placeholders": { diff --git a/bitwarden_license/bit-web/src/app/policies/disable-personal-vault-export.component.ts b/bitwarden_license/bit-web/src/app/policies/disable-personal-vault-export.component.ts index bd43b56afea..a48d8c5fce9 100644 --- a/bitwarden_license/bit-web/src/app/policies/disable-personal-vault-export.component.ts +++ b/bitwarden_license/bit-web/src/app/policies/disable-personal-vault-export.component.ts @@ -7,8 +7,8 @@ import { } from "@bitwarden/web-vault/app/organizations/policies/base-policy.component"; export class DisablePersonalVaultExportPolicy extends BasePolicy { - name = "disablePersonalVaultExport"; - description = "disablePersonalVaultExportDesc"; + readonly name = "disablePersonalVaultExport"; + readonly description = "disablePersonalVaultExportDesc"; type = PolicyType.DisablePersonalVaultExport; component = DisablePersonalVaultExportPolicyComponent; } diff --git a/bitwarden_license/bit-web/src/app/policies/maximum-vault-timeout.component.ts b/bitwarden_license/bit-web/src/app/policies/maximum-vault-timeout.component.ts index c1e193fc649..ce57e3e1744 100644 --- a/bitwarden_license/bit-web/src/app/policies/maximum-vault-timeout.component.ts +++ b/bitwarden_license/bit-web/src/app/policies/maximum-vault-timeout.component.ts @@ -10,8 +10,8 @@ import { } from "@bitwarden/web-vault/app/organizations/policies/base-policy.component"; export class MaximumVaultTimeoutPolicy extends BasePolicy { - name = "maximumVaultTimeout"; - description = "maximumVaultTimeoutDesc"; + readonly name = "maximumVaultTimeout"; + readonly description = "maximumVaultTimeoutDesc"; type = PolicyType.MaximumVaultTimeout; component = MaximumVaultTimeoutPolicyComponent; } diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/layout/dialogs/bulk-status-dialog.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/layout/dialogs/bulk-status-dialog.component.ts index 08525646f80..31090d080bd 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/layout/dialogs/bulk-status-dialog.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/layout/dialogs/bulk-status-dialog.component.ts @@ -1,11 +1,13 @@ import { DialogRef, DIALOG_DATA } from "@angular/cdk/dialog"; import { Component, Inject, OnInit } from "@angular/core"; +import { WebI18nKey } from "@bitwarden/web-vault/app/core/web-i18n.service.implementation"; + export interface BulkStatusDetails { - title: string; - subTitle: string; - columnTitle: string; - message: string; + title: WebI18nKey; + subTitle: WebI18nKey; + columnTitle: WebI18nKey; + message: WebI18nKey; details: BulkOperationStatus[]; } diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/layout/header.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/layout/header.component.ts index 8ad4e6a68e2..e2aebea60b2 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/layout/header.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/layout/header.component.ts @@ -4,6 +4,7 @@ import { combineLatest, map, Observable } from "rxjs"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { AccountProfile } from "@bitwarden/common/models/domain/account"; +import { WebI18nKey } from "@bitwarden/web-vault/app/core/web-i18n.service.implementation"; @Component({ selector: "sm-header", @@ -13,7 +14,7 @@ export class HeaderComponent { @Input() title: string; @Input() searchTitle: string; - protected routeData$: Observable<{ title: string; searchTitle: string }>; + protected routeData$: Observable<{ title: WebI18nKey; searchTitle: WebI18nKey }>; protected account$: Observable; constructor(private route: ActivatedRoute, private stateService: StateService) { diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/access/access-list.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/access/access-list.component.ts index 483835b2bb6..1b334dc1b4c 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/access/access-list.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/access/access-list.component.ts @@ -1,6 +1,8 @@ import { SelectionModel } from "@angular/cdk/collections"; import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { WebI18nKey } from "@bitwarden/web-vault/app/core/web-i18n.service.implementation"; + import { AccessTokenView } from "../models/view/access-token.view"; @Component({ @@ -34,7 +36,7 @@ export class AccessListComponent { : this.selection.select(...this.tokens.map((s) => s.id)); } - protected permission(token: AccessTokenView) { + protected permission(token: AccessTokenView): WebI18nKey { return "canRead"; } } diff --git a/libs/angular/src/pipes/i18n.pipe.ts b/libs/angular/src/pipes/i18n.pipe.ts index afab9b8d024..d362bdbca8f 100644 --- a/libs/angular/src/pipes/i18n.pipe.ts +++ b/libs/angular/src/pipes/i18n.pipe.ts @@ -5,10 +5,10 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; @Pipe({ name: "i18n", }) -export class I18nPipe implements PipeTransform { - constructor(private i18nService: I18nService) {} +export class I18nPipe implements PipeTransform { + constructor(private i18nService: I18nService) {} - transform(id: string, p1?: string | number, p2?: string | number, p3?: string | number): string { + transform(id: TKey, p1?: string | number, p2?: string | number, p3?: string | number): string { return this.i18nService.t(id, p1, p2, p3); } } diff --git a/libs/angular/src/vault/vault-filter/models/top-level-tree-node.model.ts b/libs/angular/src/vault/vault-filter/models/top-level-tree-node.model.ts index 8930e05132e..87628e372e3 100644 --- a/libs/angular/src/vault/vault-filter/models/top-level-tree-node.model.ts +++ b/libs/angular/src/vault/vault-filter/models/top-level-tree-node.model.ts @@ -1,7 +1,8 @@ import { ITreeNodeObject } from "@bitwarden/common/models/domain/tree-node"; export type TopLevelTreeNodeId = "vaults" | "types" | "collections" | "folders"; +export type TopLevelTreeNodeName = "allVaults" | "types" | "collections" | "folders"; export class TopLevelTreeNode implements ITreeNodeObject { id: TopLevelTreeNodeId; - name: string; // localizationString + name: TopLevelTreeNodeName; // localizationString } diff --git a/libs/common/src/abstractions/i18n.service.ts b/libs/common/src/abstractions/i18n.service.ts index f4a9b8ceef8..d37c10438b7 100644 --- a/libs/common/src/abstractions/i18n.service.ts +++ b/libs/common/src/abstractions/i18n.service.ts @@ -1,11 +1,11 @@ import { Observable } from "rxjs"; -export abstract class I18nService { +export abstract class I18nService { locale$: Observable; supportedTranslationLocales: string[]; translationLocale: string; collator: Intl.Collator; localeNames: Map; - t: (id: string, p1?: string | number, p2?: string | number, p3?: string | number) => string; - translate: (id: string, p1?: string, p2?: string, p3?: string) => string; + t: (id: TKey, p1?: string | number, p2?: string | number, p3?: string | number) => string; + translate: (id: TKey, p1?: string, p2?: string, p3?: string) => string; } diff --git a/libs/common/src/models/response/plan.response.ts b/libs/common/src/models/response/plan.response.ts index fcb23b5a13f..c9aa1811db7 100644 --- a/libs/common/src/models/response/plan.response.ts +++ b/libs/common/src/models/response/plan.response.ts @@ -8,8 +8,12 @@ export class PlanResponse extends BaseResponse { product: ProductType; name: string; isAnnual: boolean; - nameLocalizationKey: string; - descriptionLocalizationKey: string; + nameLocalizationKey: "planNameFree" | "planNameFamilies" | "planNameTeams" | "planNameEnterprise"; + descriptionLocalizationKey: + | "planDescFree" + | "planDescFamilies" + | "planDescTeams" + | "planDescEnterprise"; canBeUsedByBusiness: boolean; baseSeats: number; baseStorageGb: number; diff --git a/libs/common/src/models/response/subscription.response.ts b/libs/common/src/models/response/subscription.response.ts index 1b5f57a32db..57c19f6619f 100644 --- a/libs/common/src/models/response/subscription.response.ts +++ b/libs/common/src/models/response/subscription.response.ts @@ -60,7 +60,7 @@ export class BillingSubscriptionItemResponse extends BaseResponse { name: string; amount: number; quantity: number; - interval: string; + interval: "month" | "year"; sponsoredSubscriptionItem: boolean; constructor(response: any) { diff --git a/libs/common/src/services/i18n.service.ts b/libs/common/src/services/i18n.service.implementation.ts similarity index 94% rename from libs/common/src/services/i18n.service.ts rename to libs/common/src/services/i18n.service.implementation.ts index 9fd39b092a0..a19130f039e 100644 --- a/libs/common/src/services/i18n.service.ts +++ b/libs/common/src/services/i18n.service.implementation.ts @@ -1,8 +1,8 @@ import { Observable, ReplaySubject } from "rxjs"; -import { I18nService as I18nServiceAbstraction } from "../abstractions/i18n.service"; +import { I18nService } from "../abstractions/i18n.service"; -export class I18nService implements I18nServiceAbstraction { +export class I18nServiceImplementation implements I18nService { private _locale = new ReplaySubject(1); locale$: Observable = this._locale.asObservable(); // First locale is the default (English) @@ -118,11 +118,11 @@ export class I18nService implements I18nServiceAbstraction { } } - t(id: string, p1?: string, p2?: string, p3?: string): string { + t(id: TKey, p1?: string, p2?: string, p3?: string): string { return this.translate(id, p1, p2, p3); } - translate(id: string, p1?: string | number, p2?: string | number, p3?: string | number): string { + translate(id: TKey, p1?: string | number, p2?: string | number, p3?: string | number): string { let result: string; // eslint-disable-next-line if (this.localeMessages.hasOwnProperty(id) && this.localeMessages[id]) {