1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 00:03:56 +00:00

[PM-6511] New i18n for angular (#8122)

* Use state provider to store preferred language

* migrate preferred language

* Use new i18n provider to get LOCAL_ID

* Fix preloaded english i18n

This is a mock service that forces english translations, it doesn't need the i18n interface that allows changing of locales.

* PR improvements

* Fixup merge
This commit is contained in:
Matt Gibson
2024-03-11 12:59:19 -05:00
committed by GitHub
parent c10a59b019
commit f4150ffda6
25 changed files with 278 additions and 106 deletions

View File

@@ -264,7 +264,7 @@ export class SettingsComponent implements OnInit {
enableDuckDuckGoBrowserIntegration:
await this.stateService.getEnableDuckDuckGoBrowserIntegration(),
theme: await this.stateService.getTheme(),
locale: (await this.stateService.getLocale()) ?? null,
locale: await firstValueFrom(this.i18nService.locale$),
};
this.form.setValue(initialValues, { emitEvent: false });
@@ -553,7 +553,7 @@ export class SettingsComponent implements OnInit {
}
async saveLocale() {
await this.stateService.setLocale(this.form.value.locale);
await this.i18nService.setLocale(this.form.value.locale);
}
async saveTheme() {

View File

@@ -52,8 +52,7 @@ export class InitService {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.syncService.fullSync(true);
await this.vaultTimeoutService.init(true);
const locale = await this.stateService.getLocale();
await (this.i18nService as I18nRendererService).init(locale);
await (this.i18nService as I18nRendererService).init();
(this.eventUploadService as EventUploadService).init(true);
this.twoFactorService.init();
setTimeout(() => this.notificationsService.init(), 3000);

View File

@@ -43,7 +43,7 @@ import { GlobalState } from "@bitwarden/common/platform/models/domain/global-sta
import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service";
import { MigrationRunner } from "@bitwarden/common/platform/services/migration-runner";
import { SystemService } from "@bitwarden/common/platform/services/system.service";
import { StateProvider } from "@bitwarden/common/platform/state";
import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/state";
// eslint-disable-next-line import/no-restricted-paths -- Implementation for memory storage
import { MemoryStorageService as MemoryStorageServiceForStateProviders } from "@bitwarden/common/platform/state/storage/memory-storage.service";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
@@ -104,7 +104,7 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
{
provide: I18nServiceAbstraction,
useClass: I18nRendererService,
deps: [SYSTEM_LANGUAGE, LOCALES_DIRECTORY],
deps: [SYSTEM_LANGUAGE, LOCALES_DIRECTORY, GlobalStateProvider],
},
{
provide: MessagingServiceAbstraction,

View File

@@ -97,7 +97,6 @@ export class Main {
}
this.logService = new ElectronLogMainService(null, app.getPath("userData"));
this.i18nService = new I18nMainService("en", "./locales/");
const storageDefaults: any = {};
// Default vault timeout to "on restart", and action to "lock"
@@ -112,6 +111,8 @@ export class Main {
);
const globalStateProvider = new DefaultGlobalStateProvider(storageServiceProvider);
this.i18nService = new I18nMainService("en", "./locales/", globalStateProvider);
const accountService = new AccountServiceImplementation(
new NoopMessagingService(),
this.logService,
@@ -218,8 +219,7 @@ export class Main {
this.migrationRunner.run().then(
async () => {
await this.windowMain.init();
const locale = await this.stateService.getLocale();
await this.i18nService.init(locale != null ? locale : app.getLocale());
await this.i18nService.init();
this.messagingMain.init();
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
// eslint-disable-next-line @typescript-eslint/no-floating-promises

View File

@@ -1,14 +1,22 @@
import * as fs from "fs";
import * as path from "path";
import { ipcMain } from "electron";
import { app, ipcMain } from "electron";
import { I18nService as BaseI18nService } from "@bitwarden/common/platform/services/i18n.service";
import { GlobalStateProvider } from "@bitwarden/common/platform/state";
export class I18nMainService extends BaseI18nService {
constructor(systemLanguage: string, localesDirectory: string) {
super(systemLanguage, localesDirectory, (formattedLocale: string) =>
this.readLanguageFile(formattedLocale),
constructor(
systemLanguage: string,
localesDirectory: string,
globalStateProvider: GlobalStateProvider,
) {
super(
systemLanguage,
localesDirectory,
(formattedLocale: string) => this.readLanguageFile(formattedLocale),
globalStateProvider,
);
ipcMain.handle("getLanguageFile", async (event, formattedLocale: string) =>
@@ -76,6 +84,12 @@ export class I18nMainService extends BaseI18nService {
];
}
override async init(): Promise<void> {
// Set system language to electron language
this.systemLanguage = app.getLocale();
await super.init();
}
private readLanguageFile(formattedLocale: string): Promise<any> {
// Check that the provided locale only contains letters and dashes and underscores to avoid possible path traversal
if (!/^[a-zA-Z_-]+$/.test(formattedLocale)) {

View File

@@ -1,10 +1,20 @@
import { I18nService as BaseI18nService } from "@bitwarden/common/platform/services/i18n.service";
import { GlobalStateProvider } from "@bitwarden/common/platform/state";
export class I18nRendererService extends BaseI18nService {
constructor(systemLanguage: string, localesDirectory: string) {
super(systemLanguage, localesDirectory, (formattedLocale: string) => {
return ipc.platform.getLanguageFile(formattedLocale);
});
constructor(
systemLanguage: string,
localesDirectory: string,
globalStateProvider: GlobalStateProvider,
) {
super(
systemLanguage,
localesDirectory,
(formattedLocale: string) => {
return ipc.platform.getLanguageFile(formattedLocale);
},
globalStateProvider,
);
// Please leave 'en' where it is, as it's our fallback language in case no translation can be found
this.supportedTranslationLocales = [