Files
craft-libs/crates/proof
Michał Marcin BrzuchalskiandClaude Opus 5.5 20dfbeb48a Add craft-proof: Hunspell affix dictionaries, dictionary discovery and language tags
The language-independent spelling mechanism from WordCraft's wordcraft-proof
(storytold/craft-libs#30): the affix engine (AffixDict, with its compact
serialized form), finding and loading an installed Hunspell .aff/.dic pair,
and BCP 47 tag normalization.

What was WordCraft policy is now a parameter: hunspell::Search carries the
app's dictionaries-folder setting, its environment variable and its Windows
folder name, instead of a global and hard-coded WordCraft names. Which
languages an app proofs, suggestion ranking, grammar rules and user
dictionaries stay in the apps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 17:19:31 +02:00
..

craft-proof

Spelling mechanism shared by the Craft apps: read a Hunspell .aff/.dic pair installed on the system and check words against it. Seeded from WordCraft's wordcraft-proof; GridCraft, DeckCraft and PdfCraft are the next consumers (storytold/craft-libs#30). No dependency on any app or UI framework. Requires Rust 1.95.

let search = craft_proof::hunspell::Search::for_app("WordCraft");
if let Some((aff, dic)) = search.find(&["pl_PL", "pl"]) {
    let dict = craft_proof::hunspell::load(&aff, &dic)?;
    assert!(dict.check("kotami"));
}
# Ok::<(), String>(())
  • Dictionaries are not bundled. Apps read what the OS, a package manager or LibreOffice installed; without one a language simply has no spelling check.
  • Search order (Search): the app's dictionaries folder setting, <APP>_DICTIONARIES, the app's folder under the Windows application-data folders, then the usual Hunspell and LibreOffice locations for the platform. Nothing on wasm.
  • Affix engine (AffixDict): the Hunspell subset real dictionaries such as SJP.PL (Polish) and VERO (Brazilian Portuguese) use: one-character or FLAG UTF-8 flags, prefixes and suffixes with conditions and cross products, continuation classes, FORBIDDENWORD, and the TRY/MAP/REP suggestion tables. Compounding and long or numeric flags are rejected with an error rather than misread.
  • Compact form: AffixDict::to_bytes/from_bytes store a loaded dictionary deflated (Polish is under 1 MB), so an app can cache it instead of parsing the .aff/.dic each start.

What stays in each app: which languages it proofs, suggestion ranking and grammar rules per language, the user dictionary, and how marks are shown.