From 25f89e2a1c3a13733c280240baad8bfb1df9d397 Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Wed, 13 Mar 2024 10:35:46 -0500 Subject: [PATCH] [PM-6769] [SM-1158] Fix Translation pipe issues on main (#8319) * Require init in i18n service. this is needed to load translations and set translation locale * No longer need to cast i18n * Expose user preferred locale in i18nService This is for correctly displaying `default` when no locale has been set in preferences components. The `locale$` observable should always resolve to the currently locale currently being translated to. --- apps/browser/src/popup/services/init.service.ts | 1 + apps/desktop/src/app/accounts/settings.component.ts | 2 +- apps/web/src/app/core/init.service.ts | 4 +--- apps/web/src/app/core/tests/preloaded-english-i18n.module.ts | 1 + apps/web/src/app/settings/preferences.component.ts | 2 +- libs/common/src/platform/abstractions/i18n.service.ts | 2 ++ libs/common/src/platform/services/i18n.service.ts | 4 +++- libs/components/src/utils/i18n-mock.service.ts | 5 +++++ 8 files changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/browser/src/popup/services/init.service.ts b/apps/browser/src/popup/services/init.service.ts index 197854f59f..b0e80ab960 100644 --- a/apps/browser/src/popup/services/init.service.ts +++ b/apps/browser/src/popup/services/init.service.ts @@ -26,6 +26,7 @@ export class InitService { init() { return async () => { await this.stateService.init(); + await this.i18nService.init(); if (!BrowserPopupUtils.inPopup(window)) { window.document.body.classList.add("body-full"); diff --git a/apps/desktop/src/app/accounts/settings.component.ts b/apps/desktop/src/app/accounts/settings.component.ts index e7c860b01a..242e1533e9 100644 --- a/apps/desktop/src/app/accounts/settings.component.ts +++ b/apps/desktop/src/app/accounts/settings.component.ts @@ -264,7 +264,7 @@ export class SettingsComponent implements OnInit { enableDuckDuckGoBrowserIntegration: await this.stateService.getEnableDuckDuckGoBrowserIntegration(), theme: await firstValueFrom(this.themeStateService.selectedTheme$), - locale: await firstValueFrom(this.i18nService.locale$), + locale: await firstValueFrom(this.i18nService.userSetLocale$), }; this.form.setValue(initialValues, { emitEvent: false }); diff --git a/apps/web/src/app/core/init.service.ts b/apps/web/src/app/core/init.service.ts index f4768e0ee6..3d940f3596 100644 --- a/apps/web/src/app/core/init.service.ts +++ b/apps/web/src/app/core/init.service.ts @@ -19,8 +19,6 @@ import { ContainerService } from "@bitwarden/common/platform/services/container. import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; import { VaultTimeoutService } from "@bitwarden/common/services/vault-timeout/vault-timeout.service"; -import { I18nService } from "../core/i18n.service"; - @Injectable() export class InitService { constructor( @@ -52,7 +50,7 @@ export class InitService { setTimeout(() => this.notificationsService.init(), 3000); await this.vaultTimeoutService.init(true); - await (this.i18nService as I18nService).init(); + await this.i18nService.init(); (this.eventUploadService as EventUploadService).init(true); this.twoFactorService.init(); const htmlEl = this.win.document.documentElement; diff --git a/apps/web/src/app/core/tests/preloaded-english-i18n.module.ts b/apps/web/src/app/core/tests/preloaded-english-i18n.module.ts index 95d8404f1f..901f63badc 100644 --- a/apps/web/src/app/core/tests/preloaded-english-i18n.module.ts +++ b/apps/web/src/app/core/tests/preloaded-english-i18n.module.ts @@ -8,6 +8,7 @@ import eng from "../../../locales/en/messages.json"; class PreloadedEnglishI18nService extends TranslationService implements I18nService { translationLocale = "en"; + userSetLocale$: Observable = of("en"); locale$: Observable = of("en"); constructor() { super("en", "", () => { diff --git a/apps/web/src/app/settings/preferences.component.ts b/apps/web/src/app/settings/preferences.component.ts index dab89819fc..fd759cd036 100644 --- a/apps/web/src/app/settings/preferences.component.ts +++ b/apps/web/src/app/settings/preferences.component.ts @@ -141,7 +141,7 @@ export class PreferencesComponent implements OnInit { ), enableFavicons: !(await this.settingsService.getDisableFavicon()), theme: await firstValueFrom(this.themeStateService.selectedTheme$), - locale: (await firstValueFrom(this.i18nService.locale$)) ?? null, + locale: (await firstValueFrom(this.i18nService.userSetLocale$)) ?? null, }; this.startingLocale = initialFormValues.locale; this.form.setValue(initialFormValues, { emitEvent: false }); diff --git a/libs/common/src/platform/abstractions/i18n.service.ts b/libs/common/src/platform/abstractions/i18n.service.ts index 46fe1cd102..7b6eb9edc8 100644 --- a/libs/common/src/platform/abstractions/i18n.service.ts +++ b/libs/common/src/platform/abstractions/i18n.service.ts @@ -3,6 +3,8 @@ import { Observable } from "rxjs"; import { TranslationService } from "./translation.service"; export abstract class I18nService extends TranslationService { + userSetLocale$: Observable; locale$: Observable; abstract setLocale(locale: string): Promise; + abstract init(): Promise; } diff --git a/libs/common/src/platform/services/i18n.service.ts b/libs/common/src/platform/services/i18n.service.ts index 642d19155b..aa2692d20b 100644 --- a/libs/common/src/platform/services/i18n.service.ts +++ b/libs/common/src/platform/services/i18n.service.ts @@ -12,6 +12,7 @@ const LOCALE_KEY = new KeyDefinition(TRANSLATION_DISK, "locale", { export class I18nService extends TranslationService implements I18nServiceAbstraction { translationLocale: string; protected translationLocaleState: GlobalState; + userSetLocale$: Observable; locale$: Observable; constructor( @@ -22,7 +23,8 @@ export class I18nService extends TranslationService implements I18nServiceAbstra ) { super(systemLanguage, localesDirectory, getLocalesJson); this.translationLocaleState = globalStateProvider.get(LOCALE_KEY); - this.locale$ = this.translationLocaleState.state$.pipe(map((locale) => locale ?? null)); + this.userSetLocale$ = this.translationLocaleState.state$; + this.locale$ = this.userSetLocale$.pipe(map((locale) => locale ?? this.translationLocale)); } async setLocale(locale: string): Promise { diff --git a/libs/components/src/utils/i18n-mock.service.ts b/libs/components/src/utils/i18n-mock.service.ts index 2c4149bf40..6bccaddba5 100644 --- a/libs/components/src/utils/i18n-mock.service.ts +++ b/libs/components/src/utils/i18n-mock.service.ts @@ -3,6 +3,7 @@ import { Observable } from "rxjs"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; export class I18nMockService implements I18nService { + userSetLocale$: Observable; locale$: Observable; supportedTranslationLocales: string[]; translationLocale: string; @@ -38,4 +39,8 @@ export class I18nMockService implements I18nService { async setLocale(locale: string): Promise { throw new Error("Method not implemented."); } + + init(): Promise { + throw new Error("Method not implemented."); + } }