Add spell checking support

Julien LepillerTue May 01 15:04:13+0200 2018

a4d9b9b

Add spell checking support

guix-full.manifest

11
(specifications->manifest
22
 '("arc-icon-theme"; for displaying standard icons
3+
   "aspell"
4+
   "aspell-dict-en"
5+
   "aspell-dict-fr"
36
   "coreutils"
47
   "diffutils"
8+
   "enchant"
59
   "git"
610
   "gnupg"
711
   "grep"
812
   "guix"
913
   "gzip"
14+
   "hunspell"
15+
   "hunspell-dict-en-us"
16+
   "hunspell-dict-fr"
1017
   "less"
1118
   "make"
1219
   "neovim"

1724
   "python-lxml"
1825
   "python-neovim"
1926
   "python-polib"
27+
   "python-pyenchant"
2028
   "python-pyqt"
2129
   "python-ruamel.yaml"
2230
   "python-sphinx"

guix.manifest

66
   "python-dateutil"
77
   "python-lxml"
88
   "python-polib"
9+
   "python-pyenchant"
910
   "python-pyqt"
1011
   "python-ruamel.yaml"
1112
   "python-sphinx"

offlate/spellcheckedit.py unknown status 1

1+
from PyQt5.QtWidgets import *
2+
from PyQt5.QtGui import *
3+
from PyQt5.QtCore import *
4+
5+
import enchant
6+
import re
7+
import sys
8+
9+
class SpellCheckEdit(QTextEdit):
10+
    def __init__(self, lang, *args):
11+
        QTextEdit.__init__(self, *args)
12+
        self.dict = enchant.Dict(lang)
13+
        self.highlighter = Highlighter(self.document())
14+
        self.highlighter.setDict(self.dict)
15+
16+
    def contextMenuEvent(self, event):
17+
        popup_menu = self.createStandardContextMenu()
18+
19+
        # Select the word under the cursor.
20+
        cursor = self.textCursor()
21+
        cursor.select(QTextCursor.WordUnderCursor)
22+
        self.setTextCursor(cursor)
23+
24+
        if self.textCursor().hasSelection():
25+
            text = self.textCursor().selectedText()
26+
            if not self.dict.check(text):
27+
                spell_menu = QMenu(self.tr('Spelling Suggestions'))
28+
                nospell = QAction(self.tr('No Suggestions'))
29+
                nospell.setEnabled(False)
30+
                for word in self.dict.suggest(text):
31+
                    action = QAction(word)
32+
                    action.triggered.connect((lambda word: (lambda : self.correctWord(word)))(word))
33+
                    spell_menu.addAction(action)
34+
                # If there are suggestions, use the spell_menu. Otherwise, show
35+
                # there is no suggestion.
36+
                popup_menu.insertSeparator(popup_menu.actions()[0])
37+
                if len(spell_menu.actions()) != 0:
38+
                    popup_menu.insertMenu(popup_menu.actions()[0], spell_menu)
39+
                else:
40+
                    popup_menu.insertAction(popup_menu.actions()[0], nospell)
41+
42+
        popup_menu.exec_(event.globalPos())
43+
44+
    def correctWord(self, word):
45+
        cursor = self.textCursor()
46+
        cursor.beginEditBlock()
47+
48+
        cursor.removeSelectedText()
49+
        cursor.insertText(word)
50+
51+
        cursor.endEditBlock()
52+
53+
class Highlighter(QSyntaxHighlighter):
54+
    def __init__(self, *args):
55+
        QSyntaxHighlighter.__init__(self, *args)
56+
57+
    def setDict(self, dico):
58+
        self.dict = dico
59+
60+
    def highlightBlock(self, text):
61+
        if self.dict == None:
62+
            return
63+
64+
        format = QTextCharFormat()
65+
        format.setUnderlineColor(Qt.red)
66+
        format.setUnderlineStyle(QTextCharFormat.SpellCheckUnderline)
67+
68+
        for word_object in re.finditer(r'\b[^\W\d_]+\b', text):
69+
            if not self.dict.check(word_object.group()):
70+
                self.setFormat(word_object.start(), word_object.end() - word_object.start(), format)
71+
72+
73+
if __name__ == '__main__':
74+
    app = QApplication(sys.argv)
75+
    w = SpellCheckEdit()
76+
    w.show()
77+
    sys.exit(app.exec_())

offlate/window.py

77
import re
88
99
from .manager import ProjectManager
10+
from .spellcheckedit import SpellCheckEdit
1011
1112
class ProjectTab(QTabWidget):
1213
    def __init__(self, parent = None):

111112
            self.msgid.addTab(plural, self.tr("Plural"))
112113
            i = 0
113114
            for msgstr in data.msgstrs:
114-
                form = QTextEdit()
115+
                form = SpellCheckEdit(self.project.lang)
115116
                form.setText(msgstr)
116117
                form.textChanged.connect(self.modify)
117118
                self.msgstr.addTab(form, str(i))

119120
        else:
120121
            self.msgid = QTextEdit()
121122
            self.msgid.setReadOnly(True)
122-
            self.msgstr = QTextEdit()
123+
            self.msgstr = SpellCheckEdit(self.project.lang)
123124
            self.msgid.setText(data.msgids[0])
124125
            self.msgstr.setText(data.msgstrs[0])
125126
            self.msgstr.textChanged.connect(self.modify)

129130
    def modify(self):
130131
        item = self.treeWidget.currentItem()
131132
        data = item.data(0, Qt.UserRole)
132-
        if self.msgstr.__class__.__name__ == "QTextEdit":
133+
        if self.msgstr.__class__.__name__ == "SpellCheckEdit":
133134
            msgstr = self.msgstr.toPlainText()
134135
            data.update(0, msgstr)
135136
            item.setText(1, msgstr)