Engineering
Why the Czech spell checker never flagged a typo
The system spell checker is not equally implemented in every language, and where it is not, it does not report an error — it reports that everything you type is spelled correctly. Finding that out took three conclusions and a physical device.
15 September 2026 · 4 min read · The PressboardKit team
Auto-correction on a Czech keyboard corrected nothing. Not a wrong word, not a transposed pair, not a missing diacritic. Nothing was thrown; nothing was logged. Every word the user typed was, as far as the engine could tell, spelled perfectly.
The path from that symptom to a shipped fix went through three conclusions, two of which were wrong. The shape of the bug is worth writing down, because it is neither specific to Czech nor specific to us.
First: we were asking about a language iOS had never heard of
The system checker names its languages more specifically than we were naming ours. We were handing it a bare language code where it wanted a language and a region.
An unrecognised language is not refused. The checker simply reports every word as correctly spelled. So auto-correction outside English did nothing at all, silently, and English worked only because its bare code happens to resolve on its own.
That is one line of resolution logic, and it is now a pure function with tests. The interesting part is the failure mode: not an error, not an empty result, but a confident everything here is fine.
Second: iOS has no dictionary for this language
With the right language string in place, Czech still corrected nothing. So we measured it — on a real phone with the Czech system language, not in the simulator.
The checker would not flag nonsense words in Czech that it flagged instantly in English. The obvious reading was that the list of supported languages includes languages whose data is not actually installed, and that a missing dictionary calls everything correct.
That reading was half right, and we shipped a fallback on the strength of it: a spell checker of our own over a bundled word list, which generates the slips a thumb actually makes rather than computing edit distance against every word in the language, which is what makes it cheap enough to run on a keystroke.
Third: half of the API works and the other half does not
Then came the objection that broke the second conclusion. The documentation says the checker lists all available spellchecking languages. If the language is listed, it should work.
It does — through a different part of the same API. The checker is really two facilities behind one class: one that finds a misspelling, and one that suggests what you meant. They do not ship together. In Czech, on a device, the finder is silent while the suggestions come back perfectly correct.
We had never seen those suggestions, because our code asked find me a misspelling, then suggest a fix — and for Czech, the first call never returns anything. We never reached the second one.
So we tried to wake the finder up: every plausible spelling of the language, a spread of inputs from bare nonsense to a mangled real word inside a sentence, both settings of every argument. Dozens of combinations, not one hit, while English flagged the same nonsense immediately. There is no Czech spelling data to find. A working finder exists for roughly a dozen languages, and that is the whole of it.
The other half, though, is present and is good. Given a list of correct Czech words — including ones our own word list does not contain — it recognised all of them, and it called none of a list of misspellings a word. That is a usable substitute for the facility that is missing.
What shipped
A layered spell checker. Where the system’s finder works, its verdict stands. Where it does not, the system’s own lexicon still knows whether a word is real, and its suggestions still know what you probably meant — so those two are used together, with a guard, because a suggestion for a word nobody has called wrong is not evidence of anything. Where the system has no data at all, our own word list answers.
Two details matter more than they look. Typing slips are judged against the arrangement
actually on screen, so a QWERTZ keyboard treats QWERTZ neighbours as neighbours rather than
inheriting an English QWERTY’s idea of a near miss. And the accents nobody bothers to type
are restored in the same pass, so delas becomes děláš — while a word that is valid in any
language you have enabled is never rewritten at all.
Two things worth taking away
The first is that a sensible-looking API can be silently half-implemented for your language, and that its failure mode is not an error. It is a confident everything is fine. Ours took a wrong turn precisely because a dead finder and a clean piece of text look identical.
The second is that the simulator would never have shown us any of this. The behaviour differs between a simulator and a phone, and the table we eventually drew only exists because the probe ran on hardware. The end-to-end proof runs there too: a UI test types a misspelled word into the real extension and reads back the corrected one — a word our own list does not know, so only the system dictionary can have supplied it.