diff --git a/package-lock.json b/package-lock.json
index def3d554565..f4ed2388a76 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4223,7 +4223,8 @@
"jsbn": {
"version": "0.1.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "optional": true
},
"json-schema": {
"version": "0.2.3",
diff --git a/src/app/accounts/settings.component.html b/src/app/accounts/settings.component.html
index 3399272b19d..b8f20a4e967 100644
--- a/src/app/accounts/settings.component.html
+++ b/src/app/accounts/settings.component.html
@@ -42,6 +42,14 @@
{{'disableFaviconDesc' | i18n}}
+
+
+
+ {{'languageDesc' | i18n}}
+
diff --git a/src/app/accounts/settings.component.ts b/src/app/accounts/settings.component.ts
index aaf2763582e..a694f9710ea 100644
--- a/src/app/accounts/settings.component.ts
+++ b/src/app/accounts/settings.component.ts
@@ -15,6 +15,8 @@ import { StorageService } from 'jslib/abstractions/storage.service';
import { ConstantsService } from 'jslib/services/constants.service';
+import { SupportedTranslationLocales } from '../../services/i18n.service';
+
@Component({
selector: 'app-settings',
templateUrl: 'settings.component.html',
@@ -24,6 +26,8 @@ export class SettingsComponent implements OnInit {
lockOption: number = null;
disableGa: boolean = false;
disableFavicons: boolean = false;
+ locales: any[];
+ locale: string;
constructor(private analytics: Angulartics2, private toasterService: ToasterService,
private i18nService: I18nService, private platformUtilsService: PlatformUtilsService,
@@ -43,11 +47,17 @@ export class SettingsComponent implements OnInit {
{ name: i18nService.t('onRestart'), value: -1 },
{ name: i18nService.t('never'), value: null },
];
+
+ this.locales = [ { locale: null, language: 'Default' } ];
+ Object.keys(SupportedTranslationLocales).forEach((localId) => {
+ this.locales.push({locale: localId, language: i18nService.t(localId)});
+ });
}
async ngOnInit() {
this.lockOption = await this.storageService.get(ConstantsService.lockOptionKey);
this.disableFavicons = await this.storageService.get(ConstantsService.disableFaviconKey);
+ this.locale = await this.storageService.get('locale');
const disableGa = await this.storageService.get(ConstantsService.disableGaKey);
const disableGaByDefault = this.platformUtilsService.isFirefox() || this.platformUtilsService.isMacAppStore();
@@ -79,4 +89,8 @@ export class SettingsComponent implements OnInit {
const status = enabled ? 'Enabled' : 'Disabled';
this.analytics.eventTrack.next({ action: `${status} ${name}` });
}
+
+ async saveLocale() {
+ await this.storageService.save('locale', this.locale);
+ }
}
diff --git a/src/app/services/services.module.ts b/src/app/services/services.module.ts
index 1ac8d2052b4..dc0305b5fbb 100644
--- a/src/app/services/services.module.ts
+++ b/src/app/services/services.module.ts
@@ -110,7 +110,7 @@ environmentService.setUrlsFromStorage().then(() => {
export function initFactory(): Function {
return async () => {
- await i18nService.init();
+ await i18nService.init(await storageService.get('locale'));
await authService.init();
const htmlEl = window.document.documentElement;
htmlEl.classList.add('os_' + platformUtilsService.getDeviceString());
diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json
index 13c10312099..655d431af8e 100644
--- a/src/locales/en/messages.json
+++ b/src/locales/en/messages.json
@@ -770,6 +770,12 @@
"disableFaviconDesc": {
"message": "Website Icons provide a recognizable image next to each login item in your vault."
},
+ "language": {
+ "message": "Language"
+ },
+ "languageDesc": {
+ "message": "Change language. Require restart."
+ },
"copy": {
"message": "Copy",
"description": "Copy to clipboard"
diff --git a/src/main.ts b/src/main.ts
index 9da77e2bccf..229f2009730 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -62,15 +62,17 @@ export class Main {
}
bootstrap() {
- this.windowMain.init().then(async () => {
- await this.i18nService.init(app.getLocale());
- this.messagingMain.init();
- this.menuMain.init();
- this.powerMonitorMain.init();
- await this.updaterMain.init();
- }, (e: any) => {
- // tslint:disable-next-line
- console.error(e);
+ this.storageService.get('locale').then(async (locale) => {
+ this.windowMain.init().then(async () => {
+ await this.i18nService.init(locale !== null ? locale : app.getLocale());
+ this.messagingMain.init();
+ this.menuMain.init();
+ this.powerMonitorMain.init();
+ await this.updaterMain.init();
+ }, (e: any) => {
+ // tslint:disable-next-line
+ console.error(e);
+ });
});
}
}
diff --git a/src/services/i18n.service.ts b/src/services/i18n.service.ts
index 589e50979d6..690bba0c487 100644
--- a/src/services/i18n.service.ts
+++ b/src/services/i18n.service.ts
@@ -4,7 +4,7 @@ import * as path from 'path';
import { I18nService as I18nServiceAbstraction } from 'jslib/abstractions/i18n.service';
// First locale is the default (English)
-const SupportedTranslationLocales = [
+export const SupportedTranslationLocales = [
'en', 'cs', 'da', 'de', 'es', 'et', 'fi', 'fr', 'hr', 'hu', 'id', 'it', 'ja',
'nb', 'nl', 'pl', 'pt-BR', 'pt-PT', 'ro', 'ru', 'sk', 'sv', 'tr', 'uk', 'vi',
'zh-CN', 'zh-TW',