summaryrefslogtreecommitdiffhomepage
path: root/gui/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'gui/src/main')
-rw-r--r--gui/src/main/index.ts26
-rw-r--r--gui/src/main/load-translations.ts72
2 files changed, 86 insertions, 12 deletions
diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts
index ec67280e12..872c043f89 100644
--- a/gui/src/main/index.ts
+++ b/gui/src/main/index.ts
@@ -34,7 +34,7 @@ import {
RelaySettingsUpdate,
TunnelState,
} from '../shared/daemon-rpc-types';
-import { loadTranslations, messages } from '../shared/gettext';
+import { messages, relayLocations } from '../shared/gettext';
import { SYSTEM_PREFERRED_LOCALE_KEY } from '../shared/gui-settings-state';
import { IpcMainEventChannel } from '../shared/ipc-event-channel';
import log, { ConsoleOutput, Logger } from '../shared/logging';
@@ -65,11 +65,13 @@ import {
IpcInput,
OLD_LOG_FILES,
} from './logging';
+import { loadTranslations } from './load-translations';
import NotificationController from './notification-controller';
import { resolveBin } from './proc';
import ReconnectionBackoff from './reconnection-backoff';
import TrayIconController, { TrayIconType } from './tray-icon-controller';
import WindowController from './window-controller';
+import { ITranslations } from '../shared/ipc-schema';
// Only import when running app on Linux.
const linuxSplitTunneling = process.platform === 'linux' && require('./linux-split-tunneling');
@@ -204,6 +206,7 @@ class ApplicationMain {
private autoConnectFallbackScheduler = new Scheduler();
private rendererLog?: Logger;
+ private translations: ITranslations = { locale: this.locale };
public run() {
// Remove window animations to combat window flickering when opening window. Can be removed when
@@ -373,7 +376,7 @@ class ApplicationMain {
this.blockRequests();
- this.updateCurrentLocale();
+ this.translations = this.updateCurrentLocale();
this.daemonRpc.addConnectionObserver(
new ConnectionObserver(this.onDaemonConnected, this.onDaemonDisconnected),
@@ -1007,6 +1010,7 @@ class ApplicationMain {
upgradeVersion: this.upgradeVersion,
guiSettings: this.guiSettings.state,
wireguardPublicKey: this.wireguardPublicKey,
+ translations: this.translations,
}));
IpcMainEventChannel.settings.handleSetAllowLan((allowLan: boolean) =>
@@ -1074,7 +1078,7 @@ class ApplicationMain {
IpcMainEventChannel.guiSettings.handleSetPreferredLocale((locale: string) => {
this.guiSettings.preferredLocale = locale;
- this.didChangeLocale();
+ return Promise.resolve(this.updateCurrentLocale());
});
IpcMainEventChannel.account.handleCreate(() => this.createNewAccount());
@@ -1368,15 +1372,13 @@ class ApplicationMain {
log.info(`Detected locale: ${this.locale}`);
- loadTranslations(this.locale, messages);
- }
-
- private didChangeLocale() {
- this.updateCurrentLocale();
-
- if (this.windowController) {
- IpcMainEventChannel.locale.notify(this.windowController.webContents, this.locale);
- }
+ const messagesTranslations = loadTranslations(this.locale, messages);
+ const relayLocationsTranslations = loadTranslations(this.locale, relayLocations);
+ return {
+ locale: this.locale,
+ messages: messagesTranslations,
+ relayLocations: relayLocationsTranslations,
+ };
}
// Since the app frontend never performs any network requests, all requests originating from the
diff --git a/gui/src/main/load-translations.ts b/gui/src/main/load-translations.ts
new file mode 100644
index 0000000000..63d76f0ac6
--- /dev/null
+++ b/gui/src/main/load-translations.ts
@@ -0,0 +1,72 @@
+import fs from 'fs';
+import { GetTextTranslations, po } from 'gettext-parser';
+import Gettext from 'node-gettext';
+import path from 'path';
+import log from '../shared/logging';
+
+const SOURCE_LANGUAGE = 'en';
+const LOCALES_DIR = path.resolve(__dirname, '../../locales');
+
+export function loadTranslations(
+ currentLocale: string,
+ catalogue: Gettext,
+): GetTextTranslations | undefined {
+ // First look for exact match of the current locale
+ const preferredLocales = [];
+
+ if (currentLocale !== SOURCE_LANGUAGE) {
+ preferredLocales.push(currentLocale);
+ }
+
+ // In case of region bound locale like en-US, fallback to en.
+ const language = Gettext.getLanguageCode(currentLocale);
+ if (currentLocale !== language) {
+ preferredLocales.push(language);
+ }
+
+ const domain = catalogue.domain;
+ for (const locale of preferredLocales) {
+ const parsedTranslations = parseTranslation(locale, domain, catalogue);
+ if (parsedTranslations) {
+ log.info(`Loaded translations ${locale}/${domain}`);
+ catalogue.setLocale(locale);
+ return parsedTranslations;
+ }
+ }
+
+ // Reset the locale to source language if we couldn't load the catalogue for the requested locale
+ // Add empty translations to suppress some of the warnings produces by node-gettext
+ catalogue.addTranslations(SOURCE_LANGUAGE, domain, {});
+ catalogue.setLocale(SOURCE_LANGUAGE);
+ return;
+}
+
+function parseTranslation(
+ locale: string,
+ domain: string,
+ catalogue: Gettext,
+): GetTextTranslations | undefined {
+ const filename = path.join(LOCALES_DIR, locale, `${domain}.po`);
+ let contents: string;
+
+ try {
+ contents = fs.readFileSync(filename, { encoding: 'utf8' });
+ } catch (error) {
+ if (error.code !== 'ENOENT') {
+ log.error(`Cannot read the gettext file "${filename}": ${error.message}`);
+ }
+ return undefined;
+ }
+
+ let translations: GetTextTranslations;
+ try {
+ translations = po.parse(contents);
+ } catch (error) {
+ log.error(`Cannot parse the gettext file "${filename}": ${error.message}`);
+ return undefined;
+ }
+
+ catalogue.addTranslations(locale, domain, translations);
+
+ return translations;
+}