mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-22 11:45:59 +01:00
[EC-772] Add i18n key typechecking in web (#4023)
This commit is contained in:
parent
b331f5b329
commit
5a1940f3f4
@ -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();
|
||||
|
@ -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<AbstractI18nService> {
|
||||
): Promise<I18nService> {
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
@ -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(),
|
||||
|
@ -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(
|
@ -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);
|
||||
|
@ -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],
|
||||
},
|
||||
{
|
||||
|
@ -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"
|
||||
|
@ -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(
|
@ -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();
|
||||
|
||||
|
@ -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 },
|
||||
|
@ -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;
|
||||
|
10
apps/web/src/app/core/web-i18n.pipe.ts
Normal file
10
apps/web/src/app/core/web-i18n.pipe.ts
Normal file
@ -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<WebI18nKey> {}
|
@ -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<WebI18nKey> {
|
||||
constructor(systemLanguage: string, localesDirectory: string) {
|
||||
super(systemLanguage || "en-US", localesDirectory, async (formattedLocale: string) => {
|
||||
const filePath =
|
@ -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<void>;
|
||||
|
@ -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" },
|
||||
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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<string, [string, BadgeTypes]>();
|
||||
passwordStrengthMap = new Map<string, [WebI18nKey, BadgeTypes]>();
|
||||
|
||||
private passwordStrengthCache = new Map<string, number>();
|
||||
|
||||
@ -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"];
|
||||
|
@ -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;
|
||||
|
@ -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<number>();
|
||||
@Output() onCanceled = new EventEmitter();
|
||||
|
||||
|
@ -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<ApiKeyResponse>;
|
||||
|
@ -53,10 +53,7 @@
|
||||
></i>
|
||||
{{ t.details }}
|
||||
</td>
|
||||
<td
|
||||
[ngClass]="{ 'text-strike': t.refunded }"
|
||||
title="{{ (t.refunded ? 'refunded' : '') | i18n }}"
|
||||
>
|
||||
<td [ngClass]="{ 'text-strike': t.refunded }" [title]="t.refunded ? ('refunded' | i18n) : ''">
|
||||
{{ t.amount | currency: "$" }}
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -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: [],
|
||||
|
@ -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);
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -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<string>();
|
||||
|
||||
searchPlaceholder: string;
|
||||
searchPlaceholder: WebI18nKey;
|
||||
searchText = "";
|
||||
|
||||
constructor(protected vaultFilterService: VaultFilterService) {
|
||||
|
@ -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": {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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[];
|
||||
}
|
||||
|
||||
|
@ -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<AccountProfile>;
|
||||
|
||||
constructor(private route: ActivatedRoute, private stateService: StateService) {
|
||||
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
@ -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<TKey = string> implements PipeTransform {
|
||||
constructor(private i18nService: I18nService<TKey>) {}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { Observable } from "rxjs";
|
||||
|
||||
export abstract class I18nService {
|
||||
export abstract class I18nService<TKey = string> {
|
||||
locale$: Observable<string>;
|
||||
supportedTranslationLocales: string[];
|
||||
translationLocale: string;
|
||||
collator: Intl.Collator;
|
||||
localeNames: Map<string, string>;
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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<TKey = string> implements I18nService<TKey> {
|
||||
private _locale = new ReplaySubject<string>(1);
|
||||
locale$: Observable<string> = 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]) {
|
Loading…
Reference in New Issue
Block a user