This is almost a solution:
Module[{str},
checkPrevWord[char_] := (
SelectionMove[nb, Previous, Word];
SelectionMove[nb, All, Word];
str = StringJoin[
StringCases[NotebookRead[nb] /. StyleBox[a_, b___] :> a,
RegularExpression["\\w"]]];
If[StringLength[str] =!= 0 &&
Length[DictionaryLookup[str, IgnoreCase -> True]] === 0,
SetOptions[NotebookSelection[nb], FontColor -> Red];
SelectionMove[nb, Next, Word];
SetOptions[NotebookSelection[nb], FontColor -> Black],
SetOptions[NotebookSelection[nb], FontColor -> Black];
SelectionMove[nb, Next, Word]
]
NotebookWrite[nb, char];);
SetOptions[nb = CreateDocument[],
NotebookEventActions -> ({"KeyDown", #} :>
checkPrevWord[#] & /@ {" ", ";", ".", "-", "!", "?", ",", "/"})];
]
I create a new notebook and check if the previous word you typed is in the dictionary (English). Unfortunately, I do not know how to test for being in a TextCell versus any other Cell, so the spell-checker will try to check the code too. Also, (BEWARE), this crashes Mathematica if you delete your text cell.
Note that you can replace CreateDocument with SelectedNotebook if you want to affect the current notebook.
Hopefully someone can help me identify what I'm missing, and then we'll have a spell-highlighter.