Index: gc_core/js/char_player.js
==================================================================
--- gc_core/js/char_player.js
+++ gc_core/js/char_player.js
@@ -24,10 +24,14 @@
             sRes += this._dTransChars.gl_get(c, c);
         }
         return sRes.replace("eau", "o").replace("au", "o");
     },
 
+    aVowel: new Set("aáàâäāeéèêëēiíìîïīoóòôöōuúùûüūyýỳŷÿȳœæAÁÀÂÄĀEÉÈÊËĒIÍÌÎÏĪOÓÒÔÖŌUÚÙÛÜŪYÝỲŶŸȲŒÆ"),
+    aConsonant: new Set("bcçdfghjklmnñpqrstvwxzBCÇDFGHJKLMNÑPQRSTVWXZ"),
+    aDouble: new Set("bcçdfjklmnprstzBCÇDFJKLMNPRSTZ"),  // letters that may be used twice successively
+
 
     // Similar chars
 
     d1to1: new Map([
         ["1", "liîLIÎ"],
@@ -158,20 +162,18 @@
         ["Æ", ["AE",]],
         ["b", ["bb",]],
         ["B", ["BB",]],
         ["c", ["cc", "ss", "qu", "ch"]],
         ["C", ["CC", "SS", "QU", "CH"]],
-        ["ç", ["ss", "cc", "qh", "ch"]],
-        ["Ç", ["SS", "CC", "QH", "CH"]],
         ["d", ["dd",]],
         ["D", ["DD",]],
+        ["é", ["ai", "ei"]],
+        ["É", ["AI", "EI"]],
         ["f", ["ff", "ph"]],
         ["F", ["FF", "PH"]],
         ["g", ["gu", "ge", "gg", "gh"]],
         ["G", ["GU", "GE", "GG", "GH"]],
-        ["i", ["ii",]],
-        ["I", ["II",]],
         ["j", ["jj", "dj"]],
         ["J", ["JJ", "DJ"]],
         ["k", ["qu", "ck", "ch", "cu", "kk", "kh"]],
         ["K", ["QU", "CK", "CH", "CU", "KK", "KH"]],
         ["l", ["ll",]],
@@ -197,10 +199,17 @@
         ["x", ["cc", "ct", "xx"]],
         ["X", ["CC", "CT", "XX"]],
         ["z", ["ss", "zh"]],
         ["Z", ["SS", "ZH"]],
     ]),
