Grammalecte  Check-in [5c14b1c9e0]

Overview
Comment:merge trunk
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | gcerw
Files: files | file ages | folders
SHA3-256: 5c14b1c9e029f509832e2639c2e2a833568f641afd7c784527e01166fdbd5e6d
User & Date: olr on 2020-04-08 14:07:34
Other Links: branch diff | manifest | tags
Context
2020-04-08
15:00
[graphspell][py] rename lexicographer file check-in: 635140d716 user: olr tags: gcerw, graphspell
14:07
merge trunk check-in: 5c14b1c9e0 user: olr tags: gcerw
13:50
[fx] text area button: don’t show it for editable node that aren’t <p> or <div> check-in: dc0a47993e user: olr tags: fx, trunk
2020-04-06
20:43
[tb][js] update gce_worker check-in: 9fd78a9ee5 user: olr tags: gcerw, tb
Changes

Modified doc/API_web.md from [db743ee983] to [7922180e3c].

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
..
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
...
118
119
120
121
122
123
124
125
126

127
128
129
130
131
132
133
### Open the Grammalecte panel for a node

If you have disabled the spinning button, you can launch the Grammalecte panel with your custom button.

    oGrammalecteAPI.openPanelForNode("node_id")
    oGrammalecteAPI.openPanelForNode(node)

The node can be a textarea, an editable node or an iframe.
If the node is an iframe, the content won’t be modified by Grammalecte.


### Prevent Grammalecte to modify the node content

If you don’t want Grammalecte to modify directly the node content, add the property: `data-grammalecte_result_via_event="true"`.

With this property, Grammalecte will send an event to the node each times the text is modified within the panel.
................................................................................

### Open the Grammalecte panel for any text

    oGrammalecteAPI.openPanelForText("your text")
    oGrammalecteAPI.openPanelForText("your text", "node_id")
    oGrammalecteAPI.openPanelForText("your text", node)

With the second parameter, Grammalecte will send an event to the node each times the text is modified within the panel.


### Parse a node and get errors

    oGrammalecteAPI.parseNode("node_id")
    oGrammalecteAPI.parseNode(node)

