import { app , MenuItem , WebContents } from 'electron' ; import * as path from 'path' ; import { ContextMenuBuilder , DictionarySync , SpellCheckHandler , } from 'electron-spellchecker' ; import { isDevEnv , isMac } from '../common/env' ; import { i18n , LocaleType } from '../common/i18n' ; import { logger } from '../common/logger' ; import { ICustomBrowserWindow } from './window-handler' ; import { reloadWindow } from './window-utils' ; export class SpellChecker { public locale : LocaleType = 'en-US' ; private readonly spellCheckHandler : SpellCheckHandler ; private readonly dictionaryPath : string | undefined ; private readonly dictionarySync : DictionarySync ; constructor ( ) { const dictionariesDirName = 'dictionaries' ; if ( isDevEnv ) { this . dictionaryPath = path . join ( app . getAppPath ( ) , dictionariesDirName ) ; } else { const execPath = path . dirname ( app . getPath ( 'exe' ) ) ; this . dictionaryPath = path . join ( execPath , isMac ? '..' : '' , dictionariesDirName ) ; } this . dictionarySync = new DictionarySync ( this . dictionaryPath ) ; this . spellCheckHandler = new SpellCheckHandler ( this . dictionarySync ) ; this . spellCheckHandler . automaticallyIdentifyLanguages = false ; if ( ! isMac ) { const sysLocale = app . getLocale ( ) || 'en-US' ; this . spellCheckHandler . switchLanguage ( sysLocale ) ; } app . on ( 'web-contents-created' , ( _event , webContents ) : void => { this . attachToWebContents ( webContents ) ; } ) ; } param webContents { WeContents } public attachToWebContents ( webContents ) { const contextMenuBuilder = new ContextMenuBuilder ( this . spellCheckHandler , webContents , false , this . processMenu ) ; contextMenuBuilder . setAlternateStringFormatter ( this . getStringTable ( ) ) ; this . locale = i18n . getLocale ( ) ; logger . info ( `spell-check-handler: Building context menu with locale ${ this . locale }!` ) ; const contextMenuListener = ( _event , info ) => { if ( this . locale !== i18n . getLocale ( ) ) { contextMenuBuilder . setAlternateStringFormatter ( this . getStringTable ( ) ) ; this . locale = i18n . getLocale ( ) ; } contextMenuBuilder . showPopupMenu ( info ) ; } ; webContents . on ( 'context-menu' , contextMenuListener ) ; webContents . once ( 'destroyed' , ( ) => { webContents . removeListener ( 'context-menu' , contextMenuListener ) ; } ) ; } param text public isMisspelled ( text ) { if ( ! this . spellCheckHandler ) { return false ; } return this . spellCheckHandler . isMisspelled ( text ) ; } return { Object } private getStringTable ( ) { const namespace = 'ContextMenu' ; return { copyMail : ( ) => i18n . t ( 'Copy Email Address' , namespace ) ( ) , copyLinkUrl : ( ) => i18n . t ( 'Copy Link' , namespace ) ( ) , openLinkUrl : ( ) => i18n . t ( 'Open Link' , namespace ) ( ) , copyImageUrl : ( ) => i18n . t ( 'Copy Image URL' , namespace ) ( ) , copyImage : ( ) => i18n . t ( 'Copy Image' , namespace ) ( ) , addToDictionary : ( ) => i18n . t ( 'Add to Dictionary' , namespace ) ( ) , lookUpDefinition : ( lookup ) => { const formattedString = i18n . t ( 'Look Up {searchText}' , namespace ) ( { searchText : lookup . word } ) ; return formattedString || `Look Up ${ lookup . word }` ; } , searchGoogle : ( ) => i18n . t ( 'Search with Google' , namespace ) ( ) , cut : ( ) => i18n . t ( 'Cut' ) ( ) , copy : ( ) => i18n . t ( 'Copy' ) ( ) , paste : ( ) => i18n . t ( 'Paste' ) ( ) , inspectElement : ( ) => i18n . t ( 'Inspect Element' , namespace ) ( ) , } ; } param menu returns private processMenu ( menu ) { let isLink = false ; menu . items . map ( ( item ) => { if ( item . label === 'Copy Link' ) { isLink = true ; } return item ; } ) ; if ( ! isLink ) { menu . append ( new MenuItem ( { type : 'separator' } ) ) ; menu . append ( new MenuItem ( { accelerator : 'CmdOrCtrl+R' , label : i18n . t ( 'Reload' ) ( ) , click : ( _menuItem , browserWindow , _event ) => { reloadWindow ( browserWindow as ICustomBrowserWindow ) ; } , } ) ) ; } return menu ; } }