mirror of
https://github.com/finos/SymphonyElectron.git
synced 2024-12-28 09:51:06 -06:00
SDA-3844 (Use local shortcuts to fix issues on Windows) (#1488)
* SDA-3844 - Use local shortcuts to fix issues on Windows * SDA-3844 - Remove duplicate menu item * SDA-3844 - Add menu items for corp switch * SDA-3844 - Workaround for export logs local shortcut * SDA-3844 - Fix translations
This commit is contained in:
parent
421d0fa2f4
commit
aba73978b2
@ -24,7 +24,11 @@ import {
|
||||
unregisterConsoleMessages,
|
||||
updateAlwaysOnTop,
|
||||
} from './window-actions';
|
||||
import { ICustomBrowserWindow, windowHandler } from './window-handler';
|
||||
import {
|
||||
ClientSwitchType,
|
||||
ICustomBrowserWindow,
|
||||
windowHandler,
|
||||
} from './window-handler';
|
||||
import {
|
||||
reloadWindow,
|
||||
resetZoomLevel,
|
||||
@ -92,6 +96,7 @@ let {
|
||||
isAutoUpdateEnabled,
|
||||
} = config.getConfigFields(menuItemConfigFields) as IConfig;
|
||||
let initialAnalyticsSent = false;
|
||||
const CORP_URL = 'https://corporate.symphony.com';
|
||||
|
||||
const menuItemsArray = Object.keys(menuSections)
|
||||
.map((key) => menuSections[key])
|
||||
@ -582,6 +587,10 @@ export class AppMenu {
|
||||
|
||||
const { devToolsEnabled: isDevToolsEnabledCC } = this
|
||||
.cloudConfig as IConfig;
|
||||
const isCorp =
|
||||
(windowHandler.url &&
|
||||
windowHandler.url.startsWith('https://corporate.symphony.com')) ||
|
||||
false;
|
||||
|
||||
return {
|
||||
label: i18n.t('Help')(),
|
||||
@ -682,6 +691,30 @@ export class AppMenu {
|
||||
windowHandler.createAboutAppWindow(windowName);
|
||||
},
|
||||
},
|
||||
{
|
||||
click: (_item) =>
|
||||
windowHandler.switchClient(ClientSwitchType.CLIENT_1_5),
|
||||
visible: isCorp,
|
||||
type: 'checkbox',
|
||||
checked: windowHandler.url?.startsWith(CORP_URL + '/client/'),
|
||||
label: i18n.t('Switch to client 1.5')(),
|
||||
},
|
||||
{
|
||||
click: (_item) =>
|
||||
windowHandler.switchClient(ClientSwitchType.CLIENT_2_0),
|
||||
visible: isCorp,
|
||||
type: 'checkbox',
|
||||
checked: windowHandler.url?.startsWith(CORP_URL + '/client-bff'),
|
||||
label: i18n.t('Switch to client 2.0')(),
|
||||
},
|
||||
{
|
||||
click: (_item) =>
|
||||
windowHandler.switchClient(ClientSwitchType.CLIENT_2_0_DAILY),
|
||||
visible: isCorp,
|
||||
type: 'checkbox',
|
||||
checked: windowHandler.url?.startsWith(CORP_URL + '/bff-daily/daily'),
|
||||
label: i18n.t('Switch to client 2.0 daily')(),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
98
src/app/local-menu-shortcuts.ts
Normal file
98
src/app/local-menu-shortcuts.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import { Menu, MenuItem, MenuItemConstructorOptions } from 'electron';
|
||||
import { isMac } from '../common/env';
|
||||
import { windowHandler } from './window-handler';
|
||||
import { resetZoomLevel, zoomIn, zoomOut } from './window-utils';
|
||||
|
||||
export default class LocalMenuShortcuts {
|
||||
private menu: Menu;
|
||||
|
||||
constructor() {
|
||||
this.menu = new Menu();
|
||||
}
|
||||
|
||||
public buildShortcutMenu = () => {
|
||||
// Devtools shortcut
|
||||
this.menu.append(
|
||||
new MenuItem(
|
||||
this.getMenuItemOptions({
|
||||
accelerator: isMac ? 'Alt+Command+I' : 'Ctrl+Shift+I',
|
||||
click: () => windowHandler.onRegisterDevtools(),
|
||||
}),
|
||||
),
|
||||
);
|
||||
// Reload shortcut
|
||||
this.menu.append(
|
||||
new MenuItem(
|
||||
this.getMenuItemOptions({
|
||||
accelerator: 'CmdOrCtrl+R',
|
||||
click: () => windowHandler.onReload(),
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
this.menu.append(
|
||||
new MenuItem(
|
||||
this.getMenuItemOptions({
|
||||
accelerator: 'CmdOrCtrl+=',
|
||||
click: () => zoomIn(),
|
||||
}),
|
||||
),
|
||||
);
|
||||
this.menu.append(
|
||||
new MenuItem(
|
||||
this.getMenuItemOptions({
|
||||
accelerator: 'CmdOrCtrl+-',
|
||||
click: () => zoomOut(),
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
if (isMac) {
|
||||
this.menu.append(
|
||||
new MenuItem(
|
||||
this.getMenuItemOptions({
|
||||
accelerator: 'CmdOrCtrl+Plus',
|
||||
click: () => zoomIn(),
|
||||
}),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
this.menu.append(
|
||||
new MenuItem(
|
||||
this.getMenuItemOptions({
|
||||
accelerator: 'Ctrl+numadd',
|
||||
click: () => zoomIn(),
|
||||
}),
|
||||
),
|
||||
);
|
||||
this.menu.append(
|
||||
new MenuItem(
|
||||
this.getMenuItemOptions({
|
||||
accelerator: 'Ctrl+numsub',
|
||||
click: () => zoomOut(),
|
||||
}),
|
||||
),
|
||||
);
|
||||
this.menu.append(
|
||||
new MenuItem(
|
||||
this.getMenuItemOptions({
|
||||
accelerator: 'Ctrl+num0',
|
||||
click: () => resetZoomLevel(),
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Menu.setApplicationMenu(this.menu);
|
||||
};
|
||||
|
||||
private getMenuItemOptions = (opts): MenuItemConstructorOptions => {
|
||||
return {
|
||||
...{
|
||||
visible: false,
|
||||
acceleratorWorksWhenHidden: true,
|
||||
},
|
||||
...opts,
|
||||
};
|
||||
};
|
||||
}
|
@ -8,7 +8,6 @@ import {
|
||||
DesktopCapturerSource,
|
||||
dialog,
|
||||
Event,
|
||||
globalShortcut,
|
||||
ipcMain,
|
||||
RenderProcessGoneDetails,
|
||||
screen,
|
||||
@ -27,6 +26,7 @@ import {
|
||||
calculatePercentage,
|
||||
getCommandLineArgs,
|
||||
getGuid,
|
||||
throttle,
|
||||
} from '../common/utils';
|
||||
import { notification } from '../renderer/notification';
|
||||
import { cleanAppCacheOnCrash } from './app-cache-handler';
|
||||
@ -40,6 +40,7 @@ import {
|
||||
IGlobalConfig,
|
||||
} from './config-handler';
|
||||
import crashHandler from './crash-handler';
|
||||
import LocalMenuShortcuts from './local-menu-shortcuts';
|
||||
import { mainEvents } from './main-event-handler';
|
||||
import { exportLogs } from './reports-handler';
|
||||
import { SpellChecker } from './spell-check-handler';
|
||||
@ -63,11 +64,8 @@ import {
|
||||
monitorNetworkInterception,
|
||||
preventWindowNavigation,
|
||||
reloadWindow,
|
||||
resetZoomLevel,
|
||||
viewExists,
|
||||
windowExists,
|
||||
zoomIn,
|
||||
zoomOut,
|
||||
} from './window-utils';
|
||||
|
||||
const windowSize: string | null = getCommandLineArgs(
|
||||
@ -76,13 +74,14 @@ const windowSize: string | null = getCommandLineArgs(
|
||||
false,
|
||||
);
|
||||
|
||||
enum ClientSwitchType {
|
||||
export enum ClientSwitchType {
|
||||
CLIENT_1_5 = 'CLIENT_1_5',
|
||||
CLIENT_2_0 = 'CLIENT_2_0',
|
||||
CLIENT_2_0_DAILY = 'CLIENT_2_0_DAILY',
|
||||
}
|
||||
|
||||
const MAIN_WEB_CONTENTS_EVENTS = ['enter-full-screen', 'leave-full-screen'];
|
||||
const EXPORT_LOGS_THROTTLE = 1000; // 1sec
|
||||
|
||||
export interface ICustomBrowserWindowConstructorOpts
|
||||
extends Electron.BrowserWindowConstructorOptions {
|
||||
@ -301,6 +300,8 @@ export class WindowHandler {
|
||||
...this.windowOpts,
|
||||
...getBounds(this.config.mainWinPos, DEFAULT_WIDTH, DEFAULT_HEIGHT),
|
||||
}) as ICustomBrowserWindow;
|
||||
const localMenuShortcuts = new LocalMenuShortcuts();
|
||||
localMenuShortcuts.buildShortcutMenu();
|
||||
|
||||
logger.info('window-handler: windowSize: ' + JSON.stringify(windowSize));
|
||||
if (windowSize) {
|
||||
@ -389,6 +390,17 @@ export class WindowHandler {
|
||||
this.mainWindow.loadURL(this.url, { userAgent });
|
||||
this.mainWebContents = this.mainWindow.webContents;
|
||||
}
|
||||
|
||||
// SDA-3844 - workaround as local shortcuts not working
|
||||
const throttledExportLogs = throttle(() => {
|
||||
exportLogs();
|
||||
}, EXPORT_LOGS_THROTTLE);
|
||||
this.mainWebContents.on('before-input-event', (event, input) => {
|
||||
if (input.control && input.shift && input.key.toLowerCase() === 'd') {
|
||||
event.preventDefault();
|
||||
throttledExportLogs();
|
||||
}
|
||||
});
|
||||
if (isMaximized || isMaximizedFlag) {
|
||||
this.mainWindow.maximize();
|
||||
logger.info(
|
||||
@ -556,8 +568,6 @@ export class WindowHandler {
|
||||
);
|
||||
}
|
||||
}
|
||||
// Register dev tools on initial launch
|
||||
this.registerGlobalShortcuts();
|
||||
});
|
||||
|
||||
this.mainWebContents.on(
|
||||
@ -666,14 +676,6 @@ export class WindowHandler {
|
||||
handleCertificateProxyVerification,
|
||||
);
|
||||
|
||||
app.on('browser-window-focus', () => {
|
||||
this.registerGlobalShortcuts();
|
||||
});
|
||||
|
||||
app.on('browser-window-blur', () => {
|
||||
this.unregisterGlobalShortcuts();
|
||||
});
|
||||
|
||||
// Validate window navigation
|
||||
preventWindowNavigation(this.mainWindow, false);
|
||||
|
||||
@ -2026,6 +2028,99 @@ export class WindowHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies and toggle devtool based on global config settings
|
||||
* else displays a dialog
|
||||
*/
|
||||
public onRegisterDevtools(): void {
|
||||
const focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (!focusedWindow || !windowExists(focusedWindow)) {
|
||||
return;
|
||||
}
|
||||
const { devToolsEnabled } = config.getConfigFields(['devToolsEnabled']);
|
||||
if (devToolsEnabled) {
|
||||
if (
|
||||
this.mainWindow &&
|
||||
windowExists(this.mainWindow) &&
|
||||
focusedWindow === this.mainWindow
|
||||
) {
|
||||
if (this.mainView && viewExists(this.mainView)) {
|
||||
this.mainWebContents?.toggleDevTools();
|
||||
return;
|
||||
}
|
||||
}
|
||||
focusedWindow.webContents.toggleDevTools();
|
||||
return;
|
||||
}
|
||||
focusedWindow.webContents.closeDevTools();
|
||||
logger.info(
|
||||
`window-handler: dev tools disabled by admin, not opening it for the user!`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch between clients 1.5, 2.0 and 2.0 daily
|
||||
* @param clientSwitch client switch you want to switch to.
|
||||
*/
|
||||
public async switchClient(clientSwitch: ClientSwitchType): Promise<void> {
|
||||
logger.info(`window handler: switch to client ${clientSwitch}`);
|
||||
|
||||
if (!this.mainWebContents || this.mainWebContents.isDestroyed()) {
|
||||
logger.info(
|
||||
`window-handler: switch client - main window web contents destroyed already! exiting`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (!this.url) {
|
||||
this.url = this.globalConfig.url;
|
||||
}
|
||||
const parsedUrl = parse(this.url);
|
||||
const csrfToken = await this.mainWebContents?.executeJavaScript(
|
||||
`localStorage.getItem('x-km-csrf-token')`,
|
||||
);
|
||||
switch (clientSwitch) {
|
||||
case ClientSwitchType.CLIENT_1_5:
|
||||
this.url = this.startUrl + `?x-km-csrf-token=${csrfToken}`;
|
||||
break;
|
||||
case ClientSwitchType.CLIENT_2_0:
|
||||
this.url = `https://${parsedUrl.hostname}/client-bff/index.html?x-km-csrf-token=${csrfToken}`;
|
||||
break;
|
||||
case ClientSwitchType.CLIENT_2_0_DAILY:
|
||||
this.url = `https://${parsedUrl.hostname}/bff-daily/daily/index.html?x-km-csrf-token=${csrfToken}`;
|
||||
break;
|
||||
default:
|
||||
this.url = this.globalConfig.url + `?x-km-csrf-token=${csrfToken}`;
|
||||
}
|
||||
await this.execCmd(this.screenShareIndicatorFrameUtil, []);
|
||||
const userAgent = this.getUserAgent(this.mainWebContents);
|
||||
await this.mainWebContents.loadURL(this.url, { userAgent });
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
`window-handler: failed to switch client because of error ${e}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the window based on the window type
|
||||
*/
|
||||
public onReload(): void {
|
||||
const focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (!focusedWindow || !windowExists(focusedWindow)) {
|
||||
return;
|
||||
}
|
||||
reloadWindow(focusedWindow as ICustomBrowserWindow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports all logs
|
||||
*/
|
||||
public onExportLogs(): void {
|
||||
logger.info('window-handler: Exporting logs');
|
||||
exportLogs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for app load timeouts and reloads if required
|
||||
*/
|
||||
@ -2069,164 +2164,6 @@ export class WindowHandler {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers keyboard shortcuts or devtools
|
||||
*/
|
||||
private registerGlobalShortcuts(): void {
|
||||
logger.info('window-handler: register global shortcuts!');
|
||||
globalShortcut.register(isMac ? 'Cmd+Alt+I' : 'Ctrl+Shift+I', () =>
|
||||
this.onRegisterDevtools(),
|
||||
);
|
||||
globalShortcut.register('CmdOrCtrl+R', this.onReload);
|
||||
|
||||
// Hack to switch between Client 1.5, Mana-stable and Mana-daily
|
||||
if (this.url && this.url.startsWith('https://corporate.symphony.com')) {
|
||||
globalShortcut.register(isMac ? 'Cmd+Alt+1' : 'Ctrl+Shift+1', () =>
|
||||
this.switchClient(ClientSwitchType.CLIENT_1_5),
|
||||
);
|
||||
globalShortcut.register(isMac ? 'Cmd+Alt+2' : 'Ctrl+Shift+2', () =>
|
||||
this.switchClient(ClientSwitchType.CLIENT_2_0),
|
||||
);
|
||||
globalShortcut.register(isMac ? 'Cmd+Alt+3' : 'Ctrl+Shift+3', () =>
|
||||
this.switchClient(ClientSwitchType.CLIENT_2_0_DAILY),
|
||||
);
|
||||
}
|
||||
globalShortcut.register('CmdOrCtrl+=', zoomIn);
|
||||
globalShortcut.register('CmdOrCtrl+-', zoomOut);
|
||||
if (isMac) {
|
||||
globalShortcut.register('CmdOrCtrl+Plus', zoomIn);
|
||||
} else if (isWindowsOS || isLinux) {
|
||||
globalShortcut.register('Ctrl+=', zoomIn);
|
||||
globalShortcut.register('Ctrl+numadd', zoomIn);
|
||||
globalShortcut.register('Ctrl+numsub', zoomOut);
|
||||
globalShortcut.register('Ctrl+num0', resetZoomLevel);
|
||||
}
|
||||
|
||||
// Register export log shortcut
|
||||
globalShortcut.register('Ctrl+Shift+D', () => this.onExportLogs());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers keyboard shortcuts or devtools
|
||||
*/
|
||||
private unregisterGlobalShortcuts(): void {
|
||||
logger.info('window-handler: unregister global shortcuts!');
|
||||
|
||||
globalShortcut.unregister(isMac ? 'Cmd+Alt+I' : 'Ctrl+Shift+I');
|
||||
globalShortcut.unregister('CmdOrCtrl+R');
|
||||
globalShortcut.unregister('CmdOrCtrl+=');
|
||||
globalShortcut.unregister('CmdOrCtrl+-');
|
||||
if (isMac) {
|
||||
globalShortcut.unregister('CmdOrCtrl+Plus');
|
||||
} else if (isWindowsOS || isLinux) {
|
||||
globalShortcut.unregister('Ctrl+numadd');
|
||||
globalShortcut.unregister('Ctrl+numsub');
|
||||
globalShortcut.unregister('Ctrl+num0');
|
||||
}
|
||||
// Unregister shortcuts related to client switch
|
||||
if (this.url && this.url.startsWith('https://corporate.symphony.com')) {
|
||||
globalShortcut.unregister(isMac ? 'Cmd+Alt+1' : 'Ctrl+Shift+1');
|
||||
globalShortcut.unregister(isMac ? 'Cmd+Alt+2' : 'Ctrl+Shift+2');
|
||||
globalShortcut.unregister(isMac ? 'Cmd+Alt+3' : 'Ctrl+Shift+3');
|
||||
}
|
||||
|
||||
// Unregister export log shortcut
|
||||
globalShortcut.unregister('Ctrl+Shift+D');
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies and toggle devtool based on global config settings
|
||||
* else displays a dialog
|
||||
*/
|
||||
private onRegisterDevtools(): void {
|
||||
const focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (!focusedWindow || !windowExists(focusedWindow)) {
|
||||
return;
|
||||
}
|
||||
const { devToolsEnabled } = config.getConfigFields(['devToolsEnabled']);
|
||||
if (devToolsEnabled) {
|
||||
if (
|
||||
this.mainWindow &&
|
||||
windowExists(this.mainWindow) &&
|
||||
focusedWindow === this.mainWindow
|
||||
) {
|
||||
if (this.mainView && viewExists(this.mainView)) {
|
||||
this.mainWebContents?.toggleDevTools();
|
||||
return;
|
||||
}
|
||||
}
|
||||
focusedWindow.webContents.toggleDevTools();
|
||||
return;
|
||||
}
|
||||
focusedWindow.webContents.closeDevTools();
|
||||
logger.info(
|
||||
`window-handler: dev tools disabled by admin, not opening it for the user!`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the window based on the window type
|
||||
*/
|
||||
private onReload(): void {
|
||||
const focusedWindow = BrowserWindow.getFocusedWindow();
|
||||
if (!focusedWindow || !windowExists(focusedWindow)) {
|
||||
return;
|
||||
}
|
||||
reloadWindow(focusedWindow as ICustomBrowserWindow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports all logs
|
||||
*/
|
||||
private onExportLogs(): void {
|
||||
logger.info('window-handler: Exporting logs');
|
||||
exportLogs();
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch between clients 1.5, 2.0 and 2.0 daily
|
||||
* @param clientSwitch client switch you want to switch to.
|
||||
*/
|
||||
private async switchClient(clientSwitch: ClientSwitchType): Promise<void> {
|
||||
logger.info(`window handler: switch to client ${clientSwitch}`);
|
||||
|
||||
if (!this.mainWebContents || this.mainWebContents.isDestroyed()) {
|
||||
logger.info(
|
||||
`window-handler: switch client - main window web contents destroyed already! exiting`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (!this.url) {
|
||||
this.url = this.globalConfig.url;
|
||||
}
|
||||
const parsedUrl = parse(this.url);
|
||||
const csrfToken = await this.mainWebContents?.executeJavaScript(
|
||||
`localStorage.getItem('x-km-csrf-token')`,
|
||||
);
|
||||
switch (clientSwitch) {
|
||||
case ClientSwitchType.CLIENT_1_5:
|
||||
this.url = this.startUrl + `?x-km-csrf-token=${csrfToken}`;
|
||||
break;
|
||||
case ClientSwitchType.CLIENT_2_0:
|
||||
this.url = `https://${parsedUrl.hostname}/client-bff/index.html?x-km-csrf-token=${csrfToken}`;
|
||||
break;
|
||||
case ClientSwitchType.CLIENT_2_0_DAILY:
|
||||
this.url = `https://${parsedUrl.hostname}/bff-daily/daily/index.html?x-km-csrf-token=${csrfToken}`;
|
||||
break;
|
||||
default:
|
||||
this.url = this.globalConfig.url + `?x-km-csrf-token=${csrfToken}`;
|
||||
}
|
||||
await this.execCmd(this.screenShareIndicatorFrameUtil, []);
|
||||
const userAgent = this.getUserAgent(this.mainWebContents);
|
||||
await this.mainWebContents.loadURL(this.url, { userAgent });
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
`window-handler: failed to switch client because of error ${e}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up reference
|
||||
*/
|
||||
|
@ -185,6 +185,9 @@
|
||||
"Speech": "Speech",
|
||||
"Start Speaking": "Start Speaking",
|
||||
"Stop Speaking": "Stop Speaking",
|
||||
"Switch to client 1.5": "Switch to client 1.5",
|
||||
"Switch to client 2.0": "Switch to client 2.0",
|
||||
"Switch to client 2.0 daily": "Switch to client 2.0 daily",
|
||||
"Symphony Help": "Symphony Help",
|
||||
"Symphony Url": "https://symphony.com/en-US",
|
||||
"Title Bar Style": "Title Bar Style",
|
||||
|
@ -185,6 +185,9 @@
|
||||
"Speech": "Speech",
|
||||
"Start Speaking": "Start Speaking",
|
||||
"Stop Speaking": "Stop Speaking",
|
||||
"Switch to client 1.5": "Switch to client 1.5",
|
||||
"Switch to client 2.0": "Switch to client 2.0",
|
||||
"Switch to client 2.0 daily": "Switch to client 2.0 daily",
|
||||
"Symphony Help": "Symphony Help",
|
||||
"Symphony Url": "https://symphony.com/en-US",
|
||||
"Title Bar Style": "Title Bar Style",
|
||||
|
@ -185,6 +185,9 @@
|
||||
"Speech": "Dictée vocale",
|
||||
"Start Speaking": "Commencer à dicter",
|
||||
"Stop Speaking": "Arreter de dicter",
|
||||
"Switch to client 1.5": "Passer au client 1.5",
|
||||
"Switch to client 2.0": "Passer au client 2.0",
|
||||
"Switch to client 2.0 daily": "Passer à client 2.0 daily",
|
||||
"Symphony Help": "Aide en ligne de Symphony",
|
||||
"Symphony Url": "https://symphony.com/fr-FR",
|
||||
"Title Bar Style": "Style de la barre de titre",
|
||||
|
@ -185,6 +185,9 @@
|
||||
"Speech": "Dictée vocale",
|
||||
"Start Speaking": "Commencer à dicter",
|
||||
"Stop Speaking": "Arreter de dicter",
|
||||
"Switch to client 1.5": "Passer au client 1.5",
|
||||
"Switch to client 2.0": "Passer au client 2.0",
|
||||
"Switch to client 2.0 daily": "Passer à client 2.0 daily",
|
||||
"Symphony Help": "Aide en ligne de Symphony",
|
||||
"Symphony Url": "https://symphony.com/fr-FR",
|
||||
"Title Bar Style": "Style de la barre de titre",
|
||||
|
@ -185,6 +185,9 @@
|
||||
"Speech": "スピーチ",
|
||||
"Start Speaking": "スピーチを開始",
|
||||
"Stop Speaking": "スピーチを終了",
|
||||
"Switch to client 1.5": "Client 1.5 に切り替え",
|
||||
"Switch to client 2.0": "Client 2.0 に切り替え",
|
||||
"Switch to client 2.0 daily": "Client 2.0 daily に切り替え",
|
||||
"Symphony Help": "Symphonyのヘルプ",
|
||||
"Symphony Url": "https://symphony.com/ja",
|
||||
"Title Bar Style": "タイトルバーのスタイル",
|
||||
|
@ -185,6 +185,9 @@
|
||||
"Speech": "スピーチ",
|
||||
"Start Speaking": "スピーチを開始",
|
||||
"Stop Speaking": "スピーチを終了",
|
||||
"Switch to client 1.5": "Client 1.5 に切り替え",
|
||||
"Switch to client 2.0": "Client 2.0 に切り替え",
|
||||
"Switch to client 2.0 daily": "Client 2.0 daily に切り替え",
|
||||
"Symphony Help": "Symphonyのヘルプ",
|
||||
"Symphony Url": "https://symphony.com/ja",
|
||||
"Title Bar Style": "タイトルバーのスタイル",
|
||||
|
Loading…
Reference in New Issue
Block a user