From 60329e086a8b4e04a220a871548ed3ad037201aa Mon Sep 17 00:00:00 2001 From: antelle Date: Sat, 8 May 2021 10:37:24 +0200 Subject: [PATCH] translated application menu on macOS --- app/scripts/comp/settings/settings-manager.js | 15 ++++ desktop/main.js | 74 ++++++++++++++----- desktop/scripts/ipc-handlers/set-locale.js | 4 + desktop/scripts/ipc.js | 1 + desktop/scripts/locale.js | 29 ++++++++ release-notes.md | 1 + 6 files changed, 105 insertions(+), 19 deletions(-) create mode 100644 desktop/scripts/ipc-handlers/set-locale.js create mode 100644 desktop/scripts/locale.js diff --git a/app/scripts/comp/settings/settings-manager.js b/app/scripts/comp/settings/settings-manager.js index 3a6c347a..ff2cbcce 100644 --- a/app/scripts/comp/settings/settings-manager.js +++ b/app/scripts/comp/settings/settings-manager.js @@ -4,6 +4,7 @@ import { Locale } from 'util/locale'; import { ThemeWatcher } from 'comp/browser/theme-watcher'; import { AppSettingsModel } from 'models/app-settings-model'; import { Logger } from 'util/logger'; +import { Launcher } from 'comp/launcher'; const logger = new Logger('settings-manager'); @@ -164,6 +165,20 @@ const SettingsManager = { Object.assign(Locale, this.neutralLocale, localeValues); this.activeLocale = loc; Events.emit('set-locale', loc); + + if (Launcher) { + const { ipcRenderer } = Launcher.electron(); + const localeValuesForDesktopApp = {}; + for (const [key, value] of Object.entries(Locale)) { + if (key.startsWith('sysMenu')) { + localeValuesForDesktopApp[key] = value; + } + } + ipcRenderer.invoke('setLocale', { + locale: loc, + ...localeValuesForDesktopApp + }); + } }, getBrowserLocale() { diff --git a/desktop/main.js b/desktop/main.js index 14ed3b15..96da77ce 100644 --- a/desktop/main.js +++ b/desktop/main.js @@ -9,6 +9,8 @@ const electron = require('electron'); const path = require('path'); const fs = require('fs'); const url = require('url'); + +const { locale, setLocale, getLocaleValues } = require('./scripts/locale'); const { Logger } = require('./scripts/logger'); const { isDev } = require('./scripts/util/app-info'); @@ -120,6 +122,10 @@ main.on('ready', () => { setGlobalShortcuts(appSettings); subscribePowerEvents(); hookRequestHeaders(); + + loadLocale().then(() => { + setMenu(); + }); }) .catch((e) => { electron.dialog.showErrorBox('KeeWeb', 'Error loading app: ' + e); @@ -297,9 +303,6 @@ function createMainWindow() { mainWindow = new electron.BrowserWindow(windowOptions); logProgress('creating main window'); - setMenu(); - logProgress('setting menu'); - mainWindow.loadURL(htmlPath); mainWindow.once('ready-to-show', () => { logProgress('main window ready'); @@ -491,34 +494,50 @@ function setMenu() { { label: name, submenu: [ - { role: 'about' }, + { role: 'about', label: locale.sysMenuAboutKeeWeb?.replace('{}', 'KeeWeb') }, { type: 'separator' }, - { role: 'services', submenu: [] }, + { role: 'services', submenu: [], label: locale.sysMenuServices }, { type: 'separator' }, - { accelerator: 'Command+H', role: 'hide' }, - { accelerator: 'Command+Shift+H', role: 'hideothers' }, - { role: 'unhide' }, + { + accelerator: 'Command+H', + role: 'hide', + label: locale.sysMenuHide?.replace('{}', 'KeeWeb') + }, + { + accelerator: 'Command+Shift+H', + role: 'hideothers', + label: locale.sysMenuHideOthers + }, + { role: 'unhide', label: locale.sysMenuUnhide }, { type: 'separator' }, - { role: 'quit', accelerator: 'Command+Q' } + { + role: 'quit', + accelerator: 'Command+Q', + label: locale.sysMenuQuit?.replace('{}', 'KeeWeb') + } ] }, { - label: 'Edit', + label: locale.sysMenuEdit || 'Edit', submenu: [ - { accelerator: 'CmdOrCtrl+Z', role: 'undo' }, - { accelerator: 'Shift+CmdOrCtrl+Z', role: 'redo' }, + { accelerator: 'CmdOrCtrl+Z', role: 'undo', label: locale.sysMenuUndo }, + { accelerator: 'Shift+CmdOrCtrl+Z', role: 'redo', label: locale.sysMenuRedo }, { type: 'separator' }, - { accelerator: 'CmdOrCtrl+X', role: 'cut' }, - { accelerator: 'CmdOrCtrl+C', role: 'copy' }, - { accelerator: 'CmdOrCtrl+V', role: 'paste' }, - { accelerator: 'CmdOrCtrl+A', role: 'selectall' } + { accelerator: 'CmdOrCtrl+X', role: 'cut', label: locale.sysMenuCut }, + { accelerator: 'CmdOrCtrl+C', role: 'copy', label: locale.sysMenuCopy }, + { accelerator: 'CmdOrCtrl+V', role: 'paste', label: locale.sysMenuPaste }, + { + accelerator: 'CmdOrCtrl+A', + role: 'selectall', + label: locale.sysMenuSelectAll + } ] }, { - label: 'Window', + label: locale.sysMenuWindow || 'Window', submenu: [ - { accelerator: 'CmdOrCtrl+M', role: 'minimize' }, - { accelerator: 'Command+W', role: 'close' } + { accelerator: 'CmdOrCtrl+M', role: 'minimize', label: locale.sysMenuMinimize }, + { accelerator: 'Command+W', role: 'close', label: locale.sysMenuClose } ] } ]; @@ -887,6 +906,23 @@ function saveConfig(name, data, key) { }); } +function loadLocale() { + return loadConfig('locale').then((localeValues) => { + if (localeValues) { + try { + localeValues = JSON.parse(localeValues); + if (appSettings?.locale === localeValues?.locale) { + setLocale(localeValues); + } + } catch {} + } + locale.on('changed', () => { + setMenu(); + saveConfig('locale', JSON.stringify(getLocaleValues())); + }); + }); +} + // TODO: delete in 2021 function migrateOldConfigs(key) { const knownConfigs = [ diff --git a/desktop/scripts/ipc-handlers/set-locale.js b/desktop/scripts/ipc-handlers/set-locale.js new file mode 100644 index 00000000..0f83d08b --- /dev/null +++ b/desktop/scripts/ipc-handlers/set-locale.js @@ -0,0 +1,4 @@ +const { ipcMain } = require('electron'); +const { setLocale } = require('../locale'); + +ipcMain.handle('setLocale', (e, values) => setLocale(values)); diff --git a/desktop/scripts/ipc.js b/desktop/scripts/ipc.js index 01ee2354..1585121a 100644 --- a/desktop/scripts/ipc.js +++ b/desktop/scripts/ipc.js @@ -3,4 +3,5 @@ module.exports.setupIpcHandlers = () => { require('./ipc-handlers/hardware-crypto'); require('./ipc-handlers/native-module-host-proxy'); require('./ipc-handlers/spawn-process'); + require('./ipc-handlers/set-locale'); }; diff --git a/desktop/scripts/locale.js b/desktop/scripts/locale.js new file mode 100644 index 00000000..4368c23f --- /dev/null +++ b/desktop/scripts/locale.js @@ -0,0 +1,29 @@ +const { EventEmitter } = require('events'); + +class Locale extends EventEmitter {} + +const locale = new Locale(); + +let localeValues; + +function setLocale(values) { + localeValues = values; + + let changed = false; + for (const [key, value] of Object.entries(values)) { + if (locale[key] !== value) { + changed = true; + locale[key] = value; + } + } + + if (changed) { + locale.emit('changed'); + } +} + +function getLocaleValues() { + return localeValues; +} + +module.exports = { locale, setLocale, getLocaleValues }; diff --git a/release-notes.md b/release-notes.md index 3d540c5c..d8674920 100644 --- a/release-notes.md +++ b/release-notes.md @@ -13,6 +13,7 @@ Release notes `+` displaying the reason why unlock is requested `+` filters on the auto-type entry selection screen `+` adding multiple websites to one entry +`+` translated application menu on macOS `-` fixed a crash after disabling USB devices on Linux `+` tightened content security policy `-` KeeWebHttp deprecated