diff --git a/.vscode/launch.json b/.vscode/launch.json index a8300f84f..5afc2d051 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,8 @@ "program": "${workspaceFolder}/build/index.js", "protocol": "inspector", "env": { - "NODE_ENV": "development" + "NODE_ENV": "development", + "OS_PLATFORM": "win32" } }, { @@ -18,9 +19,10 @@ "name": "Franz – Live API", "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron", "program": "${workspaceFolder}/build/index.js", - "protocol": "inspector", + "protocol": "inspector", "env": { - "LIVE_API": "1" + "LIVE_API": "1", + "OS_PLATFORM": "win32" } }, { @@ -31,7 +33,8 @@ "program": "${workspaceFolder}/build/index.js", "protocol": "inspector", "env": { - "LOCAL_API": "1" + "LOCAL_API": "1", + "OS_PLATFORM": "win32" } } ] diff --git a/package.json b/package.json index fd96c602b..f35da9880 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "classnames": "^2.2.5", "du": "^0.1.0", "electron-fetch": "^1.1.0", + "electron-react-titlebar": "^0.7.1", "electron-spellchecker": "^1.1.2", "electron-updater": "^2.4.3", "electron-window-state": "^4.1.0", diff --git a/src/I18n.js b/src/I18n.js index ae3ba2fa9..4ee34157c 100644 --- a/src/I18n.js +++ b/src/I18n.js @@ -9,11 +9,18 @@ import UserStore from './stores/UserStore'; @inject('stores') @observer export default class I18N extends Component { + componentDidUpdate() { + window.franz.menu.rebuild(); + } + render() { const { stores, children } = this.props; const { locale } = stores.app; return ( - + { window.franz.intl = intlProvider ? intlProvider.getChildContext().intl : null; }} + > {children} ); diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js index 20dc2f764..686476317 100644 --- a/src/components/layout/AppLayout.js +++ b/src/components/layout/AppLayout.js @@ -2,10 +2,13 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; import { defineMessages, intlShape } from 'react-intl'; +import { TitleBar } from 'electron-react-titlebar'; import InfoBar from '../ui/InfoBar'; import globalMessages from '../../i18n/globalMessages'; +import { isMac } from '../../environment'; + function createMarkup(HTMLString) { return { __html: HTMLString }; } @@ -87,64 +90,67 @@ export default class AppLayout extends Component { return (
- {sidebar} -
- {news.length > 0 && news.map(item => ( - removeNewsItem({ newsId: item.id })} - > - - - ))} - {!isOnline && ( - - - {intl.formatMessage(globalMessages.notConnectedToTheInternet)} - - )} - {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( - - - {intl.formatMessage(messages.requiredRequestsFailed)} - - )} - {showServicesUpdatedInfoBar && ( - - - {intl.formatMessage(messages.servicesUpdated)} - - )} - {appUpdateIsDownloaded && ( - - - {intl.formatMessage(messages.updateAvailable)} - {intl.formatMessage(messages.changelog)} - - - )} - {services} + {!isMac && } +
+ {sidebar} +
+ {news.length > 0 && news.map(item => ( + removeNewsItem({ newsId: item.id })} + > + + + ))} + {!isOnline && ( + + + {intl.formatMessage(globalMessages.notConnectedToTheInternet)} + + )} + {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( + + + {intl.formatMessage(messages.requiredRequestsFailed)} + + )} + {showServicesUpdatedInfoBar && ( + + + {intl.formatMessage(messages.servicesUpdated)} + + )} + {appUpdateIsDownloaded && ( + + + {intl.formatMessage(messages.updateAvailable)} + {intl.formatMessage(messages.changelog)} + + + )} + {services} +
{children} diff --git a/src/environment.js b/src/environment.js index e185120c0..e1762129b 100644 --- a/src/environment.js +++ b/src/environment.js @@ -4,11 +4,17 @@ export const isDevMode = Boolean(process.execPath.match(/[\\/]electron/)); export const useLiveAPI = process.env.LIVE_API; export const useLocalAPI = process.env.LOCAL_API; -export const isMac = process.platform === 'darwin'; -export const isWindows = process.platform === 'win32'; -export const isLinux = process.platform === 'linux'; +let platform = process.platform; +if (process.env.OS_PLATFORM) { + platform = process.env.OS_PLATFORM; +} + +export const isMac = platform === 'darwin'; +export const isWindows = platform === 'win32'; +export const isLinux = platform === 'linux'; export const ctrlKey = isMac ? '⌘' : 'Ctrl'; +export const cmdKey = isMac ? 'Cmd' : 'Ctrl'; let api; if (!isDevMode || (isDevMode && useLiveAPI)) { diff --git a/src/helpers/validation-helpers.js b/src/helpers/validation-helpers.js index a8a242d54..2f762437d 100644 --- a/src/helpers/validation-helpers.js +++ b/src/helpers/validation-helpers.js @@ -1,6 +1,31 @@ +import { defineMessages } from 'react-intl'; + +const messages = defineMessages({ + required: { + id: 'validation.required', + defaultMessage: '!!!Field is required', + }, + email: { + id: 'validation.email', + defaultMessage: '!!!Email not valid', + }, + url: { + id: 'validation.url', + defaultMessage: '!!!Not a valid URL', + }, + minLength: { + id: 'validation.minLength', + defaultMessage: '!!!Too few characters', + }, + oneRequired: { + id: 'validation.oneRequired', + defaultMessage: '!!!At least one is required', + }, +}); + export function required({ field }) { const isValid = (field.value.trim() !== ''); - return [isValid, `${field.label} is required`]; + return [isValid, window.franz.intl.formatMessage(messages.required, { field: field.label })]; } export function email({ field }) { @@ -13,7 +38,7 @@ export function email({ field }) { isValid = true; } - return [isValid, `${field.label} not valid`]; + return [isValid, window.franz.intl.formatMessage(messages.email, { field: field.label })]; } export function url({ field }) { @@ -27,7 +52,7 @@ export function url({ field }) { isValid = true; } - return [isValid, `${field.label} is not a valid url`]; + return [isValid, window.franz.intl.formatMessage(messages.url, { field: field.label })]; } export function minLength(length) { @@ -36,13 +61,13 @@ export function minLength(length) { if (field.touched) { isValid = field.value.length >= length; } - return [isValid, `${field.label} should be at least ${length} characters long.`]; + return [isValid, window.franz.intl.formatMessage(messages.minLength, { field: field.label, length })]; }; } export function oneRequired(targets) { return ({ field, form }) => { const invalidFields = targets.filter(target => form.$(target).value === ''); - return [targets.length !== invalidFields.length, `${field.label} is required`]; + return [targets.length !== invalidFields.length, window.franz.intl.formatMessage(messages.required, { field: field.label })]; }; } diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index d5c0ea441..400a9a5d8 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -199,5 +199,52 @@ "service.crashHandler.action": "Reload {name}", "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", "service.disabledHandler.headline": "{name} is disabled", - "service.disabledHandler.action": "Enable {name}" + "service.disabledHandler.action": "Enable {name}", + "menu.edit": "Edit", + "menu.edit.undo": "Undo", + "menu.edit.redo": "Redo", + "menu.edit.cut": "Cut", + "menu.edit.copy": "Copy", + "menu.edit.paste": "Paste", + "menu.edit.pasteAndMatchStyle": "Paste And Match Style", + "menu.edit.delete": "Delete", + "menu.edit.selectAll": "Select All", + "menu.edit.speech": "Speech", + "menu.edit.startSpeaking": "Start Speaking", + "menu.edit.stopSpeaking": "Stop Speaking", + "menu.edit.startDictation": "Start Dictation", + "menu.edit.emojiSymbols": "Emoji & Symbols", + "menu.view.resetZoom": "Actual Size", + "menu.view.zoomIn": "Zoom In", + "menu.view.zoomOut": "Zoom Out", + "menu.view.enterFullScreen": "Enter Full Screen", + "menu.view.exitFullScreen": "Exit Full Screen", + "menu.view.toggleFullScreen": "Toggle Full Screen", + "menu.view.toggleDevTools": "Toggle Developer Tools", + "menu.view.toggleServiceDevTools": "Toggle Service Developer Tools", + "menu.view.reloadService": "Reload Service", + "menu.view.reloadFranz": "Reload Franz", + "menu.window.minimize": "Minimize", + "menu.window.close": "Close", + "menu.help.learnMore": "Learn More", + "menu.help.changelog": "Changelog", + "menu.help.support": "Support", + "menu.help.tos": "Terms of Service", + "menu.help.privacy": "Privacy Statement", + "menu.file": "File", + "menu.view": "View", + "menu.services": "Services", + "menu.window": "Window", + "menu.help": "Help", + "menu.app.about": "About Franz", + "menu.app.settings": "Settings", + "menu.app.hide": "Hide", + "menu.app.hideOthers": "Hide Others", + "menu.app.unhide": "Unhide", + "menu.app.quit": "Quit", + "menu.services.addNewService": "Add New Service...", + "validation.required": "{field} is required", + "validation.email": "{field} is not valid", + "validation.url": "{field} is not a valid URL", + "validation.minLength": "{field} should be at least {length} characters long" } diff --git a/src/index.html b/src/index.html index 9e5acd705..6c259e5be 100644 --- a/src/index.html +++ b/src/index.html @@ -11,7 +11,7 @@
DEV MODE