The node can be a textarea, an editable node or an iframe. The node must have an identifier.
Results (for each paragraph) will be sent in a succession of events at the node.

    node.addEventListener("GrammalecteResult", function (event) {
        const detail = (typeof(event.detail) === 'string') && JSON.parse(event.detail);
        if (detail.sType  &&  detail.sType == "proofreading") {
            let oResult = detail.oResult; // null when the text parsing is finished
            ...
................................................................................


### Parse text and get errors

    oGrammalecteAPI.parseText("your text", "node_id")
    oGrammalecteAPI.parseText("your text", node)

The node must have an identifier.
Like with `oGrammalecteAPI.parseNode()`, results (for each paragraph) will be sent in a succession of events at the node.




### Get spelling suggestions

    oGrammalecteAPI.getSpellingSuggestions(word, destination)
    oGrammalecteAPI.getSpellingSuggestions(word, destination, request_identifier)







|
|







 







|







|







 







<

>







65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
..
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
...
118
119
120
121
122
123
124

125
126
127
128
129
130
131
132
133
### Open the Grammalecte panel for a node

If you have disabled the spinning button, you can launch the Grammalecte panel with your custom button.

    oGrammalecteAPI.openPanelForNode("node_id")
    oGrammalecteAPI.openPanelForNode(node)

The node can be a textarea, an editable node or an iframe. **The node must have an identifier**.
If the node is an iframe, the content won’t be modified by Grammalecte, but events with results may be received (see below).


### Prevent Grammalecte to modify the node content

If you don’t want Grammalecte to modify directly the node content, add the property: `data-grammalecte_result_via_event="true"`.

With this property, Grammalecte will send an event to the node each times the text is modified within the panel.
................................................................................

### Open the Grammalecte panel for any text

    oGrammalecteAPI.openPanelForText("your text")
    oGrammalecteAPI.openPanelForText("your text", "node_id")
    oGrammalecteAPI.openPanelForText("your text", node)

With the second parameter, Grammalecte will send an event to the node each times the text is modified within the panel. **The node must have an identifier**.


### Parse a node and get errors

    oGrammalecteAPI.parseNode("node_id")
    oGrammalecteAPI.parseNode(node)

The node can be a textarea, an editable node or an iframe. **The node must have an identifier**.
Results (for each paragraph) will be sent in a succession of events at the node.

    node.addEventListener("GrammalecteResult", function (event) {
        const detail = (typeof(event.detail) === 'string') && JSON.parse(event.detail);
        if (detail.sType  &&  detail.sType == "proofreading") {
            let oResult = detail.oResult; // null when the text parsing is finished
            ...
................................................................................


### Parse text and get errors

    oGrammalecteAPI.parseText("your text", "node_id")
    oGrammalecteAPI.parseText("your text", node)


Like with `oGrammalecteAPI.parseNode()`, results (for each paragraph) will be sent in a succession of events at the node.
**The node must have an identifier**.



### Get spelling suggestions

    oGrammalecteAPI.getSpellingSuggestions(word, destination)
    oGrammalecteAPI.getSpellingSuggestions(word, destination, request_identifier)

Modified gc_lang/fr/build.py from [5f4b392f44] to [43a9cad18e].

1
2
3
4
5



6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30


















31
32
33
34
35
36
37
..
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# Builder for French language

import os
import platform
import zipfile



from distutils import dir_util, file_util

import helpers


def build (sLang, dVars):
    "complementary build launched from make.py"
    createWebExtension(sLang, dVars)

    createMailExtension(sLang, dVars)
    createNodeJSPackage(sLang)


def createWebExtension (sLang, dVars):
    "create Web-extension"
    print("Building WebExtension")
    helpers.createCleanFolder("_build/webext/"+sLang)
    dir_util.copy_tree("gc_lang/"+sLang+"/webext/", "_build/webext/"+sLang)
    dir_util.copy_tree("grammalecte-js", "_build/webext/"+sLang+"/grammalecte")
    dVars['webextOptionsHTML'] = _createOptionsForWebExtension(dVars)
    helpers.copyAndFileTemplate("_build/webext/"+sLang+"/manifest.json", "_build/webext/"+sLang+"/manifest.json", dVars)
    helpers.copyAndFileTemplate("_build/webext/"+sLang+"/panel/main.html", "_build/webext/"+sLang+"/panel/main.html", dVars)
    with helpers.CD("_build/webext/"+sLang):
        os.system("web-ext build")
    # Copy Firefox zip extension to _build
    helpers.moveFolderContent("_build/webext/"+sLang+"/web-ext-artifacts", "_build", "fx-"+sLang+"-", True)




















def _createOptionsForWebExtension (dVars):
    sHTML = ""
    sLang = dVars['sDefaultUILang']
    for sSection, lOpt in dVars['lStructOpt']:
        sHTML += f'\n<div id="subsection_{sSection}" class="opt_subsection">\n  <h2 data-l10n-id="option_{sSection}">{dVars["dOptLabel"][sLang][sSection][0]}</h2>\n'
................................................................................
                sHTML += f'  <p><input type="checkbox" id="option_{sOpt}" class="gc_option" data-option="{sOpt}"/><label id="option_label_{sOpt}" for="option_{sOpt}" data-l10n-id="option_{sOpt}">{dVars["dOptLabel"][sLang][sOpt][0]}</label></p>\n'
        sHTML += '</div>\n'
    return sHTML


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)





>
>
>








>






|









|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
..
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# Builder for French language

import os
import platform
import zipfile
import shutil
import json
import traceback
from distutils import dir_util, file_util

import helpers


def build (sLang, dVars):
    "complementary build launched from make.py"
    createWebExtension(sLang, dVars)
    convertWebExtensionForChrome(sLang, dVars)
    createMailExtension(sLang, dVars)
    createNodeJSPackage(sLang)


def createWebExtension (sLang, dVars):
    "create Web-extension"
    print("> Building WebExtension for Firefox")
    helpers.createCleanFolder("_build/webext/"+sLang)
    dir_util.copy_tree("gc_lang/"+sLang+"/webext/", "_build/webext/"+sLang)
    dir_util.copy_tree("grammalecte-js", "_build/webext/"+sLang+"/grammalecte")
    dVars['webextOptionsHTML'] = _createOptionsForWebExtension(dVars)
    helpers.copyAndFileTemplate("_build/webext/"+sLang+"/manifest.json", "_build/webext/"+sLang+"/manifest.json", dVars)
    helpers.copyAndFileTemplate("_build/webext/"+sLang+"/panel/main.html", "_build/webext/"+sLang+"/panel/main.html", dVars)
    with helpers.CD("_build/webext/"+sLang):
        os.system("web-ext build")
    # Copy Firefox zip extension to _build
    helpers.moveFolderContent("_build/webext/"+sLang+"/web-ext-artifacts", "_build", "firefox-", True)


def convertWebExtensionForChrome (sLang, dVars):
    "Create the extension for Chrome"
    print("> Converting WebExtension for Chrome")
    try:
        with open(f"_build/webext/{sLang}/manifest.json", "r", encoding="utf-8") as hSrc:
            dManifest = json.load(hSrc)
            if "applications" in dManifest:
                del dManifest["applications"]
            if "chrome_settings_overrides" in dManifest:
                del dManifest["chrome_settings_overrides"]
        with open(f"_build/webext/{sLang}/manifest.json", "w", encoding="utf-8") as hDst:
            json.dump(dManifest, hDst, ensure_ascii=True, indent=2)
        shutil.make_archive(f"_build/chrome-grammalecte-{sLang}-v{dVars['version']}", 'zip', "_build/webext/"+sLang)
    except:
        traceback.print_exc()
        print("  Error. Converting the WebExtension for Chrome failed.")


def _createOptionsForWebExtension (dVars):
    sHTML = ""
    sLang = dVars['sDefaultUILang']
    for sSection, lOpt in dVars['lStructOpt']:
        sHTML += f'\n<div id="subsection_{sSection}" class="opt_subsection">\n  <h2 data-l10n-id="option_{sSection}">{dVars["dOptLabel"][sLang][sSection][0]}</h2>\n'
................................................................................
                sHTML += f'  <p><input type="checkbox" id="option_{sOpt}" class="gc_option" data-option="{sOpt}"/><label id="option_label_{sOpt}" for="option_{sOpt}" data-l10n-id="option_{sOpt}">{dVars["dOptLabel"][sLang][sOpt][0]}</label></p>\n'
        sHTML += '</div>\n'
    return sHTML


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)

Modified gc_lang/fr/rules.grx from [21c94a6458] to [6a36715a8b].

1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502






1503
1504
1505
1506
1507
1508
1509
....
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
....
4179
4180
4181
4182
4183
4184
4185












4186
4187
4188
4189
4190
4191
4192
....
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
....
4326
4327
4328
4329
4330
4331
4332




4333
4334
4335
4336
4337
4338
4339
....
7464
7465
7466
7467
7468
7469
7470
7471
7472
7473
7474
7475
7476
7477
7478
....
8009
8010
8011
8012
8013
8014
8015
8016
8017
8018
8019
8020
8021
8022
8023
8024
8025
8026
.....
11564
11565
11566
11567
11568
11569
11570
11571
11572
11573
11574
11575
11576
11577
11578
11579
11580
11581
11582
11583
11584
11585
11586
11587
11588
11589
11590
11591
11592
11593
11594
11595
11596
11597
11598
11599
.....
13455
13456
13457
13458
13459
13460
13461

13462
13463
13464
13465
13466
13467
13468
.....
13703
13704
13705
13706
13707
13708
13709

13710
13711
13712
13713
13714
13715
13716
.....
18887
18888
18889
18890
18891
18892
18893
18894
18895
18896
18897
18898
18899
18900



18901
18902
18903
18904
18905
18906
18907
.....
18908
18909
18910
18911
18912
18913
18914

18915
18916
18917

18918
18919
18920
18921
18922
18923
18924
.....
19234
19235
19236
19237
19238
19239
19240


















19241
19242
19243
19244
19245
19246
19247
.....
19307
19308
19309
19310
19311
19312
19313















19314
19315
19316
19317
19318
19319
19320
19321


19322
19323
19324
19325
19326
19327
19328
.....
23065
23066
23067
23068
23069
23070
23071

23072
23073
23074
23075
23076
23077

23078
23079
23080
23081
23082
23083
23084
23085
.....
23095
23096
23097
23098
23099
23100
23101

23102
23103
23104
23105
23106
23107
23108


## Caractères rares
__<s>/ocr(ocr_caractères_rares)__
    \w*[{}<>&*#£^|]+\w*
        <<- \0 != "<" and \0 != ">" ->> _                                                           # Erreur de numérisation ? Cette chaîne contient un caractère de fréquence rare.

__<s>/ocr(ocr_doublons_caractères_rares)__
    [\]\[({}][\]\[({}]+
        <<- ->> _                                                                                   # Erreur de numérisation ? Succession douteuse de caractères.

TEST: __ocr__ trouve {{l£}} temps
TEST: __ocr__ elle s’{{avance*}} sur le seuil
TEST: __ocr__ {{e||e}} vient
TEST: __ocr__ par beaucoup d’argent ? {{{Il}} débouche le Jack Daniels






TEST: __ocr__ {{[[}}voyons celà].
TEST: __ocr__ {{((}}voyons ceci).


## Mélange chiffres/lettres
__[i]/ocr(ocr_le_la_les_regex)__
    [1[\]][easrnxiocuwàéè]
................................................................................
    >arrière >petit >neveu
        <<- /tu/ ->> arrière-petit-neveu|arrière-petits-neveux      # Mettez des traits d’union.

    >arrière >petit >nièce
        <<- /tu/ ->> arrière-petite-nièce|arrière-petites-nièces    # Mettez des traits d’union.

    [basket|volley] ball
        <<- /tu/ ->> \1-ball                                    # Il manque un trait d’union.

    bas [>côté|coté|cotés]
        <<- /tu/ morph(<1 , ":D") ->> bas-côté|bas-côtés        # Il manque un trait d’union.

    [les|des|aux] beaux arts
        <<- /tu/ -2:3>> beaux-arts                              # Il manque un trait d’union.

................................................................................

    >centre >ville
        <<- /tu/ ->> centre-ville|centres-villes                # Il manque un trait d’union.

    [chassé+ses] [croisé+ses]
        <<- /tu/ ->> chassé-croisé|chassés-croisés              # Il manque un trait d’union.













    >chef lieu
        <<- /tu/ ->> \1-\2                                      # Il manque un trait d’union.

    >chef d’ œuvre
        <<- /tu/ ->> \1-\2\3                                    # Il manque un trait d’union.

    [auto|moto] >club
................................................................................

    face [a|à] face
        <<- /tu/ morph(<1, ":D") ->> face-à-face                # Si vous employez cette locution comme un nom, mettez des traits d’union.|https://fr.wiktionary.org/wiki/face-%C3%A0-face

    gagne >pain
        <<- /tu/ not morph(<1, ":O[sv]") ->> gagne-pain         # Il manque un trait d’union.

    [grand|grands] [>père|>mère]
        <<- /tu/ ->> \1-\2                                      # Il manque un trait d’union.

    lèse majesté
        <<- /tu/ ->> \1-\2                                      # Il manque un trait d’union.

    n [ième+s|ieme+s|ème+s|eme+s]
        <<- /tu/ ->> n-ième|n-ièmes                             # Il manque un trait d’union.
................................................................................
TEST: sur le {{bas côté}}
TEST: les {{beaux arts}}
TEST: {{le}} {{bouche à oreille}}
TEST: {{chef lieu}} de ce canton
TEST: un {{chassé croisé}}
TEST: ne vois-tu pas que c’est un {{chef d’œuvre}} ?
TEST: ils sont allés au {{centre ville}}.




TEST: Le {{moto club}} était sur le point de faire faillite.
TEST: J’ai beaucoup de {{déjà vu}}.
TEST: L’{{état major}} n’a pas encore tranché la question.
TEST: Le {{face à face}} entre les forces de l’ordre et les manifestants se poursuit devant l’hôtel de ville à Bordeaux depuis environ 1h30.
TEST: {{gagne pain}} de merde
TEST: mes deux {{grands pères}} sont décédés
TEST: un crime de {{lèse majesté}}
................................................................................
    les ([elle+s]) [de|des|du|d’]
    [sous|sur] leurs ([elle+s]) [<end>|,|$:R]
        <<- /conf/ -1>> ailes
        # Confusion probable : “elle” est un pronom personnel féminin. Pour les oiseaux, les avions ou les parties d’un bâtiment ou d’une armée, écrivez “aile”.|https://fr.wiktionary.org/wiki/aile

    [elle+s] ?[droite|gauche]¿ du [château|palais|bâtiment|manoir]
    [elle+s] ?[droite|gauche]¿ [de|d’] la [maison|ferme]
        <<- /conf/ -1>> aile|ailes
        # Confusion probable : “elle” est un pronom personnel féminin. Pour les oiseaux, les avions ou les parties d’un bâtiment ou d’une armée, écrivez “aile”.|https://fr.wiktionary.org/wiki/aile

TEST: l’{{elle}} est en feu.
TEST: sous l’{{elle}} de sa mère, il ne craint rien
TEST: sur son {{elle}} droite
TEST: des {{elles}} enduites de pétrole
TEST: De l’autre côté du mur, dans l’{{elle}} réservée aux femmes, il y a des jeunes filles dont nul n’a parlé
................................................................................

TEST: ce sont des durs à {{cuir}}
TEST: Quelle dure {{a}} {{cuir}}, celle-là.


# dans / d’en
__conf_dans_dan_d_en__
    d’ en [le|la|l’|les|de|d’|des|du|un|une|mon|ton|son|ma|ta|sa|mes|tes|ses|notre|votre|nos|vos|leurs|ce|cet|cette|ces]
        <<- /conf/ not (\3 == "ce" and value(>1, "|moment|")) -1:2>> dans           # Confusion. Utilisez “dans” pour dire “à l’intérieur de quelque chose”.

    <start>  [>dent|dan]  [le|la|l’|les|un|une|mon|ton|son|ma|ta|sa|mes|tes|ses|notre|votre|nos|vos|leurs|ce|cet|cette|ces]
        <<- /conf/ -2>> dans                                                        # Confusion. Utilisez “dans” pour dire “à l’intérieur de quelque chose”.

TEST: {{dan}} la voiture
TEST: ils sont partis {{d’en}} une direction différente
TEST: {{dents}} les montagnes au loin.
TEST: Dents de la mer.
TEST: Un pauvre, ça doit consommer, bosser, et bien fermer sa gueule. Tout l’inverse d’en ce moment.
................................................................................
    mois        [après|par]     mois
    décennie    [après|par]     décennie
    année       [après|par]     année
    siècle      [après|par]     siècle
    génération  [après|par]     génération
        <<- ~>> *

    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿   [du|ce]  [matin|soir]
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿   de  l’ après-midi
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿   cet  après-midi
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿   [demain|hier]  ?[matin|soir|après-midi]¿
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿   [du|ce]  [matin|soir]
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿   de  l’ après-midi
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿   cet  après-midi
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿   [demain|hier]  ?[matin|soir|après-midi]¿
        <<- ~>> *

    [à|de]      *HOUR
    [à|de]      *HOUR  [du|ce]  [matin|soir]
    [à|de]      *HOUR  de  l’ après-midi
    [à|de]      *HOUR  cet  après-midi
    [à|de]      *HOUR  [demain|hier]  ?[matin|soir|après-midi]¿
    jusqu’ à    *HOUR
    jusqu’ à    *HOUR  [du|ce]  [matin|soir]
    jusqu’ à    *HOUR  de  l’ après-midi
    jusqu’ à    *HOUR  cet  après-midi
    jusqu’ à    *HOUR  [demain|hier]  ?[matin|soir|après-midi]¿
        <<- ~>> *

TEST: Le train de 2 h 47 {{arriveraient}} en retard.
TEST: Le train de 2 h 47 du matin {{arriveraient}} en retard.
TEST: Le train de 2h47 du matin {{arriveraient}} en retard.


................................................................................
    >chasseur [de|d’] primes
    >chemin [de|d’] [traverse|fer]
    >chemise [de|d’] nuit
    >chemise sans >manche
    >chèque sans provision
    >chili con carne
    >chou à la crème ?[fouettée|diplomate|mousseline|patissière|pralinée]¿

    >clair comme [de|d’] l’ eau [de|d’] [boudin|roche|source]
    >clair comme du cristal
    >clair comme jus [de|d’] [boudin|>chaussette|chique]
    >classement sans suite
    [>clé|>clef] à molette
    >clin d’ œil
    >clause [de|d’] [confidentialité|non-concurrence]
................................................................................
    [réglé+ses] comme du papier à musique
    >règlement [de|d’] comptes
    [remis+es] à plat
    >requête en nullité
    >requête en non [conciliation|inscription|lieu]
    >requête en non révocation [de|d’] sursis
    >responsable qualité

    >retour à la case départ
    >rivière à sec
    >robe [de|d’] [chambre|soirée]
    >robe du soir
    >robe sans >manche
    >roman à l’ eau [de|d’] rose
    >roue [avant|arrière]
................................................................................
__conf_pâte_patte_pat__
    [>patte|pat] [>alimentaire|>alsacien|>chinois|>feuilleté|>italien|>thermique]
    [>patte|pat] au [basilic|beurre|saumon|pesto|poulet|thon]
    [>patte|pat] [à|a] [>pain|>crêpe|>gaufre|>pizza|>tarte|>modeler|>tartiner]
    [>patte|pat] [d’|de] [>amande|>amende|>fruit]
        <<- /conf/ -1>> pâte|pâtes                              # Confusion. La patte est le membre d’un animal (ou d’une table…). La matière pâteuse s’écrit “pâte”.

    >mettre ?[pas|jamais]¿ la main à la [>patte|pat]
    >coq en [>patte|pat]
        <<- /conf/ --1>> pâte                                   # Confusion. La patte est le membre d’un animal (ou d’une table…). La matière pâteuse s’écrit “pâte”.

    >coup de [>pâte|pat]
        <<- /conf/ -3>> patte                                   # Confusion. Une pâte est une matière pâteuse. Pour désigner le membre d’un animal, écrivez “patte”.




    >retomber sur [mes|tes|ses|ces|nos|vos|leur|leurs] [>pâte|pat]
        <<- /conf/ --1>> pattes                                 # Confusion. Une pâte est une matière pâteuse. Pour désigner le membre d’un animal, écrivez “patte”.

    >court sur [>pâte|pat]
        <<- /conf/ --1>> pattes                                 # Confusion. Une pâte est une matière pâteuse. Pour désigner le membre d’un animal, écrivez “patte”.

TEST: Prépare la {{patte}} à tarte.
................................................................................
TEST: Ils mangent souvent des {{pattes}} au thon.
TEST: Des {{pattes}} alimentaires.
TEST: Elles ont acheté de la {{patte}} à tartiner.
TEST: La {{patte}} à pizza est plus épaisse que la pâte à crêpes.
TEST: Elle adore la {{patte}} d’amande.
TEST: Il est comme un coq en {{pattes}} là.
TEST: Elle n’a jamais mis la main à la {{patte}}.

TEST: donne-moi un coup de {{pâte}}
TEST: elle retombe toujours sur ses {{pâtes}}.
TEST: il est court sur {{pâtes}}



# péché / pêcher
__conf_péché_pêcher2__
    >pêcher par excès [de|d’]
    >pêcher par [insuffisance|omission|orgueil]
        <<- /conf/ -1>> pécher                                  # Confusion : pêcher (capturer des poissons) ≠ pécher (faire un écart de conduite).|https://fr.wiktionary.org/wiki/p%C3%A9cher
................................................................................

    [>être|>demeurer|>rester|>devenir]  >septique
        <<- /conf/ not morph(<1, ">plaie/") -2>> =\2.replace("sep", "scep")     # Confusion possible. Septique = corrompu, infecté. Sceptique = ayant des doutes.

TEST: cette fosse {{sceptique}} est pleine.
TEST: Je suis {{septique}} !




















## soit / soie / soi
__conf_aller_de_soi__
    >aller de [sois|>soie]
        <<- /conf/ -3>> soi                                 # Confusion.|https://fr.wiktionary.org/wiki/aller_de_soi

    >aller ?[pas|jamais|guère]¿ de soit
................................................................................
    >tacher  [de|d’]  ?[le|la|l’|les|en|nous|vous|lui|leur|y]¿  $:Y
    >tacher  [de|d’]  [nous|vous]     [le|la|l’|les|en|y]       $:Y
    >tacher  [de|d’]  [le|la|l’|les]  [lui|leur|en|y]           $:Y
    >tacher  [de|d’]  [lui|leur]      en                        $:Y
        <<- /conf/ -1>> =\1.replace("a", "â").replace("A", "Â")
        # Confusion. Tache signifie faire une salissure, une altération, une marque, une coloration… Pour parler de l’accomplissement d’un travail, écrivez “tâcher”.
















TEST: Quelle {{tache}} ingrate.
TEST: Une {{tache}} valorisante.
TEST: Elle se tue à la {{tache}}.
TEST: Il a accompli la {{tache}} facilement.
TEST: {{Tache}} de partir tôt.
TEST: {{Tachez}} d’arriver à l’heure.
TEST: {{Tache}} de ne pas faire trop de bruit.
TEST: se tuer à la {{tache}}


TEST: une tâche dévalorisante.
TEST: peiner à la tâche.


# taule / tôle
__conf_taule_tôle2__
    [>aller|>finir] en [>tôle|>tole]
................................................................................

    [<start>|,|(] [les|plusieurs|leurs]  @:V¬:[NAY]  [ne|n’|me|m’|te|s’|se|s’]
    [<start>|,|(] [les|plusieurs|leurs]  @:V¬:[NAY]  [le|la|l’|les|leur]  @:[123][sp]¬:[QNAG]
    [<start>|,|(] [les|plusieurs|leurs]  @:V¬:[NAY]  ?[nous|vous]¿        @:[123][sp]¬:[QG]
        <<- /conf/ hasSimil(\3, ":[NA].*:[pi]")
        -3>> =suggSimil(\3, ":[NA].*:[pi]", True)                                   # Confusion probable : “\3” est une forme verbale conjuguée. Si “\2” est un déterminant, il faut placer un nom après.


    [<start>|,|(] certains        @:V¬:[NAY]  [ne|n’|me|m’|te|s’|se|s’]
    [<start>|,|(] certains        @:V¬:[NAY]  [le|la|l’|les|leur]         @:[123][sp]¬:[QNAG]
    [<start>|,|(] certains        @:V¬:[NAY]  ?[nous|vous]¿               @:[123][sp]¬:[QG]
        <<- /conf/ hasSimil(\3, ":[NA].*:[me]:[pi]")
        -3>> =suggSimil(\3, ":[NA].*:[me]:[pi]", True)                              # Confusion probable : “\3” est une forme verbale conjuguée. Si “\2” est un déterminant, il faut placer un nom après.


    [<start>|,|(] certaines       @:V¬:[NAY]  [ne|n’|me|m’|te|s’|se|s’]
    [<start>|,|(] certaines       @:V¬:[NAY]  [le|la|l’|les|leur]         @:[123][sp]¬:[QNAG]
    [<start>|,|(] certaines       @:V¬:[NAY]  ?[nous|vous]¿               @:[123][sp]¬:[QG]
        <<- /conf/ hasSimil(\3, ":[NA].*:[fe]:[pi]")
        -3>> =suggSimil(\3, ":[NA].*:[fe]:[pi]", True)                              # Confusion probable : “\3” est une forme verbale conjuguée. Si “\2” est un déterminant, il faut placer un nom après.

TEST: Un {{défie}} se définit par la difficulté                 ->> défi
TEST: Le {{défit}} ne l’enthousiasmait pas.                     ->> défi
................................................................................
TEST: Les amener n’apportait que des problèmes.
TEST: Le prendre par surprise était difficile.
TEST: La consigner devenait une obligation.
TEST: Les reconnaître semblait nécessaire.
TEST: Son ministre du Budget, Gérald Darmanin, l’avait dit plus crûment sur RTL
TEST: Certains jouent la carte de la dérision
TEST: Certains font grève tous les vendredis pour soutenir cette cause.



__conf_suj_verbe_det_verbe_nom__
    [<start>|,|(]  [je|j’|tu|il|elle|on|nous|vous|ils|elles|iel|iels|ce|c’]   ?[ne|n’]¿   ?[le|la|l’|les|en|me|m’|te|t’|se|s’|nous|vous|lui|leur|y]¿  @:[123][sp]        [le|un]  @:[123][sp]¬:[NA].*:[me]:[si]
    [<start>|,|(]  [je|j’|tu|il|elle|on|nous|vous|ils|elles|iel|iels|ce|c’]   ?[ne|n’]¿   [me|m’|te|t’|se|s’|nous|vous]   [le|la|l’|les|en|y]         @:[123][sp]        [le|un]  @:[123][sp]¬:[NA].*:[me]:[si]
    [<start>|,|(]  [je|j’|tu|il|elle|on|nous|vous|ils|elles|iel|iels|ce|c’]   ?[ne|n’]¿   [le|la|l’|les]                  [lui|leur|en|y]             @:[123][sp]        [le|un]  @:[123][sp]¬:[NA].*:[me]:[si]
    [<start>|,|(]  [je|j’|tu|il|elle|on|nous|vous|ils|elles|iel|iels|ce|c’]   ?[ne|n’]¿   [lui|leur]                      en                          @:[123][sp]        [le|un]  @:[123][sp]¬:[NA].*:[me]:[si]







<
<
<
<




>
>
>
>
>
>







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>







 







|







 







>
>
>
>







 







|







 







|


|







 







|
|
|
|
|
|
|
|
|
|


|
|
|
|
|
|
|
|
|
|







 







>







 







>







 







|






>
>
>







 







>



>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>








>
>







 







>
|





>
|







 







>







1488
1489
1490
1491
1492
1493
1494




1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
....
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
....
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
....
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
....
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
....
7482
7483
7484
7485
7486
7487
7488
7489
7490
7491
7492
7493
7494
7495
7496
....
8027
8028
8029
8030
8031
8032
8033
8034
8035
8036
8037
8038
8039
8040
8041
8042
8043
8044
.....
11582
11583
11584
11585
11586
11587
11588
11589
11590
11591
11592
11593
11594
11595
11596
11597
11598
11599
11600
11601
11602
11603
11604
11605
11606
11607
11608
11609
11610
11611
11612
11613
11614
11615
11616
11617
.....
13473
13474
13475
13476
13477
13478
13479
13480
13481
13482
13483
13484
13485
13486
13487
.....
13722
13723
13724
13725
13726
13727
13728
13729
13730
13731
13732
13733
13734
13735
13736
.....
18907
18908
18909
18910
18911
18912
18913
18914
18915
18916
18917
18918
18919
18920
18921
18922
18923
18924
18925
18926
18927
18928
18929
18930
.....
18931
18932
18933
18934
18935
18936
18937
18938
18939
18940
18941
18942
18943
18944
18945
18946
18947
18948
18949
.....
19259
19260
19261
19262
19263
19264
19265
19266
19267
19268
19269
19270
19271
19272
19273
19274
19275
19276
19277
19278
19279
19280
19281
19282
19283
19284
19285
19286
19287
19288
19289
19290
.....
19350
19351
19352
19353
19354
19355
19356
19357
19358
19359
19360
19361
19362
19363
19364
19365
19366
19367
19368
19369
19370
19371
19372
19373
19374
19375
19376
19377
19378
19379
19380
19381
19382
19383
19384
19385
19386
19387
19388
.....
23125
23126
23127
23128
23129
23130
23131
23132
23133
23134
23135
23136
23137
23138
23139
23140
23141
23142
23143
23144
23145
23146
23147
.....
23157
23158
23159
23160
23161
23162
23163
23164
23165
23166
23167
23168
23169
23170
23171


## Caractères rares
__<s>/ocr(ocr_caractères_rares)__
    \w*[{}<>&*#£^|]+\w*
        <<- \0 != "<" and \0 != ">" ->> _                                                           # Erreur de numérisation ? Cette chaîne contient un caractère de fréquence rare.





TEST: __ocr__ trouve {{l£}} temps
TEST: __ocr__ elle s’{{avance*}} sur le seuil
TEST: __ocr__ {{e||e}} vient
TEST: __ocr__ par beaucoup d’argent ? {{{Il}} débouche le Jack Daniels


__<s>/ocr(ocr_doublons_caractères_rares)__
    [\]\[({}][\]\[({}]+
        <<- ->> _                                                                                   # Erreur de numérisation ? Succession douteuse de caractères.

TEST: __ocr__ {{[[}}voyons celà].
TEST: __ocr__ {{((}}voyons ceci).


## Mélange chiffres/lettres
__[i]/ocr(ocr_le_la_les_regex)__
    [1[\]][easrnxiocuwàéè]
................................................................................
    >arrière >petit >neveu
        <<- /tu/ ->> arrière-petit-neveu|arrière-petits-neveux      # Mettez des traits d’union.

    >arrière >petit >nièce
        <<- /tu/ ->> arrière-petite-nièce|arrière-petites-nièces    # Mettez des traits d’union.

    [basket|volley] ball
        <<- /tu/ ->> \1-\2                                      # Il manque un trait d’union.

    bas [>côté|coté|cotés]
        <<- /tu/ morph(<1 , ":D") ->> bas-côté|bas-côtés        # Il manque un trait d’union.

    [les|des|aux] beaux arts
        <<- /tu/ -2:3>> beaux-arts                              # Il manque un trait d’union.

................................................................................

    >centre >ville
        <<- /tu/ ->> centre-ville|centres-villes                # Il manque un trait d’union.

    [chassé+ses] [croisé+ses]
        <<- /tu/ ->> chassé-croisé|chassés-croisés              # Il manque un trait d’union.

    château fort
        <<- /tu/ not morph(>1, ":A.*:[me]:[si]") ->> \1-\2      # Il manque un trait d’union.|https://fr.wiktionary.org/wiki/ch%C3%A2teau-fort

    châteaux forts
        <<- /tu/ ->> \1-\2                                      # Il manque un trait d’union.|https://fr.wiktionary.org/wiki/ch%C3%A2teau-fort

    coffre fort
        <<- /tu/ not morph(>1, ":A.*:[me]:[si]") ->> \1-\2      # Il manque un trait d’union.|https://fr.wiktionary.org/wiki/coffre-fort

    coffres forts
        <<- /tu/ ->> \1-\2                                      # Il manque un trait d’union.|https://fr.wiktionary.org/wiki/coffre-fort

    >chef lieu
        <<- /tu/ ->> \1-\2                                      # Il manque un trait d’union.

    >chef d’ œuvre
        <<- /tu/ ->> \1-\2\3                                    # Il manque un trait d’union.

    [auto|moto] >club
................................................................................

    face [a|à] face
        <<- /tu/ morph(<1, ":D") ->> face-à-face                # Si vous employez cette locution comme un nom, mettez des traits d’union.|https://fr.wiktionary.org/wiki/face-%C3%A0-face

    gagne >pain
        <<- /tu/ not morph(<1, ":O[sv]") ->> gagne-pain         # Il manque un trait d’union.

    [grand+s] [>père|>mère]
        <<- /tu/ ->> \1-\2                                      # Il manque un trait d’union.

    lèse majesté
        <<- /tu/ ->> \1-\2                                      # Il manque un trait d’union.

    n [ième+s|ieme+s|ème+s|eme+s]
        <<- /tu/ ->> n-ième|n-ièmes                             # Il manque un trait d’union.
................................................................................
TEST: sur le {{bas côté}}
TEST: les {{beaux arts}}
TEST: {{le}} {{bouche à oreille}}
TEST: {{chef lieu}} de ce canton
TEST: un {{chassé croisé}}
TEST: ne vois-tu pas que c’est un {{chef d’œuvre}} ?
TEST: ils sont allés au {{centre ville}}.
TEST: un {{château fort}} n’est pas une demeure confortable
TEST: des {{châteaux forts}}
TEST: un {{coffre fort}}
TEST: des {{coffres forts}}
TEST: Le {{moto club}} était sur le point de faire faillite.
TEST: J’ai beaucoup de {{déjà vu}}.
TEST: L’{{état major}} n’a pas encore tranché la question.
TEST: Le {{face à face}} entre les forces de l’ordre et les manifestants se poursuit devant l’hôtel de ville à Bordeaux depuis environ 1h30.
TEST: {{gagne pain}} de merde
TEST: mes deux {{grands pères}} sont décédés
TEST: un crime de {{lèse majesté}}
................................................................................
    les ([elle+s]) [de|des|du|d’]
    [sous|sur] leurs ([elle+s]) [<end>|,|$:R]
        <<- /conf/ -1>> ailes
        # Confusion probable : “elle” est un pronom personnel féminin. Pour les oiseaux, les avions ou les parties d’un bâtiment ou d’une armée, écrivez “aile”.|https://fr.wiktionary.org/wiki/aile

    [elle+s] ?[droite|gauche]¿ du [château|palais|bâtiment|manoir]
    [elle+s] ?[droite|gauche]¿ [de|d’] la [maison|ferme]
        <<- /conf/ morph(<1, "<start>|,|:D") -1>> aile|ailes
        # Confusion probable : “elle” est un pronom personnel féminin. Pour les oiseaux, les avions ou les parties d’un bâtiment ou d’une armée, écrivez “aile”.|https://fr.wiktionary.org/wiki/aile

TEST: l’{{elle}} est en feu.
TEST: sous l’{{elle}} de sa mère, il ne craint rien
TEST: sur son {{elle}} droite
TEST: des {{elles}} enduites de pétrole
TEST: De l’autre côté du mur, dans l’{{elle}} réservée aux femmes, il y a des jeunes filles dont nul n’a parlé
................................................................................

TEST: ce sont des durs à {{cuir}}
TEST: Quelle dure {{a}} {{cuir}}, celle-là.


# dans / d’en
__conf_dans_dan_d_en__
    d’ en [le|la|l’|les|de|d’|des|du|un|une|mon|ton|son|ma|ta|sa|mes|tes|ses|notre|votre|nos|vos|leurs|ce|cet|cette|ces|chacun|plusieurs|quelques|certains|certaines]
        <<- /conf/ not (\3 == "ce" and value(>1, "|moment|")) -1:2>> dans           # Confusion. Utilisez “dans” pour dire “à l’intérieur de quelque chose”.

    <start>  [>dent|dan]  [le|la|l’|les|un|une|mon|ton|son|ma|ta|sa|mes|tes|ses|notre|votre|nos|vos|leurs|ce|cet|cette|ces|chacun|plusieurs|quelques|certains|certaines]
        <<- /conf/ -2>> dans                                                        # Confusion. Utilisez “dans” pour dire “à l’intérieur de quelque chose”.

TEST: {{dan}} la voiture
TEST: ils sont partis {{d’en}} une direction différente
TEST: {{dents}} les montagnes au loin.
TEST: Dents de la mer.
TEST: Un pauvre, ça doit consommer, bosser, et bien fermer sa gueule. Tout l’inverse d’en ce moment.
................................................................................
    mois        [après|par]     mois
    décennie    [après|par]     décennie
    année       [après|par]     année
    siècle      [après|par]     siècle
    génération  [après|par]     génération
        <<- ~>> *

    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   [du|ce]  [matin|soir]
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   de  l’ après-midi
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   cet  après-midi
    [à|de]      ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   [demain|hier]  ?[matin|soir|après-midi]¿
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   [du|ce]  [matin|soir]
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   de  l’ après-midi
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   cet  après-midi
    jusqu’ à    ~^\d\d?$  h  ?~^\d\d?$¿  ?[tapantes|pétantes]¿   [demain|hier]  ?[matin|soir|après-midi]¿
        <<- ~>> *

    [à|de]      *HOUR  ?[tapantes|pétantes]¿
    [à|de]      *HOUR  ?[tapantes|pétantes]¿  [du|ce]  [matin|soir]
    [à|de]      *HOUR  ?[tapantes|pétantes]¿  de  l’ après-midi
    [à|de]      *HOUR  ?[tapantes|pétantes]¿  cet  après-midi
    [à|de]      *HOUR  ?[tapantes|pétantes]¿  [demain|hier]  ?[matin|soir|après-midi]¿
    jusqu’ à    *HOUR  ?[tapantes|pétantes]¿
    jusqu’ à    *HOUR  ?[tapantes|pétantes]¿  [du|ce]  [matin|soir]
    jusqu’ à    *HOUR  ?[tapantes|pétantes]¿  de  l’ après-midi
    jusqu’ à    *HOUR  ?[tapantes|pétantes]¿  cet  après-midi
    jusqu’ à    *HOUR  ?[tapantes|pétantes]¿  [demain|hier]  ?[matin|soir|après-midi]¿
        <<- ~>> *

TEST: Le train de 2 h 47 {{arriveraient}} en retard.
TEST: Le train de 2 h 47 du matin {{arriveraient}} en retard.
TEST: Le train de 2h47 du matin {{arriveraient}} en retard.


................................................................................
    >chasseur [de|d’] primes
    >chemin [de|d’] [traverse|fer]
    >chemise [de|d’] nuit
    >chemise sans >manche
    >chèque sans provision
    >chili con carne
    >chou à la crème ?[fouettée|diplomate|mousseline|patissière|pralinée]¿
    >cité u
    >clair comme [de|d’] l’ eau [de|d’] [boudin|roche|source]
    >clair comme du cristal
    >clair comme jus [de|d’] [boudin|>chaussette|chique]
    >classement sans suite
    [>clé|>clef] à molette
    >clin d’ œil
    >clause [de|d’] [confidentialité|non-concurrence]
................................................................................
    [réglé+ses] comme du papier à musique
    >règlement [de|d’] comptes
    [remis+es] à plat
    >requête en nullité
    >requête en non [conciliation|inscription|lieu]
    >requête en non révocation [de|d’] sursis
    >responsable qualité
    [>resto|>restau] u
    >retour à la case départ
    >rivière à sec
    >robe [de|d’] [chambre|soirée]
    >robe du soir
    >robe sans >manche
    >roman à l’ eau [de|d’] rose
    >roue [avant|arrière]
................................................................................
__conf_pâte_patte_pat__
    [>patte|pat] [>alimentaire|>alsacien|>chinois|>feuilleté|>italien|>thermique]
    [>patte|pat] au [basilic|beurre|saumon|pesto|poulet|thon]
    [>patte|pat] [à|a] [>pain|>crêpe|>gaufre|>pizza|>tarte|>modeler|>tartiner]
    [>patte|pat] [d’|de] [>amande|>amende|>fruit]
        <<- /conf/ -1>> pâte|pâtes                              # Confusion. La patte est le membre d’un animal (ou d’une table…). La matière pâteuse s’écrit “pâte”.

    >mettre la main à [la|cette] [>patte|pat]
    >coq en [>patte|pat]
        <<- /conf/ --1>> pâte                                   # Confusion. La patte est le membre d’un animal (ou d’une table…). La matière pâteuse s’écrit “pâte”.

    >coup de [>pâte|pat]
        <<- /conf/ -3>> patte                                   # Confusion. Une pâte est une matière pâteuse. Pour désigner le membre d’un animal, écrivez “patte”.

    >montrer [>pâte|pat] [blanche+s]
        <<- /conf/ -2:3>> patte blanche                         # Confusion. Une pâte est une matière pâteuse. Pour désigner le membre d’un animal, écrivez “patte”.

    >retomber sur [mes|tes|ses|ces|nos|vos|leur|leurs] [>pâte|pat]
        <<- /conf/ --1>> pattes                                 # Confusion. Une pâte est une matière pâteuse. Pour désigner le membre d’un animal, écrivez “patte”.

    >court sur [>pâte|pat]
        <<- /conf/ --1>> pattes                                 # Confusion. Une pâte est une matière pâteuse. Pour désigner le membre d’un animal, écrivez “patte”.

TEST: Prépare la {{patte}} à tarte.
................................................................................
TEST: Ils mangent souvent des {{pattes}} au thon.
TEST: Des {{pattes}} alimentaires.
TEST: Elles ont acheté de la {{patte}} à tartiner.
TEST: La {{patte}} à pizza est plus épaisse que la pâte à crêpes.
TEST: Elle adore la {{patte}} d’amande.
TEST: Il est comme un coq en {{pattes}} là.
TEST: Elle n’a jamais mis la main à la {{patte}}.
TEST: ne mets jamais la main à la {{patte}}
TEST: donne-moi un coup de {{pâte}}
TEST: elle retombe toujours sur ses {{pâtes}}.
TEST: il est court sur {{pâtes}}
TEST: elle va montrer {{pâte blanche}} et tout ira bien.


# péché / pêcher
__conf_péché_pêcher2__
    >pêcher par excès [de|d’]
    >pêcher par [insuffisance|omission|orgueil]
        <<- /conf/ -1>> pécher                                  # Confusion : pêcher (capturer des poissons) ≠ pécher (faire un écart de conduite).|https://fr.wiktionary.org/wiki/p%C3%A9cher
................................................................................

    [>être|>demeurer|>rester|>devenir]  >septique
        <<- /conf/ not morph(<1, ">plaie/") -2>> =\2.replace("sep", "scep")     # Confusion possible. Septique = corrompu, infecté. Sceptique = ayant des doutes.

TEST: cette fosse {{sceptique}} est pleine.
TEST: Je suis {{septique}} !


## se / ce
__conf_ce_se_nom__
    [de|par|pour|sans]  se  *WORD
        <<- /conf/ analyse(\3, ":N.*:[me]:[si]", ":Y") -2>> ce                  # Confusion probable. Si “\-1” est bien un nom ou un adjectif, alors écrivez “ce”.

    <start>  se  *WORD  [ne|n’|me|m’|te|t’|se|s’]
    <start>  se  *WORD  [le|la|l’|les|en|nous|vous|lui|leur|y]  @:(?:[123][sp]|P)¬:G
    <start>  se  *WORD  [nous|vous]     [le|la|l’|les|en|y]     @:(?:[123][sp]|P)
    <start>  se  *WORD  [le|la|l’|les]  [lui|leur|en|y]         @:(?:[123][sp]|P)
    <start>  se  *WORD  [lui|leur|y]    en                      @:(?:[123][sp]|P)
    <start>  se  *WORD  @:(?:[123][sp]|P)¬:G
        <<- /conf/ analyse(\3, ":[NA]", ":Y") -2>> ce                           # Confusion probable. Si “\3” est bien un nom ou un adjectif, alors écrivez “ce”.

TEST: que sais-tu de {{se}} {{type}}
TEST: {{se}} type nous emmerde.                                         ->> ce
TEST: se doit d’être fort, ce con, sinon c’est la fin pour lui.


## soit / soie / soi
__conf_aller_de_soi__
    >aller de [sois|>soie]
        <<- /conf/ -3>> soi                                 # Confusion.|https://fr.wiktionary.org/wiki/aller_de_soi

    >aller ?[pas|jamais|guère]¿ de soit
................................................................................
    >tacher  [de|d’]  ?[le|la|l’|les|en|nous|vous|lui|leur|y]¿  $:Y
    >tacher  [de|d’]  [nous|vous]     [le|la|l’|les|en|y]       $:Y
    >tacher  [de|d’]  [le|la|l’|les]  [lui|leur|en|y]           $:Y
    >tacher  [de|d’]  [lui|leur]      en                        $:Y
        <<- /conf/ -1>> =\1.replace("a", "â").replace("A", "Â")
        # Confusion. Tache signifie faire une salissure, une altération, une marque, une coloration… Pour parler de l’accomplissement d’un travail, écrivez “tâcher”.

    [<start>|,|(]  *WORD  >tache  >être       [de|d’]  [ne|n’|me|m’|te|t’|se|s’]
    [<start>|,|(]  *WORD  >tache  >être       [de|d’]  [le|la|l’|les|en|nous|vous|lui|leur|y]  @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >être       [de|d’]  [nous|vous]     [le|la|l’|les|en|y]     @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >être       [de|d’]  [le|la|l’|les]  [lui|leur|en|y]         @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >être       [de|d’]  [lui|leur|y]    en                      @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >être       [de|d’]  @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >consister  [à|a]    [ne|n’|me|m’|te|t’|se|s’]
    [<start>|,|(]  *WORD  >tache  >consister  [à|a]    [le|la|l’|les|en|nous|vous|lui|leur|y]  @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >consister  [à|a]    [nous|vous]     [le|la|l’|les|en|y]     @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >consister  [à|a]    [le|la|l’|les]  [lui|leur|en|y]         @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >consister  [à|a]    [lui|leur|y]    en                      @:(?:Y|V1.*:Q)
    [<start>|,|(]  *WORD  >tache  >consister  [à|a]    @:(?:Y|V1.*:Q)
        <<- /conf/ morph(\2, ":D", ":R") -3>> =\3.replace("ach", "âch").replace("ACH", "ÂCH")
        # Confusion. Une tache est une salissure, une altération, une marque, une coloration… Pour parler d’un travail à accomplir, écrivez “tâche”.

TEST: Quelle {{tache}} ingrate.
TEST: Une {{tache}} valorisante.
TEST: Elle se tue à la {{tache}}.
TEST: Il a accompli la {{tache}} facilement.
TEST: {{Tache}} de partir tôt.
TEST: {{Tachez}} d’arriver à l’heure.
TEST: {{Tache}} de ne pas faire trop de bruit.
TEST: se tuer à la {{tache}}
TEST: leur {{tache}} consiste à obéir et à fermer leur gueule
TEST: ma {{tache}} est d’accomplir ce que personne d’autre ne peut faire.
TEST: une tâche dévalorisante.
TEST: peiner à la tâche.


# taule / tôle
__conf_taule_tôle2__
    [>aller|>finir] en [>tôle|>tole]
................................................................................

    [<start>|,|(] [les|plusieurs|leurs]  @:V¬:[NAY]  [ne|n’|me|m’|te|s’|se|s’]
    [<start>|,|(] [les|plusieurs|leurs]  @:V¬:[NAY]  [le|la|l’|les|leur]  @:[123][sp]¬:[QNAG]
    [<start>|,|(] [les|plusieurs|leurs]  @:V¬:[NAY]  ?[nous|vous]¿        @:[123][sp]¬:[QG]
        <<- /conf/ hasSimil(\3, ":[NA].*:[pi]")
        -3>> =suggSimil(\3, ":[NA].*:[pi]", True)                                   # Confusion probable : “\3” est une forme verbale conjuguée. Si “\2” est un déterminant, il faut placer un nom après.

    [<start>|,|(] certains        @:V¬:[NAY]  [me|m’|te|s’|se|s’]
    [<start>|,|(] certains        @:V¬:[NAY]  [ne|n’]                     @:[123][sp]
    [<start>|,|(] certains        @:V¬:[NAY]  [le|la|l’|les|leur]         @:[123][sp]¬:[QNAG]
    [<start>|,|(] certains        @:V¬:[NAY]  ?[nous|vous]¿               @:[123][sp]¬:[QG]
        <<- /conf/ hasSimil(\3, ":[NA].*:[me]:[pi]")
        -3>> =suggSimil(\3, ":[NA].*:[me]:[pi]", True)                              # Confusion probable : “\3” est une forme verbale conjuguée. Si “\2” est un déterminant, il faut placer un nom après.

    [<start>|,|(] certaines       @:V¬:[NAY]  [me|m’|te|s’|se|s’]
    [<start>|,|(] certaines       @:V¬:[NAY]  [ne|n’]                     @:[123][sp]
    [<start>|,|(] certaines       @:V¬:[NAY]  [le|la|l’|les|leur]         @:[123][sp]¬:[QNAG]
    [<start>|,|(] certaines       @:V¬:[NAY]  ?[nous|vous]¿               @:[123][sp]¬:[QG]
        <<- /conf/ hasSimil(\3, ":[NA].*:[fe]:[pi]")
        -3>> =suggSimil(\3, ":[NA].*:[fe]:[pi]", True)                              # Confusion probable : “\3” est une forme verbale conjuguée. Si “\2” est un déterminant, il faut placer un nom après.

TEST: Un {{défie}} se définit par la difficulté                 ->> défi
TEST: Le {{défit}} ne l’enthousiasmait pas.                     ->> défi
................................................................................
TEST: Les amener n’apportait que des problèmes.
TEST: Le prendre par surprise était difficile.
TEST: La consigner devenait une obligation.
TEST: Les reconnaître semblait nécessaire.
TEST: Son ministre du Budget, Gérald Darmanin, l’avait dit plus crûment sur RTL
TEST: Certains jouent la carte de la dérision
TEST: Certains font grève tous les vendredis pour soutenir cette cause.
TEST: Certains confient ne pas avoir mangé depuis deux ou trois jours


__conf_suj_verbe_det_verbe_nom__
    [<start>|,|(]  [je|j’|tu|il|elle|on|nous|vous|ils|elles|iel|iels|ce|c’]   ?[ne|n’]¿   ?[le|la|l’|les|en|me|m’|te|t’|se|s’|nous|vous|lui|leur|y]¿  @:[123][sp]        [le|un]  @:[123][sp]¬:[NA].*:[me]:[si]
    [<start>|,|(]  [je|j’|tu|il|elle|on|nous|vous|ils|elles|iel|iels|ce|c’]   ?[ne|n’]¿   [me|m’|te|t’|se|s’|nous|vous]   [le|la|l’|les|en|y]         @:[123][sp]        [le|un]  @:[123][sp]¬:[NA].*:[me]:[si]
    [<start>|,|(]  [je|j’|tu|il|elle|on|nous|vous|ils|elles|iel|iels|ce|c’]   ?[ne|n’]¿   [le|la|l’|les]                  [lui|leur|en|y]             @:[123][sp]        [le|un]  @:[123][sp]¬:[NA].*:[me]:[si]
    [<start>|,|(]  [je|j’|tu|il|elle|on|nous|vous|ils|elles|iel|iels|ce|c’]   ?[ne|n’]¿   [lui|leur]                      en                          @:[123][sp]        [le|un]  @:[123][sp]¬:[NA].*:[me]:[si]

Modified gc_lang/fr/webext/content_scripts/api.js from [184dcb850a] to [0dfb85fb05].

4
5
6
7
8
9
10






11
12
13
14

15
16
17
18
19
20
21
22
..
24
25
26
27
28
29
30
31
32
33
34
35
36



37
38
39
40
41
42
43
44
45
46
47
48

49
50
51
52
53
54
55
56
..
57
58
59
60
61
62
63
64

65
66
67
68
69
70
71
72


const oGrammalecteAPI = {
    // functions callable from within pages
    // to be sent to the content-cript via an event “GrammalecteCall”

    sVersion: "1.0",







    openPanelForNode: function (vNode) {
        //  Parameter: a HTML node or the identifier of a HTML node
        if (vNode instanceof HTMLElement && vNode.id) {

            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "openPanelForNode", sNodeId: vNode.id}) });
            document.dispatchEvent(xEvent);
        }
        else if (typeof(vNode) === "string" && document.getElementById(vNode)) {
            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "openPanelForNode", sNodeId: vNode}) });
            document.dispatchEvent(xEvent);
        }
        else {
................................................................................
        }
    },

    openPanelForText: function (sText, vNode=null) {
        //  Parameter: text to analyze, and optionaly a node to send results to.
        if (typeof(sText) === "string") {
            let sNodeId = "";
            if (vNode instanceof HTMLElement && vNode.id) {
                sNodeId = vNode.id;
            }
            else if (typeof(vNode) === "string" && document.getElementById(vNode)) {
                sNodeId = vNode;
            }



            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "openPanelForText", sText: sText, sNodeId: sNodeId}) });
            document.dispatchEvent(xEvent);
        } else {
            console.log("[Grammalecte API] Error: parameter is not a text.");
        }
    },

    parseNode: function (vNode) {
        /*  Parameter: a HTML node (with a identifier) or the identifier of a HTML node.
            The result will be sent as an event “GrammalecteResult” to the node.
        */
        if (vNode instanceof HTMLElement  &&  vNode.id) {

            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "parseNode", sNodeId: vNode.id}) });
            document.dispatchEvent(xEvent);
        }
        else if (typeof(vNode) === "string" && document.getElementById(vNode)) {
            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "parseNode", sNodeId: vNode}) });
            document.dispatchEvent(xEvent);
        }
        else {
................................................................................
            console.log("[Grammalecte API] Error: parameter is not a HTML node with an identifier.");
        }
    },

    parseText: function (sText, vNode) {
        //  Parameter: text to analyze, and a node to send results to.
        if (typeof(sText) === "string") {
            if (vNode instanceof HTMLElement  &&  vNode.id) {

                let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "parseText", sText: sText, sNodeId: vNode.id}) });
                document.dispatchEvent(xEvent);
            }
            else if (typeof(vNode) === "string" && document.getElementById(vNode)) {
                let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "parseText", sText: sText, sNodeId: vNode}) });
                document.dispatchEvent(xEvent);
            }
            else {







>
>
>
>
>
>



|
>
|







 







|
|




>
>
>











|
>
|







 







|
>
|







4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
..
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
..
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84


const oGrammalecteAPI = {
    // functions callable from within pages
    // to be sent to the content-cript via an event “GrammalecteCall”

    sVersion: "1.0",

    generateNodeId: function (xNode) {
        xNode.id = "grammalecte_generated_id_" + Date.now().toString(36) + "_" + (Math.floor(Math.random() * (1000000))).toString(36);
        console.log("[Grammalecte API] generated id:", xNode.id);
        return xNode.id;
    },

    openPanelForNode: function (vNode) {
        //  Parameter: a HTML node or the identifier of a HTML node
        if (vNode instanceof HTMLElement) {
            let sNodeId = vNode.id || this.generateNodeId(vNode);
            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "openPanelForNode", sNodeId: sNodeId}) });
            document.dispatchEvent(xEvent);
        }
        else if (typeof(vNode) === "string" && document.getElementById(vNode)) {
            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "openPanelForNode", sNodeId: vNode}) });
            document.dispatchEvent(xEvent);
        }
        else {
................................................................................
        }
    },

    openPanelForText: function (sText, vNode=null) {
        //  Parameter: text to analyze, and optionaly a node to send results to.
        if (typeof(sText) === "string") {
            let sNodeId = "";
            if (vNode instanceof HTMLElement) {
                sNodeId = vNode.id || this.generateNodeId(vNode);
            }
            else if (typeof(vNode) === "string" && document.getElementById(vNode)) {
                sNodeId = vNode;
            }
            else {
                console.log("[Grammalecte API] No node identifier. No event, no result will be sent.")
            }
            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "openPanelForText", sText: sText, sNodeId: sNodeId}) });
            document.dispatchEvent(xEvent);
        } else {
            console.log("[Grammalecte API] Error: parameter is not a text.");
        }
    },

    parseNode: function (vNode) {
        /*  Parameter: a HTML node (with a identifier) or the identifier of a HTML node.
            The result will be sent as an event “GrammalecteResult” to the node.
        */
        if (vNode instanceof HTMLElement) {
            let sNodeId = vNode.id || this.generateNodeId(vNode);
            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "parseNode", sNodeId: sNodeId}) });
            document.dispatchEvent(xEvent);
        }
        else if (typeof(vNode) === "string" && document.getElementById(vNode)) {
            let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "parseNode", sNodeId: vNode}) });
            document.dispatchEvent(xEvent);
        }
        else {
................................................................................
            console.log("[Grammalecte API] Error: parameter is not a HTML node with an identifier.");
        }
    },

    parseText: function (sText, vNode) {
        //  Parameter: text to analyze, and a node to send results to.
        if (typeof(sText) === "string") {
            if (vNode instanceof HTMLElement) {
                let sNodeId = vNode.id || this.generateNodeId(vNode);
                let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "parseText", sText: sText, sNodeId: sNodeId}) });
                document.dispatchEvent(xEvent);
            }
            else if (typeof(vNode) === "string" && document.getElementById(vNode)) {
                let xEvent = new CustomEvent("GrammalecteCall", { detail: JSON.stringify({sCommand: "parseText", sText: sText, sNodeId: vNode}) });
                document.dispatchEvent(xEvent);
            }
            else {

Modified gc_lang/fr/webext/content_scripts/init.js from [d05c6e1179] to [56313a38a6].

468
469
470
471
472
473
474

475
476




477
478
479
480
481
482
483
        switch (oCommand.sCommand) {
            case "openPanelForNode":
                if (oCommand.sNodeId && document.getElementById(oCommand.sNodeId)) {
                    oGrammalecte.startGCPanel(document.getElementById(oCommand.sNodeId));
                }
                break;
            case "openPanelForText":

                if (oCommand.sText && oCommand.sNodeId && document.getElementById(oCommand.sNodeId)) {
                    oGrammalecte.startGCPanel(oCommand.sText, document.getElementById(oCommand.sNodeId));




                }
                break;
            case "parseNode":
                if (oCommand.sNodeId && document.getElementById(oCommand.sNodeId)) {
                    let xNode = document.getElementById(oCommand.sNodeId);
                    if (xNode.tagName == "TEXTAREA"  ||  xNode.tagName == "INPUT") {
                        oGrammalecteBackgroundPort.parseAndSpellcheck(xNode.value, oCommand.sNodeId);







>
|
|
>
>
>
>







468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
        switch (oCommand.sCommand) {
            case "openPanelForNode":
                if (oCommand.sNodeId && document.getElementById(oCommand.sNodeId)) {
                    oGrammalecte.startGCPanel(document.getElementById(oCommand.sNodeId));
                }
                break;
            case "openPanelForText":
                if (oCommand.sText) {
                    if (oCommand.sText && oCommand.sNodeId && document.getElementById(oCommand.sNodeId)) {
                        oGrammalecte.startGCPanel(oCommand.sText, document.getElementById(oCommand.sNodeId));
                    }
                    else {
                        oGrammalecte.startGCPanel(oCommand.sText);
                    }
                }
                break;
            case "parseNode":
                if (oCommand.sNodeId && document.getElementById(oCommand.sNodeId)) {
                    let xNode = document.getElementById(oCommand.sNodeId);
                    if (xNode.tagName == "TEXTAREA"  ||  xNode.tagName == "INPUT") {
                        oGrammalecteBackgroundPort.parseAndSpellcheck(xNode.value, oCommand.sNodeId);

Modified gc_lang/fr/webext/content_scripts/menu.js from [562aee0f70] to [1c8166f9c8].

1
2
3
4
5
6
7

8
9
10
11
12
13
14
..
35
36
37
38
39
40
41

42
43
44
45
46
47
48
49
50
51




52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72








73
74
75
76
77
78
79
// JavaScript

/* jshint esversion:6, -W097 */
/* jslint esversion:6 */
/* global oGrammalecte, showError, window, document */

"use strict";


class GrammalecteButton {

    constructor () {
        // the pearl button
        this.xButton = oGrammalecte.createNode("div", { className: "grammalecte_menu_main_button", textContent: " " });
        this.xButton.onclick = () => {
................................................................................
            this._bEditableNode = oOptions.ui_options.editablenode;
        }
    }

    examineNode (xNode) {
        if (xNode && xNode instanceof HTMLElement) {
            if (xNode === this.xTextNode) {

                return;
            }
            if ( ( (xNode.tagName == "TEXTAREA" && this._bTextArea && xNode.getAttribute("spellcheck") !== "false")
                    || (xNode.isContentEditable && this._bEditableNode)
                    || (xNode.tagName == "IFRAME" && this._bIframe) )
                    && xNode.style.display !== "none" && xNode.style.visibility !== "hidden"
                    && !(xNode.dataset.grammalecte_button  &&  xNode.dataset.grammalecte_button == "false") ) {
                this.xTextNode = xNode;
                this.show()
            }




        }
        else {
            this.xTextNode = null;
            this.hide();
        }
    }

    show () {
        if (this.xTextNode) {
            this.xButton.style.display = "none"; // we hide it before showing it again to relaunch the animation
            let oCoord = oGrammalecte.getElementCoord(this.xTextNode);
            //console.log("top:", oCoord.left, "bottom:", oCoord.top, "left:", oCoord.bottom, "right:", oCoord.right);
            this.xButton.style.top = `${oCoord.bottom}px`;
            this.xButton.style.left = `${oCoord.left}px`;
            this.xButton.style.display = "block";
        }
    }

    hide () {
        this.xButton.style.display = "none";
    }









    insertIntoPage () {
        this.bShadow = document.body.createShadowRoot || document.body.attachShadow;
        if (this.bShadow) {
            this.xShadowBtn = oGrammalecte.createNode("div", { style: "display:none; position:absolute; width:0; height:0;" });
            this.xShadowBtnNode = this.xShadowBtn.attachShadow({ mode: "open" });
            oGrammalecte.createStyle("content_scripts/menu.css", null, this.xShadowBtnNode);







>







 







>



|






>
>
>
>










|
<
<
<







>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
..
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// JavaScript

/* jshint esversion:6, -W097 */
/* jslint esversion:6 */
/* global oGrammalecte, showError, window, document */

"use strict";


class GrammalecteButton {

    constructor () {
        // the pearl button
        this.xButton = oGrammalecte.createNode("div", { className: "grammalecte_menu_main_button", textContent: " " });
        this.xButton.onclick = () => {
................................................................................
            this._bEditableNode = oOptions.ui_options.editablenode;
        }
    }

    examineNode (xNode) {
        if (xNode && xNode instanceof HTMLElement) {
            if (xNode === this.xTextNode) {
                this.move();
                return;
            }
            if ( ( (xNode.tagName == "TEXTAREA" && this._bTextArea && xNode.getAttribute("spellcheck") !== "false")
                    || ( (xNode.tagName == "P" || xNode.tagName == "DIV") && xNode.isContentEditable && this._bEditableNode )
                    || (xNode.tagName == "IFRAME" && this._bIframe) )
                    && xNode.style.display !== "none" && xNode.style.visibility !== "hidden"
                    && !(xNode.dataset.grammalecte_button  &&  xNode.dataset.grammalecte_button == "false") ) {
                this.xTextNode = xNode;
                this.show()
            }
            else {
                this.xTextNode = null;
                this.hide();
            }
        }
        else {
            this.xTextNode = null;
            this.hide();
        }
    }

    show () {
        if (this.xTextNode) {
            this.xButton.style.display = "none"; // we hide it before showing it again to relaunch the animation
            this.move();



            this.xButton.style.display = "block";
        }
    }

    hide () {
        this.xButton.style.display = "none";
    }

    move () {
        if (this.xTextNode) {
            let oCoord = oGrammalecte.getElementCoord(this.xTextNode);
            this.xButton.style.top = `${oCoord.bottom}px`;
            this.xButton.style.left = `${oCoord.left}px`;
        }
    }

    insertIntoPage () {
        this.bShadow = document.body.createShadowRoot || document.body.attachShadow;
        if (this.bShadow) {
            this.xShadowBtn = oGrammalecte.createNode("div", { style: "display:none; position:absolute; width:0; height:0;" });
            this.xShadowBtnNode = this.xShadowBtn.attachShadow({ mode: "open" });
            oGrammalecte.createStyle("content_scripts/menu.css", null, this.xShadowBtnNode);

Modified gc_lang/fr/webext/content_scripts/panel.js from [98261d40f5] to [8de62f65f5].

15
16
17
18
19
20
21

22
23
24
25
26
27
28
...
140
141
142
143
144
145
146

147
148
149
150

151
152
153
154
155
156
157
        this.nWidth = nWidth;
        this.nHeight = nHeight;
        this.bFlexible = bFlexible;
        this.bHorizStrech = false;
        this.bVertStrech = false;
        this.nPositionX = 2;
        this.nPositionY = 2;

        this.bWorking = false;

        this.bShadow = document.body.createShadowRoot || document.body.attachShadow;
        if (this.bShadow) {
            this.xShadowPanel = oGrammalecte.createNode("div", {id: this.sId+"_shadow", style: "width:0;height:0;"});
            this.xShadow = this.xShadowPanel.attachShadow({mode: "open"});
            this.xParent = this.xShadow;
................................................................................
            }
            document.body.appendChild(this.xPanel);
        }
    }

    show () {
        this.xPanel.style.display = "flex";

    }

    hide () {
        this.xPanel.style.display = "none";

    }

    center () {
        this.nPosition = 5;
        this.setSizeAndPosition();
    }








>







 







>




>







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
        this.nWidth = nWidth;
        this.nHeight = nHeight;
        this.bFlexible = bFlexible;
        this.bHorizStrech = false;
        this.bVertStrech = false;
        this.nPositionX = 2;
        this.nPositionY = 2;
        this.bOpened = false;
        this.bWorking = false;

        this.bShadow = document.body.createShadowRoot || document.body.attachShadow;
        if (this.bShadow) {
            this.xShadowPanel = oGrammalecte.createNode("div", {id: this.sId+"_shadow", style: "width:0;height:0;"});
            this.xShadow = this.xShadowPanel.attachShadow({mode: "open"});
            this.xParent = this.xShadow;
................................................................................
            }
            document.body.appendChild(this.xPanel);
        }
    }

    show () {
        this.xPanel.style.display = "flex";
        this.bOpened = true;
    }

    hide () {
        this.xPanel.style.display = "none";
        this.bOpened = false;
    }

    center () {
        this.nPosition = 5;
        this.setSizeAndPosition();
    }

Modified gc_lang/fr/webext/content_scripts/panel_gc.js from [e6011e0390] to [a5deafa9f3].

271
272
273
274
275
276
277



278
279
280
281

282
283
284
285
286
287
288



289
290
291
292
293
294
295
...
401
402
403
404
405
406
407



408
409
410
411
412
413
414
415
416
....
1024
1025
1026
1027
1028
1029
1030




1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046

1047
1048
1049
1050
1051

1052
1053
1054
1055

1056

1057
1058
1059
1060
1061
1062
1063
1064
1065
    }

    endTimer () {
        window.clearTimeout(this.nTimer);
    }

    recheckParagraph (iParaNum) {



        let sParagraphId = "grammalecte_paragraph" + iParaNum;
        let xParagraph = this.xParent.getElementById(sParagraphId);
        this._blockParagraph(xParagraph);
        let sText = this.purgeText(xParagraph.textContent);

        oGrammalecteBackgroundPort.parseAndSpellcheck1(sText, "__GrammalectePanel__", sParagraphId);
        this.oTextControl.setParagraph(iParaNum, sText);
        this.oTextControl.write();
    }

    refreshParagraph (sParagraphId, oResult) {
        // function called when results are sent by the Worker



        try {
            let xParagraph = this.xParent.getElementById(sParagraphId);
            // save caret position
            let [nStart, nEnd] = oGrammalecte.getCaretPosition(xParagraph);
            xParagraph.dataset.caret_position_start = nStart;
            xParagraph.dataset.caret_position_end = nEnd;
            // erase texte
................................................................................
        try {
            let sErrorId = this.xParent.getElementById(sNodeSuggId).dataset.error_id;
            //let sParaNum = sErrorId.slice(0, sErrorId.indexOf("-"));
            let xNodeErr = this.xParent.getElementById("grammalecte_err" + sErrorId);
            xNodeErr.textContent = this.xParent.getElementById(sNodeSuggId).textContent;
            xNodeErr.className = "grammalecte_error_corrected";
            xNodeErr.removeAttribute("style");



            this.oTooltip.hide();
            this.recheckParagraph(parseInt(sErrorId.slice(0, sErrorId.indexOf("-")), 10));
        }
        catch (e) {
            showError(e);
        }
    }

    ignoreError (sIgnoreButtonId) {  // ignore
................................................................................
    getText () {
        return [...this.dParagraph.values()].join("\n").normalize("NFC");
    }

    setParagraph (iParagraph, sText) {
        this.dParagraph.set(iParagraph, sText);
    }





    eraseNodeContent () {
        while (this.xNode.firstChild) {
            this.xNode.removeChild(this.xNode.firstChild);
        }
    }

    write () {
        if (this.xNode !== null) {
            if (this.bResultInEvent) {
                const xEvent = new CustomEvent("GrammalecteResult", { detail: JSON.stringify({ sType: "text", sText: this.getText() }) });
                this.xNode.dispatchEvent(xEvent);
                //console.log("Text to xNode:", xEvent.detail);
            }
            else if (this.bTextArea) {
                this.xNode.value = this.getText();

            }
            else if (this.bIframe) {
                //console.log(this.getText());
            }
            else {

                this.eraseNodeContent();
                this.dParagraph.forEach((val, key) => {
                    this.xNode.appendChild(document.createTextNode(val.normalize("NFC")));
                    this.xNode.appendChild(document.createElement("br"));

                });

            }
        }
        else if (this.xResultNode !== null) {
            const xEvent = new CustomEvent("GrammalecteResult", { detail: JSON.stringify({ sType: "text", sText: this.getText() }) });
            this.xResultNode.dispatchEvent(xEvent);
            //console.log("Text to xResultNode:", xEvent.detail);
        }
    }
}







>
>
>



|
>

<
<




>
>
>







 







>
>
>

|







 







>
>
>
>












|



>





>




>

>





|



271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286


287
288
289
290
291
292
293
294
295
296
297
298
299
300
...
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
....
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
    }

    endTimer () {
        window.clearTimeout(this.nTimer);
    }

    recheckParagraph (iParaNum) {
        if (!this.bOpened) {
            return;
        }
        let sParagraphId = "grammalecte_paragraph" + iParaNum;
        let xParagraph = this.xParent.getElementById(sParagraphId);
        this._blockParagraph(xParagraph);
        //let sText = this.purgeText(xParagraph.textContent);
        let sText = this.oTextControl.getParagraph(iParaNum);
        oGrammalecteBackgroundPort.parseAndSpellcheck1(sText, "__GrammalectePanel__", sParagraphId);


    }

    refreshParagraph (sParagraphId, oResult) {
        // function called when results are sent by the Worker
        if (!this.bOpened) {
            return;
        }
        try {
            let xParagraph = this.xParent.getElementById(sParagraphId);
            // save caret position
            let [nStart, nEnd] = oGrammalecte.getCaretPosition(xParagraph);
            xParagraph.dataset.caret_position_start = nStart;
            xParagraph.dataset.caret_position_end = nEnd;
            // erase texte
................................................................................
        try {
            let sErrorId = this.xParent.getElementById(sNodeSuggId).dataset.error_id;
            //let sParaNum = sErrorId.slice(0, sErrorId.indexOf("-"));
            let xNodeErr = this.xParent.getElementById("grammalecte_err" + sErrorId);
            xNodeErr.textContent = this.xParent.getElementById(sNodeSuggId).textContent;
            xNodeErr.className = "grammalecte_error_corrected";
            xNodeErr.removeAttribute("style");
            let iParaNum = parseInt(sErrorId.slice(0, sErrorId.indexOf("-")), 10);
            this.oTextControl.setParagraph(iParaNum, this.purgeText(this.xParent.getElementById("grammalecte_paragraph" + iParaNum).textContent));
            this.oTextControl.write();
            this.oTooltip.hide();
            this.recheckParagraph(iParaNum);
        }
        catch (e) {
            showError(e);
        }
    }

    ignoreError (sIgnoreButtonId) {  // ignore
................................................................................
    getText () {
        return [...this.dParagraph.values()].join("\n").normalize("NFC");
    }

    setParagraph (iParagraph, sText) {
        this.dParagraph.set(iParagraph, sText);
    }

    getParagraph (iParaNum) {
        return this.dParagraph.get(iParaNum);
    }

    eraseNodeContent () {
        while (this.xNode.firstChild) {
            this.xNode.removeChild(this.xNode.firstChild);
        }
    }

    write () {
        if (this.xNode !== null) {
            if (this.bResultInEvent) {
                const xEvent = new CustomEvent("GrammalecteResult", { detail: JSON.stringify({ sType: "text", sText: this.getText() }) });
                this.xNode.dispatchEvent(xEvent);
                console.log("[Grammalecte debug] Text sent to xNode via event:", xEvent.detail);
            }
            else if (this.bTextArea) {
                this.xNode.value = this.getText();
                console.log("[Grammalecte debug] text written in textarea:", this.getText());
            }
            else if (this.bIframe) {
                //console.log(this.getText());
            }
            else {
                let sText = "";
                this.eraseNodeContent();
                this.dParagraph.forEach((val, key) => {
                    this.xNode.appendChild(document.createTextNode(val.normalize("NFC")));
                    this.xNode.appendChild(document.createElement("br"));
                    sText += val.normalize("NFC") + "\n";
                });
                console.log("[Grammalecte debug] text written in editable node:", sText);
            }
        }
        else if (this.xResultNode !== null) {
            const xEvent = new CustomEvent("GrammalecteResult", { detail: JSON.stringify({ sType: "text", sText: this.getText() }) });
            this.xResultNode.dispatchEvent(xEvent);
            console.log("[Grammalecte debug] Text sent to xResultNode via event:", xEvent.detail);
        }
    }
}

Modified graphspell-js/char_player.js from [53774aa734] to [14e0bd8318].

64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
...
285
286
287
288
289
290
291


292
293
294
295
296
297
298
    aConsonant: new Set("bcçdfghjklmnñpqrstvwxzBCÇDFGHJKLMNÑPQRSTVWXZ"),
    aDouble: new Set("bcdfjklmnprstzBCDFJKLMNPRSTZ"),  // letters that may be used twice successively


    // Similar chars

    d1to1: new Map([
        ["1", "liîLIÎ"],
        ["2", "zZ"],
        ["3", "eéèêEÉÈÊ"],
        ["4", "aàâAÀÂ"],
        ["5", "sgSG"],
        ["6", "bdgBDG"],
        ["7", "ltLT"],
        ["8", "bB"],
        ["9", "gbdGBD"],
        ["0", "oôOÔ"],

        ["a", "aAàÀâÂáÁäÄāĀæÆ"],
        ["A", "AaÀàÂâÁáÄäĀāÆæ"],
        ["à", "aAàÀâÂáÁäÄāĀæÆ"],
        ["À", "AaÀàÂâÁáÄäĀāÆæ"],
        ["â", "aAàÀâÂáÁäÄāĀæÆ"],
        ["Â", "AaÀàÂâÁáÄäĀāÆæ"],
................................................................................
        ["AE", ["Æ", "É"]],
        ["ai", ["ei", "é", "è", "ê", "ë"]],
        ["AI", ["EI", "É", "È", "Ê", "Ë"]],
        ["ei", ["ai", "é", "è", "ê", "ë"]],
        ["EI", ["AI", "É", "È", "Ê", "Ë"]],
        ["ch", ["sh", "c", "ss"]],
        ["CH", ["SH", "C", "SS"]],


        ["ct", ["x", "cc"]],
        ["CT", ["X", "CC"]],
        ["oa", ["oi",]],
        ["OA", ["OI",]],
        ["oe", ["œ",]],
        ["OE", ["Œ",]],
        ["oi", ["oa", "oie"]],







|
|
|
|
|
|
|
|
|
|







 







>
>







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
    aConsonant: new Set("bcçdfghjklmnñpqrstvwxzBCÇDFGHJKLMNÑPQRSTVWXZ"),
    aDouble: new Set("bcdfjklmnprstzBCDFJKLMNPRSTZ"),  // letters that may be used twice successively


    // Similar chars

    d1to1: new Map([
        ["1", "1liîLIÎ"],
        ["2", "2zZ"],
        ["3", "3eéèêEÉÈÊ"],
        ["4", "4aàâAÀÂ"],
        ["5", "5sgSG"],
        ["6", "6bdgBDG"],
        ["7", "7ltLT"],
        ["8", "8bB"],
        ["9", "9gbdGBD"],
        ["0", "0oôOÔ"],

        ["a", "aAàÀâÂáÁäÄāĀæÆ"],
        ["A", "AaÀàÂâÁáÄäĀāÆæ"],
        ["à", "aAàÀâÂáÁäÄāĀæÆ"],
        ["À", "AaÀàÂâÁáÄäĀāÆæ"],
        ["â", "aAàÀâÂáÁäÄāĀæÆ"],
        ["Â", "AaÀàÂâÁáÄäĀāÆæ"],
................................................................................
        ["AE", ["Æ", "É"]],
        ["ai", ["ei", "é", "è", "ê", "ë"]],
        ["AI", ["EI", "É", "È", "Ê", "Ë"]],
        ["ei", ["ai", "é", "è", "ê", "ë"]],
        ["EI", ["AI", "É", "È", "Ê", "Ë"]],
        ["ch", ["sh", "c", "ss"]],
        ["CH", ["SH", "C", "SS"]],
        ["ck", ["qu", "q"]],
        ["CK", ["QU", "Q"]],
        ["ct", ["x", "cc"]],
        ["CT", ["X", "CC"]],
        ["oa", ["oi",]],
        ["OA", ["OI",]],
        ["oe", ["œ",]],
        ["OE", ["Œ",]],
        ["oi", ["oa", "oie"]],

Modified graphspell-js/suggest.js from [b9786704df] to [64a0045832].

26
27
28
29
30
31
32


33
34
35
36
37
38
39
        ["mns", "min"],
        ["parce-que", "parce que"],
        ["pcq", "parce que"],
        ["pd", "pendant|pédé"],
        ["pdq", "pendant que"],
        ["pdt", "pendant"],
        ["pdtq", "pendant que"],


        ["pk", "pourquoi"],
        ["pkoi", "pourquoi"],
        ["pq", "pourquoi|PQ"],
        ["prq", "presque"],
        ["prsq", "presque"],
        ["qcq", "quiconque"],
        ["qd", "quand"],







>
>







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
        ["mns", "min"],
        ["parce-que", "parce que"],
        ["pcq", "parce que"],
        ["pd", "pendant|pédé"],
        ["pdq", "pendant que"],
        ["pdt", "pendant"],
        ["pdtq", "pendant que"],
        ["pécunier", "pécuniaire"],
        ["pécuniers", "pécuniaires"],
        ["pk", "pourquoi"],
        ["pkoi", "pourquoi"],
        ["pq", "pourquoi|PQ"],
        ["prq", "presque"],
        ["prsq", "presque"],
        ["qcq", "quiconque"],
        ["qd", "quand"],

Modified graphspell/char_player.py from [820a4d128a] to [56f265c6d5].

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
...
273
274
275
276
277
278
279


280
281
282
283
284
285
286
aConsonant = set("bcçdfghjklmnñpqrstvwxzBCÇDFGHJKLMNÑPQRSTVWXZ")
aDouble = set("bcdfjklmnprstzBCDFJKLMNPRSTZ")  # letters that may be used twice successively


# Similar chars

d1to1 = {
    "1": "liîLIÎ",
    "2": "zZ",
    "3": "eéèêEÉÈÊ",
    "4": "aàâAÀÂ",
    "5": "sgSG",
    "6": "bdgBDG",
    "7": "ltLT",
    "8": "bB",
    "9": "gbdGBD",
    "0": "oôOÔ",

    "a": "aAàÀâÂáÁäÄāĀæÆ",
    "A": "AaÀàÂâÁáÄäĀāÆæ",
    "à": "aAàÀâÂáÁäÄāĀæÆ",
    "À": "AaÀàÂâÁáÄäĀāÆæ",
    "â": "aAàÀâÂáÁäÄāĀæÆ",
    "Â": "AaÀàÂâÁáÄäĀāÆæ",
................................................................................
    "AE": ("Æ", "É"),
    "ai": ("ei", "é", "è", "ê", "ë"),
    "AI": ("EI", "É", "È", "Ê", "Ë"),
    "ei": ("ai", "é", "è", "ê", "ë"),
    "EI": ("AI", "É", "È", "Ê", "Ë"),
    "ch": ("sh", "c", "ss"),
    "CH": ("SH", "C", "SS"),


    "ct": ("x", "cc"),
    "CT": ("X", "CC"),
    "gg": ("gu",),
    "GG": ("GU",),
    "gu": ("gg",),
    "GU": ("GG",),
    "oa": ("oi",),







|
|
|
|
|
|
|
|
|
|







 







>
>







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
aConsonant = set("bcçdfghjklmnñpqrstvwxzBCÇDFGHJKLMNÑPQRSTVWXZ")
aDouble = set("bcdfjklmnprstzBCDFJKLMNPRSTZ")  # letters that may be used twice successively


# Similar chars

d1to1 = {
    "1": "1liîLIÎ",
    "2": "2zZ",
    "3": "3eéèêEÉÈÊ",
    "4": "4aàâAÀÂ",
    "5": "5sgSG",
    "6": "6bdgBDG",
    "7": "7ltLT",
    "8": "8bB",
    "9": "9gbdGBD",
    "0": "0oôOÔ",

    "a": "aAàÀâÂáÁäÄāĀæÆ",
    "A": "AaÀàÂâÁáÄäĀāÆæ",
    "à": "aAàÀâÂáÁäÄāĀæÆ",
    "À": "AaÀàÂâÁáÄäĀāÆæ",
    "â": "aAàÀâÂáÁäÄāĀæÆ",
    "Â": "AaÀàÂâÁáÄäĀāÆæ",
................................................................................
    "AE": ("Æ", "É"),
    "ai": ("ei", "é", "è", "ê", "ë"),
    "AI": ("EI", "É", "È", "Ê", "Ë"),
    "ei": ("ai", "é", "è", "ê", "ë"),
    "EI": ("AI", "É", "È", "Ê", "Ë"),
    "ch": ("sh", "c", "ss"),
    "CH": ("SH", "C", "SS"),
    "ck": ("qu", "q"),
    "CK": ("QU", "Q"),
    "ct": ("x", "cc"),
    "CT": ("X", "CC"),
    "gg": ("gu",),
    "GG": ("GU",),
    "gu": ("gg",),
    "GU": ("GG",),
    "oa": ("oi",),

Modified graphspell/fr.py from [f127f4b49a] to [358150069c].

39
40
41
42
43
44
45


46
47
48
49
50
51
52
    "mns": "min",
    "parce-que": "parce que",
    "pcq": "parce que",
    "pd": "pendant",
    "pdq": "pendant que",
    "pdt": "pendant",
    "pdtq": "pendant que",


    "pk": "pourquoi",
    "pkoi": "pourquoi",
    "pq": "pourquoi|PQ",
    "prq": "presque",
    "prsq": "presque",
    "qcq": "quiconque",
    "qd": "quand",







>
>







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
    "mns": "min",
    "parce-que": "parce que",
    "pcq": "parce que",
    "pd": "pendant",
    "pdq": "pendant que",
    "pdt": "pendant",
    "pdtq": "pendant que",
    "pécunier": "pécuniaire",
    "pécuniers": "pécuniaires",
    "pk": "pourquoi",
    "pkoi": "pourquoi",
    "pq": "pourquoi|PQ",
    "prq": "presque",
    "prsq": "presque",
    "qcq": "quiconque",
    "qd": "quand",

Modified helpers.py from [9aa31c58b5] to [f66c7bb7d2].

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
def fileFile (spf, dVars):
    "return file <spf> as a text filed with variables from <dVars>"
    return Template(open(spf, "r", encoding="utf-8").read()).safe_substitute(dVars)


def copyAndFileTemplate (spfSrc, spfDst, dVars):
    "write file <spfSrc> as <spfDst> with variables filed with <dVars>"
    s = Template(open(spfSrc, "r", encoding="utf-8").read()).safe_substitute(dVars)
    open(spfDst, "w", encoding="utf-8", newline="\n").write(s)


def addFolderToZipAndFileFile (hZip, spSrc, spDst, dVars, bRecursive):
    "add folder content to zip archive and file files with <dVars>"
    # recursive function
    spSrc = spSrc.strip("/ ")
    spDst = spDst.strip("/ ")







|
|







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
def fileFile (spf, dVars):
    "return file <spf> as a text filed with variables from <dVars>"
    return Template(open(spf, "r", encoding="utf-8").read()).safe_substitute(dVars)


def copyAndFileTemplate (spfSrc, spfDst, dVars):
    "write file <spfSrc> as <spfDst> with variables filed with <dVars>"
    sText = Template(open(spfSrc, "r", encoding="utf-8").read()).safe_substitute(dVars)
    open(spfDst, "w", encoding="utf-8", newline="\n").write(sText)


def addFolderToZipAndFileFile (hZip, spSrc, spDst, dVars, bRecursive):
    "add folder content to zip archive and file files with <dVars>"
    # recursive function
    spSrc = spSrc.strip("/ ")
    spDst = spDst.strip("/ ")