Index: gc_lang/fr/build.py ================================================================== --- gc_lang/fr/build.py +++ gc_lang/fr/build.py @@ -6,14 +6,15 @@ from distutils import dir_util, file_util import helpers -def build (sLang, dVars, spLangPack): +def build (sLang, dVars): "complementary build launched from make.py" createWebExtension(sLang, dVars) - createThunderbirdExtension(sLang, dVars, spLangPack) + createThunderbirdExtension(sLang, dVars) + createMailExtension(sLang, dVars) createNodeJSPackage(sLang) def createWebExtension (sLang, dVars): "create Web-extension" @@ -38,27 +39,40 @@ sHTML += f'

\n' sHTML += '\n' return sHTML -def createThunderbirdExtension (sLang, dVars, spLangPack): - "create extension for Thunderbird" +def createMailExtension (sLang, dVars): + "create extension for Thunderbird (as MailExtension)" + print("Building extension for Thunderbird (MailExtension)") + spfZip = "_build/" + dVars['tb_identifier'] + "-v" + dVars['version'] + '.mailext.xpi' + hZip = zipfile.ZipFile(spfZip, mode='w', compression=zipfile.ZIP_DEFLATED) + _copyGrammalecteJSPackageInZipFile(hZip, sLang) + for spf in ["LICENSE.txt", "LICENSE.fr.txt"]: + hZip.write(spf) + dVars = _createOptionsForThunderbird(dVars) + helpers.addFolderToZipAndFileFile(hZip, "gc_lang/"+sLang+"/mailext", "", dVars, True) + hZip.close() + spExtension = dVars['win_tb_debug_extension_path'] if platform.system() == "Windows" else dVars['linux_tb_debug_extension_path'] + file_util.copy_file(spfZip, spExtension + "/" + dVars['tb_identifier']+ ".xpi") # Filename for TB is just + spExtension = dVars['win_tb_beta_extension_path'] if platform.system() == "Windows" else dVars['linux_tb_beta_extension_path'] + file_util.copy_file(spfZip, spExtension + "/" + dVars['tb_identifier']+ ".xpi") # Filename for TB is just + + +def createThunderbirdExtension (sLang, dVars): + "create extension for Thunderbird (as XUL addon)" print("Building extension for Thunderbird") - sExtensionName = dVars['tb_identifier'] + "-v" + dVars['version'] + '.xpi' - spfZip = "_build/" + sExtensionName + spfZip = "_build/" + dVars['tb_identifier'] + "-v" + dVars['version'] + '.xpi' hZip = zipfile.ZipFile(spfZip, mode='w', compression=zipfile.ZIP_DEFLATED) - _copyGrammalecteJSPackageInZipFile(hZip, spLangPack) + _copyGrammalecteJSPackageInZipFile(hZip, sLang) for spf in ["LICENSE.txt", "LICENSE.fr.txt"]: hZip.write(spf) dVars = _createOptionsForThunderbird(dVars) helpers.addFolderToZipAndFileFile(hZip, "gc_lang/"+sLang+"/tb", "", dVars, True) hZip.close() - spDebugProfile = dVars['win_tb_debug_extension_path'] if platform.system() == "Windows" else dVars['linux_tb_debug_extension_path'] - helpers.unzip(spfZip, spDebugProfile) - spfBetaExtension = dVars['win_tb_beta_extension_filepath'] if platform.system() == "Windows" else dVars['linux_tb_beta_extension_filepath'] - #helpers.unzip(spfZip, spBetaProfile) - file_util.copy_file(spfZip, spfBetaExtension) + #spDebugProfile = dVars['win_tb_debug_extension_path'] if platform.system() == "Windows" else dVars['linux_tb_debug_extension_path'] + #helpers.unzip(spfZip, spDebugProfile) def _createOptionsForThunderbird (dVars): dVars['sXULTabs'] = "" dVars['sXULTabPanels'] = "" @@ -74,24 +88,24 @@ for sLang in dVars['dOptLabel'].keys(): dVars['gc_options_labels_'+sLang] = "\n".join( [ "' for sOpt in dVars['dOptLabel'][sLang] ] ) return dVars -def _copyGrammalecteJSPackageInZipFile (hZip, spLangPack, sAddPath=""): +def _copyGrammalecteJSPackageInZipFile (hZip, sLang, sAddPath=""): for sf in os.listdir("grammalecte-js"): if not os.path.isdir("grammalecte-js/"+sf): - hZip.write("grammalecte-js/"+sf, sAddPath+"grammalecte-js/"+sf) + hZip.write("grammalecte-js/"+sf, sAddPath+"grammalecte/"+sf) for sf in os.listdir("grammalecte-js/graphspell"): if not os.path.isdir("grammalecte-js/graphspell/"+sf): - hZip.write("grammalecte-js/graphspell/"+sf, sAddPath+"grammalecte-js/graphspell/"+sf) + hZip.write("grammalecte-js/graphspell/"+sf, sAddPath+"grammalecte/graphspell/"+sf) for sf in os.listdir("grammalecte-js/graphspell/_dictionaries"): if not os.path.isdir("grammalecte-js/graphspell/_dictionaries/"+sf): - hZip.write("grammalecte-js/graphspell/_dictionaries/"+sf, sAddPath+"grammalecte-js/graphspell/_dictionaries/"+sf) - for sf in os.listdir(spLangPack): - if not os.path.isdir(spLangPack+"/"+sf): - hZip.write(spLangPack+"/"+sf, sAddPath+spLangPack+"/"+sf) + hZip.write("grammalecte-js/graphspell/_dictionaries/"+sf, sAddPath+"grammalecte/graphspell/_dictionaries/"+sf) + for sf in os.listdir("grammalecte-js/"+sLang): + if not os.path.isdir("grammalecte-js/"+sLang+"/"+sf): + hZip.write("grammalecte-js/"+sLang+"/"+sf, sAddPath+"grammalecte/"+sLang+"/"+sf) def createNodeJSPackage (sLang): helpers.createCleanFolder("_build/nodejs/"+sLang) dir_util.copy_tree("gc_lang/"+sLang+"/nodejs/", "_build/nodejs/"+sLang) dir_util.copy_tree("grammalecte-js", "_build/nodejs/"+sLang+"/core/grammalecte") Index: gc_lang/fr/config.ini ================================================================== --- gc_lang/fr/config.ini +++ gc_lang/fr/config.ini @@ -8,11 +8,11 @@ # always use 3 numbers for version: x.y.z version = 1.3.2 author = Olivier R. provider = Grammalecte.net link = https://grammalecte.net -description = Correcteur grammatical pour le français. +description = Correcteur grammatical, orthographique et typographique pour le français. extras = README_fr.txt logo = logo.png # main dictionary lexicon_src = lexicons/French.lex @@ -54,18 +54,17 @@ # Thunderbird tb_identifier = French-GC-TB@grammalecte.net tb_name = Grammalecte [fr] win_tb_path = C:\Program Files (x86)\Mozilla Thunderbird\thunderbird.exe -#win_tb_beta_path = C:\Program Files (x86)\Mozilla Thunderbird (Beta)\thunderbird.exe -win_tb_beta_path = C:\Program Files (x86)\Mozilla Thunderbird (Beta)\thunderbird.exe +win_tb_beta_path = C:\Program Files\Thunderbird Daily\thunderbird.exe linux_tb_path = /usr/bin/thunderbird linux_tb_beta_path = /usr/bin/thunderbird -win_tb_debug_extension_path = D:\_temp\tb-debug.profile\extensions\French-GC-TB@grammalecte.net -linux_tb_debug_extension_path = ~/tb-debug.profile/extensions/French-GC-TB@grammalecte.net -win_tb_beta_extension_filepath = D:\_temp\tb-beta.profile\extensions\French-GC-TB@grammalecte.net.xpi -linux_tb_beta_extension_filepath = ~/tb-beta.profile/extensions/French-GC-TB@grammalecte.net.xpi +win_tb_debug_extension_path = D:\_temp\tb-debug.profile\extensions +linux_tb_debug_extension_path = ~/tb-debug.profile/extensions +win_tb_beta_extension_path = D:\_temp\tb-beta.profile\extensions +linux_tb_beta_extension_path = ~/tb-beta.profile/extensions # Set Thunderbird folder in your PATH variable # Create a local profile: # thunderbird -CreateProfile "debug _build\tb-debug.profile" # Or you can use the GUI with: # thunderbird -P ADDED gc_lang/fr/mailext/README.txt Index: gc_lang/fr/mailext/README.txt ================================================================== --- /dev/null +++ gc_lang/fr/mailext/README.txt @@ -0,0 +1,14 @@ + += GRAMMALECTE = + +French grammar checker +By Olivier R. (olivier /at/ grammalecte /dot/ net) + +Website: https://grammalecte.net/ + +License: GPL 3 -- http://www.gnu.org/copyleft/gpl.html + +Grammalecte for Firefox is a derivative tool born from the version +for LibreOffice written in Python. + +Written in JavaScript ES6/ES7. ADDED gc_lang/fr/mailext/background.js Index: gc_lang/fr/mailext/background.js ================================================================== --- /dev/null +++ gc_lang/fr/mailext/background.js @@ -0,0 +1,202 @@ +// Background + +"use strict"; + +// Draft for later + +const oWorkerHandler = { + xGCEWorker: null, + + nLastTimeWorkerResponse: 0, // milliseconds since 1970-01-01 + + oTask: {}, + + start: function () { + this.xGCEWorker = new Worker("gce_worker.js"); + this.xGCEWorker.onmessage = function (e) { + // Messages received from the Worker + // https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent + try { + this.nLastTimeWorkerResponse = Date.now(); + let {sActionDone, result, dInfo, bEnd, bError} = e.data; + if (bError) { + console.log(result); + console.log(dInfo); + return; + } + switch (sActionDone) { + case "init": + storeGCOptions(result); + break; + case "parse": + case "parseAndSpellcheck": + case "parseAndSpellcheck1": + case "parseFull": + case "getListOfTokens": + case "getSpellSuggestions": + case "getVerb": + // send result to content script + if (typeof(dInfo.iReturnPort) === "number") { + let xPort = dConnx.get(dInfo.iReturnPort); + xPort.postMessage(e.data); + } else { + console.log("[background] don’t know where to send results"); + console.log(e.data); + } + break; + case "textToTest": + case "fullTests": + // send result to panel + browser.runtime.sendMessage(e.data); + break; + case "getOptions": + case "getDefaultOptions": + case "resetOptions": + // send result to panel + storeGCOptions(result); + browser.runtime.sendMessage(e.data); + break; + case "setOptions": + case "setOption": + storeGCOptions(result); + break; + case "setDictionary": + case "setDictionaryOnOff": + //console.log("[background] " + sActionDone + ": " + result); + break; + default: + console.log("[background] Unknown command: " + sActionDone); + console.log(e.data); + } + } + catch (error) { + showError(error); + console.log(e.data); + } + }; + }, + + getTimeSinceLastResponse: function () { + // result in seconds + return Math.floor((Date.now() - this.nLastTimeWorkerResponse) / 1000); + }, + + restart: function (nDelay=5) { + if (this.getTimeSinceLastResponse() <= nDelay) { + console.log("Worker not restarted. Worked ", nDelay, " seconds ago."); + return false; + } + if (this.xGCEWorker) { + this.xGCEWorker.terminate(); + } + this.start(); + oInitHandler.initGrammarChecker(); + sendCommandToAllTabs("workerRestarted"); + console.log("Worker restarted."); + return true; + }, + + addTask: function () { + // + }, + + closeTask: function () { + // + } +} + + +const oInitHandler = { + + initUIOptions: function () { + browser.storage.local.get("ui_options").then(this._initUIOptions, showError); + browser.storage.local.get("autorefresh_option").then(this._initUIOptions, showError); + }, + + initGrammarChecker: function () { + browser.storage.local.get("gc_options").then(this._initGrammarChecker, showError); + browser.storage.local.get("personal_dictionary").then(this._setSpellingDictionaries, showError); + browser.storage.local.get("community_dictionary").then(this._setSpellingDictionaries, showError); + browser.storage.local.get("sc_options").then(this._initSCOptions, showError); + }, + + _initUIOptions: function (oSavedOptions) { + if (!oSavedOptions.hasOwnProperty("ui_options")) { + browser.storage.local.set({"ui_options": { + textarea: true, + editablenode: true + }}); + } + if (!oSavedOptions.hasOwnProperty("autorefresh_option")) { + browser.storage.local.set({"autorefresh_option": true}); + } + }, + + _initGrammarChecker: function (oSavedOptions) { + try { + let dOptions = (oSavedOptions.hasOwnProperty("gc_options")) ? oSavedOptions.gc_options : null; + if (dOptions !== null && Object.getOwnPropertyNames(dOptions).length == 0) { + console.log("# Error: the saved options was an empty object."); + dOptions = null; + } + oWorkerHandler.xGCEWorker.postMessage({ + sCommand: "init", + dParam: {sExtensionPath: browser.extension.getURL(""), dOptions: dOptions, sContext: "Firefox"}, + dInfo: {} + }); + } + catch (e) { + console.log("initGrammarChecker failed"); + showError(e); + } + }, + + _setSpellingDictionaries: function (oData) { + if (oData.hasOwnProperty("community_dictionary")) { + oWorkerHandler.xGCEWorker.postMessage({ sCommand: "setDictionary", dParam: { sDictionary: "community", oDict: oData["community_dictionary"] }, dInfo: {} }); + } + if (oData.hasOwnProperty("personal_dictionary")) { + oWorkerHandler.xGCEWorker.postMessage({ sCommand: "setDictionary", dParam: { sDictionary: "personal", oDict: oData["personal_dictionary"] }, dInfo: {} }); + } + }, + + _initSCOptions: function (oData) { + if (!oData.hasOwnProperty("sc_options")) { + browser.storage.local.set({"sc_options": { + community: true, + personal: true + }}); + oWorkerHandler.xGCEWorker.postMessage({ sCommand: "setDictionaryOnOff", dParam: { sDictionary: "community", bActivate: true }, dInfo: {} }); + oWorkerHandler.xGCEWorker.postMessage({ sCommand: "setDictionaryOnOff", dParam: { sDictionary: "personal", bActivate: true }, dInfo: {} }); + } else { + oWorkerHandler.xGCEWorker.postMessage({ sCommand: "setDictionaryOnOff", dParam: { sDictionary: "community", bActivate: oData.sc_options["community"] }, dInfo: {} }); + oWorkerHandler.xGCEWorker.postMessage({ sCommand: "setDictionaryOnOff", dParam: { sDictionary: "personal", bActivate: oData.sc_options["personal"] }, dInfo: {} }); + } + } +} + +// start the Worker for the GC +oWorkerHandler.start(); + +// init the options stuff and start the GC +oInitHandler.initUIOptions(); +oInitHandler.initGrammarChecker(); + + + +/* + Actions +*/ + +function storeGCOptions (dOptions) { + if (dOptions instanceof Map) { + dOptions = helpers.mapToObject(dOptions); + } + browser.storage.local.set({"gc_options": dOptions}); +} + + +function showError (e) { + console.error(e); + //console.error(e.fileName + "\n" + e.name + "\nline: " + e.lineNumber + "\n" + e.message); +} ADDED gc_lang/fr/mailext/chrome.manifest Index: gc_lang/fr/mailext/chrome.manifest ================================================================== --- /dev/null +++ gc_lang/fr/mailext/chrome.manifest @@ -0,0 +1,9 @@ +# https://developer.mozilla.org/en-US/docs/Chrome_Registration +content grammarchecker content/ +content promiseworker ./worker/ +resource grammalecte ./grammalecte/ +locale grammarchecker fr locale/fr/ +locale grammarchecker en locale/en/ +skin grammarchecker classic/1.0 skin/ +overlay chrome://messenger/content/messengercompose/messengercompose.xul chrome://grammarchecker/content/overlay.xul +style chrome://messenger/content/customizeToolbar.xul chrome://grammarchecker/content/overlay.css ADDED gc_lang/fr/mailext/content/about.css Index: gc_lang/fr/mailext/content/about.css ================================================================== --- /dev/null +++ gc_lang/fr/mailext/content/about.css @@ -0,0 +1,46 @@ +/* CSS */ + +.descr { + font-size: 18px; + font-weight: bold; + text-align: center; +} + +.stdlabel { + font-size: 16px; + text-align: center; +} + +#website { + font-size: 16px; + font-weight: bold; + color: hsl(210, 50%, 50%); + text-align: center; + cursor: pointer; +} + +#contrib { + font-size: 16px; + text-align: center; + color: hsl(210, 50%, 50%); + cursor: pointer; +} + + +/* + TB Next: fix dialogheaders +*/ +dialogheader { + -moz-binding: url("chrome://messenger/content/generalBindings.xml#dialogheader"); + margin: 0 5px 5px; + border: 1px solid ThreeDDarkShadow; + padding: 5px 8px; + background-color: Highlight; + color: HighlightText; +} + +.dialogheader-title { + margin: 0 !important; + font-size: larger; + font-weight: bold; +} ADDED gc_lang/fr/mailext/content/about.js Index: gc_lang/fr/mailext/content/about.js ================================================================== --- /dev/null +++ gc_lang/fr/mailext/content/about.js @@ -0,0 +1,35 @@ +// JavaScript + +const Cc = Components.classes; +const Ci = Components.interfaces; +//const Cu = Components.utils; + + +function openInBrowserURL (sURL) { + // method found in S3.Google.Translator + try { + openURL(sURL); + // Works in overlay.js, but not here… Seems there is no documentation available about this feature on Mozilla.org + } + catch (e) { + console.error(e); + //Cu.reportError(e); + } +} + +function openInTabURL (sURL) { + // method found in S3.Google.Translator + try { + let xWM = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator); + let xWin = xWM.getMostRecentWindow("mail:3pane"); + let xTabmail = xWin.document.getElementById('tabmail'); + xWin.focus(); + if (xTabmail) { + xTabmail.openTab('contentTab', { contentPage: sURL }); + } + } + catch (e) { + console.error(e); + //Cu.reportError(e); + } +} ADDED gc_lang/fr/mailext/content/about.xul Index: gc_lang/fr/mailext/content/about.xul ================================================================== --- /dev/null +++ gc_lang/fr/mailext/content/about.xul @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + +