aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar haraldox <hnaumann+github@gmail.com>2018-03-02 13:48:34 +0100
committerLibravatar haraldox <hnaumann+github@gmail.com>2018-03-02 13:48:34 +0100
commita49511f4b71c3902f9f3b24622428dc715bd96d8 (patch)
tree297dbe5145fa8036e2d3f2297fac4d79ad3d5983 /src
parentMerge branch 'feature/titlebar' into feature/i18n-universal (diff)
downloadferdium-app-a49511f4b71c3902f9f3b24622428dc715bd96d8.tar.gz
ferdium-app-a49511f4b71c3902f9f3b24622428dc715bd96d8.tar.zst
ferdium-app-a49511f4b71c3902f9f3b24622428dc715bd96d8.zip
internationalized menu
tested on macOS
Diffstat (limited to 'src')
-rw-r--r--src/i18n/locales/en-US.json42
-rw-r--r--src/lib/Menu.js307
2 files changed, 299 insertions, 50 deletions
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index cd0258d8a..400a9a5d8 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -201,6 +201,48 @@
201 "service.disabledHandler.headline": "{name} is disabled", 201 "service.disabledHandler.headline": "{name} is disabled",
202 "service.disabledHandler.action": "Enable {name}", 202 "service.disabledHandler.action": "Enable {name}",
203 "menu.edit": "Edit", 203 "menu.edit": "Edit",
204 "menu.edit.undo": "Undo",
205 "menu.edit.redo": "Redo",
206 "menu.edit.cut": "Cut",
207 "menu.edit.copy": "Copy",
208 "menu.edit.paste": "Paste",
209 "menu.edit.pasteAndMatchStyle": "Paste And Match Style",
210 "menu.edit.delete": "Delete",
211 "menu.edit.selectAll": "Select All",
212 "menu.edit.speech": "Speech",
213 "menu.edit.startSpeaking": "Start Speaking",
214 "menu.edit.stopSpeaking": "Stop Speaking",
215 "menu.edit.startDictation": "Start Dictation",
216 "menu.edit.emojiSymbols": "Emoji & Symbols",
217 "menu.view.resetZoom": "Actual Size",
218 "menu.view.zoomIn": "Zoom In",
219 "menu.view.zoomOut": "Zoom Out",
220 "menu.view.enterFullScreen": "Enter Full Screen",
221 "menu.view.exitFullScreen": "Exit Full Screen",
222 "menu.view.toggleFullScreen": "Toggle Full Screen",
223 "menu.view.toggleDevTools": "Toggle Developer Tools",
224 "menu.view.toggleServiceDevTools": "Toggle Service Developer Tools",
225 "menu.view.reloadService": "Reload Service",
226 "menu.view.reloadFranz": "Reload Franz",
227 "menu.window.minimize": "Minimize",
228 "menu.window.close": "Close",
229 "menu.help.learnMore": "Learn More",
230 "menu.help.changelog": "Changelog",
231 "menu.help.support": "Support",
232 "menu.help.tos": "Terms of Service",
233 "menu.help.privacy": "Privacy Statement",
234 "menu.file": "File",
235 "menu.view": "View",
236 "menu.services": "Services",
237 "menu.window": "Window",
238 "menu.help": "Help",
239 "menu.app.about": "About Franz",
240 "menu.app.settings": "Settings",
241 "menu.app.hide": "Hide",
242 "menu.app.hideOthers": "Hide Others",
243 "menu.app.unhide": "Unhide",
244 "menu.app.quit": "Quit",
245 "menu.services.addNewService": "Add New Service...",
204 "validation.required": "{field} is required", 246 "validation.required": "{field} is required",
205 "validation.email": "{field} is not valid", 247 "validation.email": "{field} is not valid",
206 "validation.url": "{field} is not a valid URL", 248 "validation.url": "{field} is not a valid URL",
diff --git a/src/lib/Menu.js b/src/lib/Menu.js
index 50196af96..5a05e47b3 100644
--- a/src/lib/Menu.js
+++ b/src/lib/Menu.js
@@ -11,6 +11,174 @@ const menuItems = defineMessages({
11 id: 'menu.edit', 11 id: 'menu.edit',
12 defaultMessage: '!!!Edit', 12 defaultMessage: '!!!Edit',
13 }, 13 },
14 undo: {
15 id: 'menu.edit.undo',
16 defaultMessage: '!!!Undo',
17 },
18 redo: {
19 id: 'menu.edit.redo',
20 defaultMessage: '!!!Redo',
21 },
22 cut: {
23 id: 'menu.edit.cut',
24 defaultMessage: '!!!Cut',
25 },
26 copy: {
27 id: 'menu.edit.copy',
28 defaultMessage: '!!!Copy',
29 },
30 paste: {
31 id: 'menu.edit.paste',
32 defaultMessage: '!!!Paste',
33 },
34 pasteAndMatchStyle: {
35 id: 'menu.edit.pasteAndMatchStyle',
36 defaultMessage: '!!!Paste And Match Style',
37 },
38 delete: {
39 id: 'menu.edit.delete',
40 defaultMessage: '!!!Delete',
41 },
42 selectAll: {
43 id: 'menu.edit.selectAll',
44 defaultMessage: '!!!Select All',
45 },
46 speech: {
47 id: 'menu.edit.speech',
48 defaultMessage: '!!!Speech',
49 },
50 startSpeaking: {
51 id: 'menu.edit.startSpeaking',
52 defaultMessage: '!!!Start Speaking',
53 },
54 stopSpeaking: {
55 id: 'menu.edit.stopSpeaking',
56 defaultMessage: '!!!Stop Speaking',
57 },
58 startDictation: {
59 id: 'menu.edit.startDictation',
60 defaultMessage: '!!!Start Dictation',
61 },
62 emojiSymbols: {
63 id: 'menu.edit.emojiSymbols',
64 defaultMessage: '!!!Emoji & Symbols',
65 },
66 resetZoom: {
67 id: 'menu.view.resetZoom',
68 defaultMessage: '!!!Actual Size',
69 },
70 zoomIn: {
71 id: 'menu.view.zoomIn',
72 defaultMessage: '!!!Zoom In',
73 },
74 zoomOut: {
75 id: 'menu.view.zoomOut',
76 defaultMessage: '!!!Zoom Out',
77 },
78 enterFullScreen: {
79 id: 'menu.view.enterFullScreen',
80 defaultMessage: '!!!Enter Full Screen',
81 },
82 exitFullScreen: {
83 id: 'menu.view.exitFullScreen',
84 defaultMessage: '!!!Exit Full Screen',
85 },
86 toggleFullScreen: {
87 id: 'menu.view.toggleFullScreen',
88 defaultMessage: '!!!Toggle Full Screen',
89 },
90 toggleDevTools: {
91 id: 'menu.view.toggleDevTools',
92 defaultMessage: '!!!Toggle Developer Tools',
93 },
94 toggleServiceDevTools: {
95 id: 'menu.view.toggleServiceDevTools',
96 defaultMessage: '!!!Toggle Service Developer Tools',
97 },
98 reloadService: {
99 id: 'menu.view.reloadService',
100 defaultMessage: '!!!Reload Service',
101 },
102 reloadFranz: {
103 id: 'menu.view.reloadFranz',
104 defaultMessage: '!!!Reload Franz',
105 },
106 minimize: {
107 id: 'menu.window.minimize',
108 defaultMessage: '!!!Minimize',
109 },
110 close: {
111 id: 'menu.window.close',
112 defaultMessage: '!!!Close',
113 },
114 learnMore: {
115 id: 'menu.help.learnMore',
116 defaultMessage: '!!!Learn More',
117 },
118 changelog: {
119 id: 'menu.help.changelog',
120 defaultMessage: '!!!Changelog',
121 },
122 support: {
123 id: 'menu.help.support',
124 defaultMessage: '!!!Support',
125 },
126 tos: {
127 id: 'menu.help.tos',
128 defaultMessage: '!!!Terms of Service',
129 },
130 privacy: {
131 id: 'menu.help.privacy',
132 defaultMessage: '!!!Privacy Statement',
133 },
134 file: {
135 id: 'menu.file',
136 defaultMessage: '!!!File',
137 },
138 view: {
139 id: 'menu.view',
140 defaultMessage: '!!!View',
141 },
142 services: {
143 id: 'menu.services',
144 defaultMessage: '!!!Services',
145 },
146 window: {
147 id: 'menu.window',
148 defaultMessage: '!!!Window',
149 },
150 help: {
151 id: 'menu.help',
152 defaultMessage: '!!!Help',
153 },
154 about: {
155 id: 'menu.app.about',
156 defaultMessage: '!!!About Franz',
157 },
158 settings: {
159 id: 'menu.app.settings',
160 defaultMessage: '!!!Settings',
161 },
162 hide: {
163 id: 'menu.app.hide',
164 defaultMessage: '!!!Hide',
165 },
166 hideOthers: {
167 id: 'menu.app.hideOthers',
168 defaultMessage: '!!!Hide Others',
169 },
170 unhide: {
171 id: 'menu.app.unhide',
172 defaultMessage: '!!!Unhide',
173 },
174 quit: {
175 id: 'menu.app.quit',
176 defaultMessage: '!!!Quit',
177 },
178 addNewService: {
179 id: 'menu.services.addNewService',
180 defaultMessage: '!!!Add New Service...',
181 },
14}); 182});
15 183
16function getActiveWebview() { 184function getActiveWebview() {
@@ -22,104 +190,123 @@ const _templateFactory = intl => [
22 label: intl.formatMessage(menuItems.edit), 190 label: intl.formatMessage(menuItems.edit),
23 submenu: [ 191 submenu: [
24 { 192 {
193 label: intl.formatMessage(menuItems.undo),
25 role: 'undo', 194 role: 'undo',
26 }, 195 },
27 { 196 {
197 label: intl.formatMessage(menuItems.redo),
28 role: 'redo', 198 role: 'redo',
29 }, 199 },
30 { 200 {
31 type: 'separator', 201 type: 'separator',
32 }, 202 },
33 { 203 {
34 role: 'cut', 204 label: intl.formatMessage(menuItems.cut),
205 accelerator: 'Cmd+X',
206 selector: 'cut:',
35 }, 207 },
36 { 208 {
37 label: 'Copy', 209 label: intl.formatMessage(menuItems.copy),
38 accelerator: 'CmdOrCtrl+C', 210 accelerator: 'Cmd+C',
39 selector: 'copy:', 211 selector: 'copy:',
40 }, 212 },
41 { 213 {
42 label: 'Paste', 214 label: intl.formatMessage(menuItems.paste),
43 accelerator: 'CmdOrCtrl+V', 215 accelerator: 'Cmd+V',
44 selector: 'paste:', 216 selector: 'paste:',
45 }, 217 },
46 { 218 {
47 role: 'pasteandmatchstyle', 219 label: intl.formatMessage(menuItems.pasteAndMatchStyle),
220 accelerator: 'Cmd+Shift+V',
221 selector: 'pasteAndMatchStyle:',
48 }, 222 },
49 { 223 {
224 label: intl.formatMessage(menuItems.delete),
50 role: 'delete', 225 role: 'delete',
51 }, 226 },
52 { 227 {
53 role: 'selectall', 228 label: intl.formatMessage(menuItems.selectAll),
229 accelerator: 'Cmd+A',
230 selector: 'selectAll:',
54 }, 231 },
55 ], 232 ],
56 }, 233 },
57 { 234 {
58 label: 'View', 235 label: intl.formatMessage(menuItems.view),
59 submenu: [ 236 submenu: [
60 { 237 {
61 type: 'separator', 238 type: 'separator',
62 }, 239 },
63 { 240 {
241 label: intl.formatMessage(menuItems.resetZoom),
64 role: 'resetzoom', 242 role: 'resetzoom',
65 }, 243 },
66 { 244 {
245 label: intl.formatMessage(menuItems.zoomIn),
246 // accelerator: 'Cmd+=',
67 role: 'zoomin', 247 role: 'zoomin',
68 accelerator: 'CommandOrControl+=',
69 }, 248 },
70 { 249 {
250 label: intl.formatMessage(menuItems.zoomOut),
71 role: 'zoomout', 251 role: 'zoomout',
72 }, 252 },
73 { 253 {
74 type: 'separator', 254 type: 'separator',
75 }, 255 },
76 { 256 {
257 label: app.mainWindow.isFullScreen() // label doesn't work, gets overridden by Electron
258 ? intl.formatMessage(menuItems.exitFullScreen)
259 : intl.formatMessage(menuItems.enterFullScreen),
77 role: 'togglefullscreen', 260 role: 'togglefullscreen',
78 }, 261 },
79 ], 262 ],
80 }, 263 },
81 { 264 {
82 label: 'Services', 265 label: intl.formatMessage(menuItems.services),
83 submenu: [], 266 submenu: [],
84 }, 267 },
85 { 268 {
269 label: intl.formatMessage(menuItems.window),
86 role: 'window', 270 role: 'window',
87 submenu: [ 271 submenu: [
88 { 272 {
273 label: intl.formatMessage(menuItems.minimize),
89 role: 'minimize', 274 role: 'minimize',
90 }, 275 },
91 { 276 {
277 label: intl.formatMessage(menuItems.close),
92 role: 'close', 278 role: 'close',
93 }, 279 },
94 ], 280 ],
95 }, 281 },
96 { 282 {
283 label: intl.formatMessage(menuItems.help),
97 role: 'help', 284 role: 'help',
98 submenu: [ 285 submenu: [
99 { 286 {
100 label: 'Learn More', 287 label: intl.formatMessage(menuItems.learnMore),
101 click() { shell.openExternal('http://meetfranz.com'); }, 288 click() { shell.openExternal('http://meetfranz.com'); },
102 }, 289 },
103 { 290 {
104 label: 'Changelog', 291 label: intl.formatMessage(menuItems.changelog),
105 click() { shell.openExternal('https://github.com/meetfranz/franz/blob/master/CHANGELOG.md'); }, 292 click() { shell.openExternal('https://github.com/meetfranz/franz/blob/master/CHANGELOG.md'); },
106 }, 293 },
107 { 294 {
108 type: 'separator', 295 type: 'separator',
109 }, 296 },
110 { 297 {
111 label: 'Support', 298 label: intl.formatMessage(menuItems.support),
112 click() { shell.openExternal('http://meetfranz.com/support'); }, 299 click() { shell.openExternal('http://meetfranz.com/support'); },
113 }, 300 },
114 { 301 {
115 type: 'separator', 302 type: 'separator',
116 }, 303 },
117 { 304 {
118 label: 'Terms of Service', 305 label: intl.formatMessage(menuItems.tos),
119 click() { shell.openExternal('https://meetfranz.com/terms'); }, 306 click() { shell.openExternal('https://meetfranz.com/terms'); },
120 }, 307 },
121 { 308 {
122 label: 'Privacy Statement', 309 label: intl.formatMessage(menuItems.privacy),
123 click() { shell.openExternal('https://meetfranz.com/privacy'); }, 310 click() { shell.openExternal('https://meetfranz.com/privacy'); },
124 }, 311 },
125 ], 312 ],
@@ -128,17 +315,17 @@ const _templateFactory = intl => [
128 315
129const _titleBarTemplateFactory = intl => [ 316const _titleBarTemplateFactory = intl => [
130 { 317 {
131 label: 'Edit', 318 label: intl.formatMessage(menuItems.edit),
132 submenu: [ 319 submenu: [
133 { 320 {
134 label: 'Undo', 321 label: intl.formatMessage(menuItems.undo),
135 accelerator: `${ctrlKey}+Z`, 322 accelerator: `${ctrlKey}+Z`,
136 click() { 323 click() {
137 getActiveWebview().undo(); 324 getActiveWebview().undo();
138 }, 325 },
139 }, 326 },
140 { 327 {
141 label: 'Redo', 328 label: intl.formatMessage(menuItems.redo),
142 accelerator: `${ctrlKey}+Y`, 329 accelerator: `${ctrlKey}+Y`,
143 click() { 330 click() {
144 getActiveWebview().redo(); 331 getActiveWebview().redo();
@@ -148,41 +335,41 @@ const _titleBarTemplateFactory = intl => [
148 type: 'separator', 335 type: 'separator',
149 }, 336 },
150 { 337 {
151 label: 'Cut', 338 label: intl.formatMessage(menuItems.cut),
152 accelerator: `${ctrlKey}+X`, 339 accelerator: `${ctrlKey}+X`,
153 click() { 340 click() {
154 getActiveWebview().cut(); 341 getActiveWebview().cut();
155 }, 342 },
156 }, 343 },
157 { 344 {
158 label: 'Copy', 345 label: intl.formatMessage(menuItems.copy),
159 accelerator: `${ctrlKey}+C`, 346 accelerator: `${ctrlKey}+C`,
160 click() { 347 click() {
161 getActiveWebview().copy(); 348 getActiveWebview().copy();
162 }, 349 },
163 }, 350 },
164 { 351 {
165 label: 'Paste', 352 label: intl.formatMessage(menuItems.paste),
166 accelerator: `${ctrlKey}+V`, 353 accelerator: `${ctrlKey}+V`,
167 click() { 354 click() {
168 getActiveWebview().paste(); 355 getActiveWebview().paste();
169 }, 356 },
170 }, 357 },
171 { 358 {
172 label: 'Paste and Match Style', 359 label: intl.formatMessage(menuItems.pasteAndMatchStyle),
173 accelerator: `${ctrlKey}+Shift+V`, 360 accelerator: `${ctrlKey}+Shift+V`,
174 click() { 361 click() {
175 getActiveWebview().pasteAndMatchStyle(); 362 getActiveWebview().pasteAndMatchStyle();
176 }, 363 },
177 }, 364 },
178 { 365 {
179 label: 'Delete', 366 label: intl.formatMessage(menuItems.delete),
180 click() { 367 click() {
181 getActiveWebview().delete(); 368 getActiveWebview().delete();
182 }, 369 },
183 }, 370 },
184 { 371 {
185 label: 'Select All', 372 label: intl.formatMessage(menuItems.selectAll),
186 accelerator: `${ctrlKey}+A`, 373 accelerator: `${ctrlKey}+A`,
187 click() { 374 click() {
188 getActiveWebview().selectAll(); 375 getActiveWebview().selectAll();
@@ -191,21 +378,21 @@ const _titleBarTemplateFactory = intl => [
191 ], 378 ],
192 }, 379 },
193 { 380 {
194 label: 'View', 381 label: intl.formatMessage(menuItems.view),
195 submenu: [ 382 submenu: [
196 { 383 {
197 type: 'separator', 384 type: 'separator',
198 }, 385 },
199 { 386 {
200 label: 'Reset Zoom', 387 label: intl.formatMessage(menuItems.resetZoom),
201 accelerator: `${ctrlKey}+0`, 388 accelerator: `${ctrlKey}+0`,
202 click() { 389 click() {
203 getActiveWebview().setZoomLevel(0); 390 getActiveWebview().setZoomLevel(0);
204 }, 391 },
205 }, 392 },
206 { 393 {
207 label: 'Zoom in', 394 label: intl.formatMessage(menuItems.zoomIn),
208 accelerator: `${ctrlKey}+=`, 395 accelerator: `${ctrlKey}+Plus`,
209 click() { 396 click() {
210 getActiveWebview().getZoomLevel((zoomLevel) => { 397 getActiveWebview().getZoomLevel((zoomLevel) => {
211 getActiveWebview().setZoomLevel(zoomLevel === 5 ? zoomLevel : zoomLevel + 1); 398 getActiveWebview().setZoomLevel(zoomLevel === 5 ? zoomLevel : zoomLevel + 1);
@@ -213,7 +400,7 @@ const _titleBarTemplateFactory = intl => [
213 }, 400 },
214 }, 401 },
215 { 402 {
216 label: 'Zoom out', 403 label: intl.formatMessage(menuItems.zoomOut),
217 accelerator: `${ctrlKey}+-`, 404 accelerator: `${ctrlKey}+-`,
218 click() { 405 click() {
219 getActiveWebview().getZoomLevel((zoomLevel) => { 406 getActiveWebview().getZoomLevel((zoomLevel) => {
@@ -221,24 +408,36 @@ const _titleBarTemplateFactory = intl => [
221 }); 408 });
222 }, 409 },
223 }, 410 },
411 {
412 type: 'separator',
413 },
414 {
415 label: app.mainWindow.isFullScreen() // label doesn't work, gets overridden by Electron
416 ? intl.formatMessage(menuItems.exitFullScreen)
417 : intl.formatMessage(menuItems.enterFullScreen),
418 accelerator: `${ctrlKey}+F`,
419 click(menuItem, browserWindow) {
420 browserWindow.setFullScreen(!browserWindow.isFullScreen());
421 },
422 },
224 ], 423 ],
225 }, 424 },
226 { 425 {
227 label: 'Services', 426 label: intl.formatMessage(menuItems.services),
228 submenu: [], 427 submenu: [],
229 }, 428 },
230 { 429 {
231 label: 'Window', 430 label: intl.formatMessage(menuItems.window),
232 submenu: [ 431 submenu: [
233 { 432 {
234 label: 'Minimize', 433 label: intl.formatMessage(menuItems.minimize),
235 accelerator: 'Alt+M', 434 accelerator: 'Alt+M',
236 click(menuItem, browserWindow) { 435 click(menuItem, browserWindow) {
237 browserWindow.minimize(); 436 browserWindow.minimize();
238 }, 437 },
239 }, 438 },
240 { 439 {
241 label: 'Close', 440 label: intl.formatMessage(menuItems.close),
242 accelerator: 'Alt+W', 441 accelerator: 'Alt+W',
243 click(menuItem, browserWindow) { 442 click(menuItem, browserWindow) {
244 browserWindow.close(); 443 browserWindow.close();
@@ -250,29 +449,29 @@ const _titleBarTemplateFactory = intl => [
250 label: '?', 449 label: '?',
251 submenu: [ 450 submenu: [
252 { 451 {
253 label: 'Learn More', 452 label: intl.formatMessage(menuItems.learnMore),
254 click() { shell.openExternal('http://meetfranz.com'); }, 453 click() { shell.openExternal('http://meetfranz.com'); },
255 }, 454 },
256 { 455 {
257 label: 'Changelog', 456 label: intl.formatMessage(menuItems.changelog),
258 click() { shell.openExternal('https://github.com/meetfranz/franz/blob/master/CHANGELOG.md'); }, 457 click() { shell.openExternal('https://github.com/meetfranz/franz/blob/master/CHANGELOG.md'); },
259 }, 458 },
260 { 459 {
261 type: 'separator', 460 type: 'separator',
262 }, 461 },
263 { 462 {
264 label: 'Support', 463 label: intl.formatMessage(menuItems.support),
265 click() { shell.openExternal('http://meetfranz.com/support'); }, 464 click() { shell.openExternal('http://meetfranz.com/support'); },
266 }, 465 },
267 { 466 {
268 type: 'separator', 467 type: 'separator',
269 }, 468 },
270 { 469 {
271 label: 'Terms of Service', 470 label: intl.formatMessage(menuItems.tos),
272 click() { shell.openExternal('https://meetfranz.com/terms'); }, 471 click() { shell.openExternal('https://meetfranz.com/terms'); },
273 }, 472 },
274 { 473 {
275 label: 'Privacy Statement', 474 label: intl.formatMessage(menuItems.privacy),
276 click() { shell.openExternal('https://meetfranz.com/privacy'); }, 475 click() { shell.openExternal('https://meetfranz.com/privacy'); },
277 }, 476 },
278 ], 477 ],
@@ -311,13 +510,13 @@ export default class FranzMenu {
311 tpl[1].submenu.push({ 510 tpl[1].submenu.push({
312 type: 'separator', 511 type: 'separator',
313 }, { 512 }, {
314 label: 'Toggle Developer Tools', 513 label: intl.formatMessage(menuItems.toggleDevTools),
315 accelerator: `${cmdKey}+Alt+I`, 514 accelerator: `${cmdKey}+Alt+I`,
316 click: (menuItem, browserWindow) => { 515 click: (menuItem, browserWindow) => {
317 browserWindow.webContents.toggleDevTools(); 516 browserWindow.webContents.toggleDevTools();
318 }, 517 },
319 }, { 518 }, {
320 label: 'Open Service Developer Tools', 519 label: intl.formatMessage(menuItems.toggleServiceDevTools),
321 accelerator: `${cmdKey}+Shift+Alt+I`, 520 accelerator: `${cmdKey}+Shift+Alt+I`,
322 click: () => { 521 click: () => {
323 this.actions.service.openDevToolsForActiveService(); 522 this.actions.service.openDevToolsForActiveService();
@@ -325,8 +524,8 @@ export default class FranzMenu {
325 }); 524 });
326 525
327 tpl[1].submenu.unshift({ 526 tpl[1].submenu.unshift({
328 label: 'Reload Service', 527 label: intl.formatMessage(menuItems.reloadService),
329 id: 'reloadService', 528 id: 'reloadService', // TODO: needed?
330 accelerator: `${cmdKey}+R`, 529 accelerator: `${cmdKey}+R`,
331 click: () => { 530 click: () => {
332 if (this.stores.user.isLoggedIn 531 if (this.stores.user.isLoggedIn
@@ -337,7 +536,7 @@ export default class FranzMenu {
337 } 536 }
338 }, 537 },
339 }, { 538 }, {
340 label: 'Reload Franz', 539 label: intl.formatMessage(menuItems.reloadFranz),
341 accelerator: `${cmdKey}+Shift+R`, 540 accelerator: `${cmdKey}+Shift+R`,
342 click: () => { 541 click: () => {
343 window.location.reload(); 542 window.location.reload();
@@ -345,16 +544,17 @@ export default class FranzMenu {
345 }); 544 });
346 545
347 tpl.unshift({ 546 tpl.unshift({
348 label: isMac ? app.getName() : 'File', 547 label: isMac ? app.getName() : intl.formatMessage(menuItems.file),
349 submenu: [ 548 submenu: [
350 { 549 {
550 label: intl.formatMessage(menuItems.about),
351 role: 'about', 551 role: 'about',
352 }, 552 },
353 { 553 {
354 type: 'separator', 554 type: 'separator',
355 }, 555 },
356 { 556 {
357 label: 'Settings', 557 label: intl.formatMessage(menuItems.settings),
358 accelerator: 'CmdOrCtrl+,', 558 accelerator: 'CmdOrCtrl+,',
359 click: () => { 559 click: () => {
360 this.actions.ui.openSettings({ path: 'app' }); 560 this.actions.ui.openSettings({ path: 'app' });
@@ -364,6 +564,7 @@ export default class FranzMenu {
364 type: 'separator', 564 type: 'separator',
365 }, 565 },
366 { 566 {
567 label: intl.formatMessage(menuItems.services),
367 role: 'services', 568 role: 'services',
368 submenu: [], 569 submenu: [],
369 }, 570 },
@@ -371,25 +572,29 @@ export default class FranzMenu {
371 type: 'separator', 572 type: 'separator',
372 }, 573 },
373 { 574 {
575 label: intl.formatMessage(menuItems.hide),
374 role: 'hide', 576 role: 'hide',
375 }, 577 },
376 { 578 {
579 label: intl.formatMessage(menuItems.hideOthers),
377 role: 'hideothers', 580 role: 'hideothers',
378 }, 581 },
379 { 582 {
583 label: intl.formatMessage(menuItems.unhide),
380 role: 'unhide', 584 role: 'unhide',
381 }, 585 },
382 { 586 {
383 type: 'separator', 587 type: 'separator',
384 }, 588 },
385 { 589 {
590 label: intl.formatMessage(menuItems.quit),
386 role: 'quit', 591 role: 'quit',
387 }, 592 },
388 ], 593 ],
389 }); 594 });
390 595
391 const about = { 596 const about = {
392 label: 'About Franz', 597 label: intl.formatMessage(menuItems.about),
393 click: () => { 598 click: () => {
394 dialog.showMessageBox({ 599 dialog.showMessageBox({
395 type: 'info', 600 type: 'info',
@@ -407,12 +612,14 @@ export default class FranzMenu {
407 type: 'separator', 612 type: 'separator',
408 }, 613 },
409 { 614 {
410 label: 'Speech', 615 label: intl.formatMessage(menuItems.speech),
411 submenu: [ 616 submenu: [
412 { 617 {
618 label: intl.formatMessage(menuItems.startSpeaking),
413 role: 'startspeaking', 619 role: 'startspeaking',
414 }, 620 },
415 { 621 {
622 label: intl.formatMessage(menuItems.stopSpeaking),
416 role: 'stopspeaking', 623 role: 'stopspeaking',
417 }, 624 },
418 ], 625 ],
@@ -425,7 +632,7 @@ export default class FranzMenu {
425 } else { 632 } else {
426 tpl[0].submenu = [ 633 tpl[0].submenu = [
427 { 634 {
428 label: 'Preferences...', 635 label: intl.formatMessage(menuItems.settings),
429 accelerator: 'Ctrl+P', 636 accelerator: 'Ctrl+P',
430 click: () => { 637 click: () => {
431 this.actions.ui.openSettings({ path: 'app' }); 638 this.actions.ui.openSettings({ path: 'app' });
@@ -435,7 +642,7 @@ export default class FranzMenu {
435 type: 'separator', 642 type: 'separator',
436 }, 643 },
437 { 644 {
438 label: 'Quit', 645 label: intl.formatMessage(menuItems.quit),
439 accelerator: 'Alt+F4', 646 accelerator: 'Alt+F4',
440 click: () => { 647 click: () => {
441 app.quit(); 648 app.quit();
@@ -449,7 +656,7 @@ export default class FranzMenu {
449 } 656 }
450 657
451 serviceTpl.unshift({ 658 serviceTpl.unshift({
452 label: 'Add new Service', 659 label: intl.formatMessage(menuItems.addNewService),
453 accelerator: `${cmdKey}+N`, 660 accelerator: `${cmdKey}+N`,
454 click: () => { 661 click: () => {
455 this.actions.ui.openSettings({ path: 'recipes' }); 662 this.actions.ui.openSettings({ path: 'recipes' });