+
+    get1toXReplacement: function (cPrev, cCur, cNext) {
+        if (this.aConsonant.has(cCur)  &&  (this.aConsonant.has(cPrev)  ||  this.aConsonant.has(cNext))) {
+            return [];
+        }
+        return this.d1toX.gl_get(cCur, []);
+    },
 
     d2toX: new Map([
         ["an", ["en",]],
         ["AN", ["EN",]],
         ["au", ["eau", "o", "ô"]],

Index: gc_core/js/ibdawg.js
==================================================================
--- gc_core/js/ibdawg.js
+++ gc_core/js/ibdawg.js
@@ -306,11 +306,11 @@
                     if (nMaxDel > 0) {
                         this._suggest(oSuggResult, sRemain.slice(1), nMaxSwitch, nMaxDel-1, nMaxHardRepl, nDeep+1, iAddr, sNewWord, true);
                     }
                 }
                 // Phonetic replacements
-                for (let sRepl of char_player.d1toX.gl_get(cCurrent, [])) {
+                for (let sRepl of char_player.get1toXReplacement(sNewWord.slice(-1), cCurrent, sRemain.slice(1,2))) {
                     this._suggest(oSuggResult, sRepl + sRemain.slice(1), nMaxSwitch, nMaxDel, nMaxHardRepl, nDeep+1, iAddr, sNewWord, true);
                 }
                 for (let sRepl of char_player.d2toX.gl_get(sRemain.slice(0, 2), [])) {
                     this._suggest(oSuggResult, sRepl + sRemain.slice(2), nMaxSwitch, nMaxDel, nMaxHardRepl, nDeep+1, iAddr, sNewWord, true);
                 }

Index: gc_core/py/char_player.py
==================================================================
--- gc_core/py/char_player.py
+++ gc_core/py/char_player.py
@@ -16,10 +16,15 @@
 
 def cleanWord (sWord):
     "word simplication before calculating distance between words"
     return sWord.lower().translate(_xTransChars).replace("eau", "o").replace("au", "o")
 
+
+aVowel = set("aáàâäāeéèêëēiíìîïīoóòôöōuúùûüūyýỳŷÿȳœæAÁÀÂÄĀEÉÈÊËĒIÍÌÎÏĪOÓÒÔÖŌUÚÙÛÜŪYÝỲŶŸȲŒÆ")
+aConsonant = set("bcçdfghjklmnñpqrstvwxzBCÇDFGHJKLMNÑPQRSTVWXZ")
+aDouble = set("bcçdfjklmnprstzBCÇDFJKLMNPRSTZ")  # letters that may be used twice successively
+
 
 # Similar chars
 
 d1to1 = {
     "1": "liîLIÎ",
@@ -150,20 +155,18 @@
     "Æ": ("AE",),
     "b": ("bb",),
     "B": ("BB",),
     "c": ("cc", "ss", "qu", "ch"),
     "C": ("CC", "SS", "QU", "CH"),
-    "ç": ("ss", "cc", "qh", "ch"),
-    "Ç": ("SS", "CC", "QH", "CH"),
     "d": ("dd",),
     "D": ("DD",),
+    "é": ("ai", "ei"),
+    "É": ("AI", "EI"),
     "f": ("ff", "ph"),
     "F": ("FF", "PH"),
     "g": ("gu", "ge", "gg", "gh"),
     "G": ("GU", "GE", "GG", "GH"),
-    "i": ("ii",),
-    "I": ("II",),
     "j": ("jj", "dj"),
     "J": ("JJ", "DJ"),
     "k": ("qu", "ck", "ch", "cu", "kk", "kh"),
     "K": ("QU", "CK", "CH", "CU", "KK", "KH"),
     "l": ("ll",),
@@ -189,10 +192,17 @@
     "x": ("cc", "ct", "xx"),
     "X": ("CC", "CT", "XX"),
     "z": ("ss", "zh"),
     "Z": ("SS", "ZH"),
 }
+
+
+def get1toXReplacement (cPrev, cCur, cNext):
+    if cCur in aConsonant  and  (cPrev in aConsonant  or  cNext in aConsonant):
+        return ()
+    return d1toX.get(cCur, ())
+
 
 d2toX = {
     "an": ("en",),
     "AN": ("EN",),
     "au": ("eau", "o", "ô"),

Index: gc_core/py/ibdawg.py
==================================================================
--- gc_core/py/ibdawg.py
+++ gc_core/py/ibdawg.py
@@ -288,11 +288,11 @@
                         self._suggest(oSuggResult, sRemain[1:2]+sRemain[0:1]+sRemain[2:], nMaxSwitch-1, nMaxDel, nMaxHardRepl, nDeep+1, iAddr, sNewWord, "><",True)
                     # delete char
                     if nMaxDel:
                         self._suggest(oSuggResult, sRemain[1:], nMaxSwitch, nMaxDel-1, nMaxHardRepl, nDeep+1, iAddr, sNewWord, "-"+cCurrent, True)
                 # Phonetic replacements
-                for sRepl in cp.d1toX.get(cCurrent, ()):
+                for sRepl in cp.get1toXReplacement(sNewWord[-1:], cCurrent, sRemain[1:2]):
                     self._suggest(oSuggResult, sRepl + sRemain[1:], nMaxSwitch, nMaxDel, nMaxHardRepl, nDeep+1, iAddr, sNewWord, cCurrent+">"+sRepl, True)
                 for sRepl in cp.d2toX.get(sRemain[0:2], ()):
                     self._suggest(oSuggResult, sRepl + sRemain[2:], nMaxSwitch, nMaxDel, nMaxHardRepl, nDeep+1, iAddr, sNewWord, sRemain[0:2]+">"+sRepl, True)
                 # Hard replacements
                 if nDeep > 3 and nMaxHardRepl: