Compare commits

..
Author SHA1 Message Date
Dylan M. Taylor 0a5b4221fd Merge pull request #5205 from benandez/feat/cp2-scowl
CP2.3: English spelling reads SCOWL 2026 (#40, #520, #1281, #1045)
2026-11-02 16:52:47 -05:00
Dylan M. Taylor 52a8a5db76 Merge main into SCOWL spelling PR 2026-11-02 16:23:38 -05:00
Martin BallandClaude Opus 5.5 9ffd30d968 CP2.3: review — NOTICE carries the SCOWL, Titze and Ispell notices; gap 8 records SCOWL English; status lines for localization-tr and architecture
CodeRabbit on #5205:
- NOTICE: the SCOWL English dictionaries (en_US, en_GB-ise, en_CA) with
  Kevin Atkinson's SCOWLv2 notice, Benjamin Titze's notice and Geoff
  Kuenning's Ispell BSD licence for the affix files, as their licences ask of
  distributions.
- docs/gaps.md: gap 8's evidence says each English checks its own SCOWL
  2026 dictionary, with the #40 and #520 regression tests; #40 (closed) is no
  longer listed as open. Status line and revision history.

Also: docs/localization-tr.md's craft-proof path change (3110dcf02, #5202)
and docs/architecture.md's no-data wording (b7dad64d9) get their status lines
and revision rows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 00:39:15 +00:00
Martin BallandClaude Opus 5.5 96c6c19b9e CP2.3: review — pin craft-proof to craft-libs#483's re-review fix (British -ize only for real -ize words)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 00:31:38 +00:00
Martin BallandClaude Opus 5.5 919b8a5838 CP2.3: Cargo.toml — the craft-proof pin needs no follow-up (merge commits keep #483's head in storytold main)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 00:31:38 +00:00
Martin BallandClaude Opus 5.5 211377f550 CP2.3: review — pin craft-proof to craft-libs#483's review fixes (each English checks its own SCOWL dictionary) and craft-i18n to #114's merge
craft-proof moves to 0675d58: an English no longer takes another English's
SCOWL words (en-US flagged colourblind, en-GB colorblind), British English
keeps -ize, and English suggestions drop junk splits and names.
craft-i18n.rev and the Flatpak source move to storytold/craft-i18n#114's merge
commit (059cbf9: judgment/judgement right in every English).
No wordcraft test depended on the dialects crossing
(engine 1120 + 43, layout 578 pass). localization-parity's English row says so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 00:31:38 +00:00
Martin BallandClaude Opus 5.5 09e9522a35 CP2.3: English spelling reads SCOWL 2026; regression tests for #40, #520, #1281, #1045
craft-proof moves to storytold/craft-libs#483's head (e6e948f, on #482's
9e5862a): each English checks against its own SCOWL rel-2026.02.25 dictionary
through the affix engine (ordinals via COMPOUNDRULE), with en-variants.txt as
the dialect policy. Lookup order: dictionaries folder, [English pack], SCOWL,
system Hunspell, the built-in Moby list; Moby stays for hyphenation.
craft-i18n.rev and the Flatpak source move to storytold/craft-i18n#109's merge
commit (efb1127), which adds the SCOWL files.

Typed-text tests pin British spellings in en-GB (#40), modern words (#520),
Canadian/Australian/NZ/Indian English (#1281, #1045) and ordinals; they skip
without the Language data, as the other data tests do. Docs: typing-parity,
localization-parity, ROADMAP progress log.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
2026-11-02 00:31:38 +00:00
14 changed files with 280 additions and 170 deletions
Generated
+97 -145
View File
@@ -155,28 +155,13 @@ version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
[[package]]
name = "alloc-no-stdlib"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2fb6cfd47bf496ff64095c20eaba0c201404ee38714d4142fcfa1dc334fcc7a"
[[package]]
name = "alloc-stdlib"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195"
dependencies = [
"alloc-no-stdlib 2.0.4",
]
[[package]]
name = "alloc-stdlib"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b5c1865780388bfa186411ab5f247819487fc4864c6e9c3106611fa347586e1"
dependencies = [
"alloc-no-stdlib 3.0.0",
"alloc-no-stdlib",
]
[[package]]
@@ -225,6 +210,15 @@ version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
[[package]]
name = "arbitrary"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
dependencies = [
"derive_arbitrary",
]
[[package]]
name = "arboard"
version = "3.7.0"
@@ -620,9 +614,9 @@ version = "8.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3"
dependencies = [
"alloc-no-stdlib 2.0.4",
"alloc-stdlib 0.2.4",
"brotli-decompressor 5.0.3",
"alloc-no-stdlib",
"alloc-stdlib",
"brotli-decompressor",
]
[[package]]
@@ -631,18 +625,8 @@ version = "5.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583"
dependencies = [
"alloc-no-stdlib 2.0.4",
"alloc-stdlib 0.2.4",
]
[[package]]
name = "brotli-decompressor"
version = "6.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34c6783f42c21c952ad7112b354f0ba2f10760e9decea5b1b60523d6e270faaf"
dependencies = [
"alloc-no-stdlib 3.0.0",
"alloc-stdlib 0.3.0",
"alloc-no-stdlib",
"alloc-stdlib",
]
[[package]]
@@ -1080,7 +1064,7 @@ dependencies = [
[[package]]
name = "craft-proof"
version = "0.1.0"
source = "git+https://github.com/storytold/craft-libs?rev=48ed6f8cbd4104225a9ecde122d9fb8d1353b5a6#48ed6f8cbd4104225a9ecde122d9fb8d1353b5a6"
source = "git+https://github.com/storytold/craft-libs?rev=6e45fda67c6d748b4775428cc495e26006a3bf4a#6e45fda67c6d748b4775428cc495e26006a3bf4a"
dependencies = [
"log",
"miniz_oxide 0.9.1",
@@ -1130,7 +1114,7 @@ dependencies = [
"verifysign",
"winreg",
"winsafe",
"zip",
"zip 9.1.0",
]
[[package]]
@@ -1277,6 +1261,17 @@ version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e9de72ce2ad1f90dc62fa25f0f430ef85eb4b0d8fa0be4f30373bc40a21d28e"
[[package]]
name = "derive_arbitrary"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "dify"
version = "0.8.0"
@@ -1534,9 +1529,9 @@ dependencies = [
[[package]]
name = "encoding_rs"
version = "0.8.44"
version = "0.8.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89253175e704ab869b04f9db224d38630e0211a53841a79181deae0889e169f5"
checksum = "8e985e0451871ad22fb8d2b6b076e2028a502a0d3950998c2c5c0a4f9b5d9679"
dependencies = [
"cfg-if",
"core_detect",
@@ -1583,7 +1578,7 @@ dependencies = [
"ecolor",
"emath",
"epaint_default_fonts",
"font-types 0.12.7",
"font-types 0.12.6",
"harfrust 0.12.0",
"log",
"nohash-hasher",
@@ -1596,7 +1591,7 @@ dependencies = [
"unicode-general-category",
"unicode-properties",
"unicode-segmentation",
"vello_cpu 0.2.0",
"vello_cpu",
]
[[package]]
@@ -1682,12 +1677,6 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97b65636e5b9ef369943878ac74335ba1c55c1cb6adbf1e2c293c624248d693"
[[package]]
name = "fearless_simd"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4beca3cb2444e3304ac30843cc091f44ed58932353cd492ce740067bfce6b12"
[[package]]
name = "fearless_simd"
version = "1.1.0"
@@ -1815,9 +1804,9 @@ dependencies = [
[[package]]
name = "font-types"
version = "0.12.7"
version = "0.12.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "835ae9d781464a79026cde387f9cbc650c9a4909d7cf7e658b127e3c35d2f35d"
checksum = "6c92d9081c7ab3bd83ef1eecdfad090f3d966e3ce74106779664114cfe1a6274"
dependencies = [
"bytemuck",
]
@@ -1987,9 +1976,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
dependencies = [
"cfg-if",
"js-sys",
"libc",
"r-efi 5.3.0",
"wasip2",
"wasm-bindgen",
]
[[package]]
@@ -2032,22 +2023,6 @@ name = "glifo"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282a26c1e23de04bdab3e34a21b6f877a479b96737792516b9b8b8f69b6661be"
dependencies = [
"bytemuck",
"foldhash 0.2.0",
"hashbrown 0.17.1",
"log",
"peniko",
"skrifa 0.44.0",
"smallvec",
"vello_common 0.2.0",
]
[[package]]
name = "glifo"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f1218dedd5348c1b166ec3b8b3cbca49d2f527bd43b3fa072ea5123c523ed3f"
dependencies = [
"bytemuck",
"foldhash 0.2.0",
@@ -2057,7 +2032,7 @@ dependencies = [
"png",
"skrifa 0.44.0",
"smallvec",
"vello_common 0.3.0",
"vello_common",
]
[[package]]
@@ -2206,15 +2181,15 @@ dependencies = [
[[package]]
name = "harfrust"
version = "0.15.0"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "865dcc4105d51c323d8fedbb2d75b5e9c8ecddf5613f74c82f851d0afbc97114"
checksum = "948d0741125ba89cd3e1c23e5642415b6ade7e1d29d67ba25fb925b533e989d6"
dependencies = [
"bitflags 2.13.2",
"bytemuck",
"read-fonts 0.46.0",
"once_cell",
"read-fonts 0.43.3",
"smallvec",
"yoke",
]
[[package]]
@@ -2246,6 +2221,12 @@ dependencies = [
"foldhash 0.2.0",
]
[[package]]
name = "hayro-ccitt"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f4d0e94ddd48749f06bbe4e5389fb9799a0c45bcaf00495042076ef05e3241a"
[[package]]
name = "hayro-ccitt"
version = "0.4.0"
@@ -2264,9 +2245,9 @@ dependencies = [
[[package]]
name = "hayro-interpret"
version = "0.8.0"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac9df074ff163a63864cec9b0bf640ccbff8abf4e44481df7369ce0ac172ffbe"
checksum = "f2613d0406898995042d0794c4245b2f2fba1246490c8ac593769bba6551129d"
dependencies = [
"bitflags 2.13.2",
"hayro-cmap",
@@ -2276,7 +2257,7 @@ dependencies = [
"phf 0.13.1",
"rustc-hash 2.1.3",
"siphasher",
"skrifa 0.46.2",
"skrifa 0.42.1",
"smallvec",
"yoke",
]
@@ -2288,16 +2269,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "000e025850f4592ddcaee85640db70704151f2bafd43b6f431aa5b6a2c6a35a9"
dependencies = [
"fearless_simd 1.1.0",
"hayro-ccitt",
"hayro-ccitt 0.4.0",
]
[[package]]
name = "hayro-jpeg2000"
version = "0.4.1"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "122c5f834c37a2260b9c851bb8be685cf539b2a8b94b704a931ef7d2525d5835"
checksum = "c75ab947623ef4ccaa7acf0579edf7cbb5a73838e3839a7be73335e522f433a1"
dependencies = [
"fearless_simd 1.1.0",
"fearless_simd 0.4.1",
]
[[package]]
@@ -2308,12 +2289,12 @@ checksum = "885c5ef0654933139a9b9546fc2c69e18d37f38aa2520f079092b1be18f1fcaa"
[[package]]
name = "hayro-syntax"
version = "0.8.0"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6cdc818d8d265dcb42081d488f7599df4f73fb79e9d347ecedcd3c23809d2026"
checksum = "0edeafd70aa2db743de8ede8637d07ec87db05efe69cde371d03f1b185fcef27"
dependencies = [
"flate2",
"hayro-ccitt",
"hayro-ccitt 0.3.0",
"hayro-jbig2",
"hayro-jpeg2000",
"memchr",
@@ -4222,7 +4203,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046a7d674daf459825b32f5062056d6882db0d2f5a479fbd76ccfc870ac18709"
dependencies = [
"bytemuck",
"font-types 0.12.7",
"font-types 0.12.6",
"once_cell",
]
@@ -4233,22 +4214,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "005c8acf251756c478b0bf402885bfd88a1476020c4c7e6060edc1aa68da38ea"
dependencies = [
"bytemuck",
"font-types 0.12.7",
"font-types 0.12.6",
"once_cell",
]
[[package]]
name = "read-fonts"
version = "0.46.0"
version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdaa4fffe9ff3ca2c353fa9729792805b9b3e324695ff5a081f860612e81b330"
checksum = "d5a0cf4bb6cbce4c29756270d189a5e400ac05e91192161d83a0bcb6e68492e8"
dependencies = [
"bytemuck",
"foldhash 0.2.0",
"font-types 0.12.7",
"font-types 0.12.6",
"once_cell",
"smallvec",
"yoke",
]
[[package]]
@@ -5000,25 +4978,12 @@ dependencies = [
[[package]]
name = "skrifa"
version = "0.46.2"
version = "0.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4febebda507fb889c545a37a135517769d1391941013561292897961d1887d6"
checksum = "526e654b303ff4ad73a5a40b25de2b3ce3d039c5e3b6da5f89ae6e57004cb40f"
dependencies = [
"bytemuck",
"read-fonts 0.43.3",
]
[[package]]
name = "skrifa"
version = "0.49.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7459fb60888ad9a5f367dd293fa2fb9df142cb451aa6bfd6cd66a7d6a9b739d"
dependencies = [
"bytemuck",
"once_cell",
"read-fonts 0.46.0",
"smallvec",
"yoke",
"read-fonts 0.44.0",
]
[[package]]
@@ -5834,21 +5799,6 @@ dependencies = [
"guillotiere",
"log",
"peniko",
"smallvec",
"thiserror 2.0.21",
]
[[package]]
name = "vello_common"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73c2fbe53548bcd25c8ff42f75a93770a8611a16b37bee56d7ef7b44e36027f1"
dependencies = [
"bytemuck",
"fearless_simd 0.7.0",
"guillotiere",
"log",
"peniko",
"png",
"smallvec",
"thiserror 2.0.21",
@@ -5859,28 +5809,16 @@ name = "vello_cpu"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace506ca414548966fcf3c283be94eb1cad8254de488791ee698bf438b0890a9"
dependencies = [
"bytemuck",
"glifo 0.3.0",
"hashbrown 0.17.1",
"vello_common 0.2.0",
]
[[package]]
name = "vello_cpu"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed1fec424fbba6acf6cbc78bb526447eb77590d95f40419d598870fe37535212"
dependencies = [
"bytemuck",
"crossbeam-channel",
"glifo 0.4.0",
"glifo",
"hashbrown 0.17.1",
"ordered-channel",
"png",
"rayon",
"thread_local",
"vello_common 0.3.0",
"vello_common",
]
[[package]]
@@ -6702,9 +6640,9 @@ checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
[[package]]
name = "wl-clipboard-rs"
version = "0.9.5"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "959c7ac3b8afde864f7a7448ac16f29b2b83350b7eccbf77fb781c3999aa6848"
checksum = "4d7888ccd4896447b2d14d3a9350a85df2aeb6f181e2e7a31349d104ac46cac1"
dependencies = [
"libc",
"log",
@@ -6732,7 +6670,7 @@ dependencies = [
"eframe",
"egui",
"fmv-macos-events",
"getrandom 0.4.3",
"getrandom 0.3.4",
"log",
"objc2 0.6.5",
"objc2-app-kit 0.3.2",
@@ -6809,12 +6747,12 @@ dependencies = [
"base64 0.23.1",
"cfb",
"chrono",
"getrandom 0.4.3",
"getrandom 0.3.4",
"hmac",
"image",
"log",
"proptest",
"quick-xml 0.42.0",
"quick-xml 0.41.0",
"sha1 0.11.0",
"sha2 0.11.1",
"thiserror 2.0.21",
@@ -6822,7 +6760,7 @@ dependencies = [
"wordcraft-doc",
"wordcraft-geom",
"zeroize",
"zip",
"zip 3.0.0",
]
[[package]]
@@ -6833,7 +6771,7 @@ dependencies = [
"chrono",
"craft-proof",
"encoding_rs",
"getrandom 0.4.3",
"getrandom 0.3.4",
"image",
"js-sys",
"libc",
@@ -6853,18 +6791,18 @@ dependencies = [
"wordcraft-pdf",
"wordcraft-render",
"zeroize",
"zip",
"zip 3.0.0",
]
[[package]]
name = "wordcraft-fonts"
version = "0.14.0"
dependencies = [
"brotli-decompressor 6.2.0",
"harfrust 0.15.0",
"brotli-decompressor",
"harfrust 0.13.3",
"kurbo",
"log",
"skrifa 0.49.0",
"skrifa 0.47.0",
"unicode-bidi",
"unicode-script",
"wuff",
@@ -6882,11 +6820,11 @@ dependencies = [
"js-sys",
"log",
"proptest",
"quick-xml 0.42.0",
"quick-xml 0.41.0",
"wordcraft-doc",
"wordcraft-geom",
"wordcraft-metafile",
"zip",
"zip 3.0.0",
]
[[package]]
@@ -6964,7 +6902,7 @@ version = "0.14.0"
dependencies = [
"image",
"log",
"vello_cpu 0.3.0",
"vello_cpu",
"wordcraft-doc",
"wordcraft-fonts",
"wordcraft-geom",
@@ -7000,7 +6938,7 @@ dependencies = [
"wordcraft-render",
"wordcraft-zotero",
"zbus",
"zip",
"zip 3.0.0",
]
[[package]]
@@ -7070,7 +7008,7 @@ version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "200a7b806377b65f1ff9a985874332f15357c87e5dd7855f35f06dade95b8b3d"
dependencies = [
"brotli-decompressor 5.0.3",
"brotli-decompressor",
"bytes",
"flate2",
]
@@ -7419,6 +7357,20 @@ dependencies = [
"syn 3.0.6",
]
[[package]]
name = "zip"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308"
dependencies = [
"arbitrary",
"crc32fast",
"flate2",
"indexmap",
"memchr",
"zopfli",
]
[[package]]
name = "zip"
version = "9.1.0"
+11 -9
View File
@@ -25,8 +25,10 @@ wordcraft-pdf = { path = "crates/pdf" }
# language-data/, embedded from CRAFT_I18N_DIR (craft-i18n.rev). The package keeps the
# `wordcraft-proof` name here so `wordcraft_proof::` paths are unchanged.
# Pinned like the other craft-libs crates (each has its own rev). This rev is the head of
# storytold/craft-libs#482, which adds craft-proof; move it to that PR's merge commit once merged.
wordcraft-proof = { package = "craft-proof", git = "https://github.com/storytold/craft-libs", rev = "48ed6f8cbd4104225a9ecde122d9fb8d1353b5a6", version = "=0.1.0" }
# storytold/craft-libs#483 (SCOWL English, stacked on #482, which adds craft-proof), fetched
# from storytold (GitHub serves PR heads from the base repo); merged with a merge commit, it
# stays in storytold main, so the pin needs no follow-up.
wordcraft-proof = { package = "craft-proof", git = "https://github.com/storytold/craft-libs", rev = "6e45fda67c6d748b4775428cc495e26006a3bf4a", version = "=0.1.0" }
wordcraft-engine = { path = "crates/engine" }
wordcraft-mcp = { path = "crates/mcp" }
wordcraft-zotero = { path = "crates/zotero" }
@@ -52,22 +54,22 @@ regex = { version = "1", default-features = false, features = ["std", "unicode",
regex-automata = { version = "0.4", default-features = false, features = ["std", "syntax", "meta", "nfa-pikevm", "unicode"] }
# text / rendering / formats
skrifa = "0.49"
harfrust = "0.15"
skrifa = "0.47"
harfrust = "0.13"
# WOFF / WOFF2 web fonts added by the user (#582): pure Rust (MIT); its brotli and zlib decoders
# (brotli-decompressor, flate2) are already in the tree.
wuff = "0.2.9"
# WOFF2's brotli stream, decoded ahead of wuff so its glyph point counts are checked first (#3703).
# The same crate and version wuff already decodes it with (no new code in the build): pure Rust,
# `forbid(unsafe_code)` in its default build, no_std-capable (builds for wasm), BSD-3-Clause/MIT.
brotli-decompressor = "6"
vello_cpu = "0.3"
brotli-decompressor = "5"
vello_cpu = "0.2"
image = { version = "0.25", default-features = false, features = ["png", "jpeg", "webp", "gif", "bmp", "tiff"] }
craft-pdf = { git = "https://github.com/storytold/craft-libs", rev = "92d392cff132eaf53e13afff77f38b5c11b73aa0", version = "=0.1.0", default-features = false, features = ["write"] }
# craft-update: app-specific pretend versions apply to startup and manual checks.
craft-update = { git = "https://github.com/storytold/craft-libs", version = "=0.1.0", rev = "c5a1cbfb5f9049f9270955caffb5bee5997aebf7", features = ["egui"] }
quick-xml = "0.42"
zip = { version = "9", default-features = false, features = ["deflate"] }
quick-xml = "0.41"
zip = { version = "3", default-features = false, features = ["deflate"] }
# zlib streams (compressed metafile pictures in `.doc` drawings); already in the lock as a dependency of other crates.
miniz_oxide = "0.9"
cfb = "0.15"
@@ -82,7 +84,7 @@ sha1 = "0.11"
sha2 = "0.11"
hmac = "0.13"
base64 = "0.23"
getrandom = "0.4"
getrandom = "0.3"
zeroize = "1"
# Unix open flags (O_NONBLOCK for the engine's checked file reads, #3666); already in the lock as a
# dependency of other crates.
+61 -1
View File
@@ -20,13 +20,73 @@ list (author, source, license) is in ATTRIBUTION.md.
https://github.com/storytold/craft-fonts/blob/main/ATTRIBUTION.md (BIZ UDPGothic, BIZ UDMincho,
Shippori Mincho), under the SIL Open Font License 1.1. Their licence texts ship with the
packages as OFL-<family>.txt. Builds without CRAFT_FONTS_DIR do not include them.
- Language data (craft-i18n): the word list and hyphenation patterns below are embedded at build
- Language data (craft-i18n): the word lists, dictionaries and hyphenation patterns below are embedded at build
time from https://github.com/storytold/craft-i18n (language-data/, CRAFT_I18N_DIR at the commit
in craft-i18n.rev; all official releases) by craft-proof (storytold/craft-libs). Builds without
CRAFT_I18N_DIR do not include them.
- English word list (craft-i18n language-data/en-us/en-us.dic) — derived from the Moby Hyphenator II list by
Grady Ward, public domain (Project Gutenberg eBook #3204). The hyphenation patterns
(craft-i18n language-data/en-us/hyphenation.pat) were trained from it and are released as CC0-1.0.
- English spelling dictionaries (craft-i18n language-data/en-us, en-gb and en-ca: spelling.aff and
spelling.dic) — the SCOWL rel-2026.02.25 Hunspell dictionaries en_US, en_GB-ise and en_CA from
https://wordlist.aspell.net, bundled unmodified. Their upstream notice (embedded too, for the
About window) is language-data/en-us/LICENCE-SCOWL.txt in craft-i18n. The word lists:
Copyright 2000-2026 by Kevin Atkinson
Permission to use, copy, modify, distribute, and sell any part of SCOWLv2, or
word lists created from it, is hereby granted without fee, provided that the
above copyright notice appears in all copies and that both the above
copyright notice and this notice appear in supporting documentation. Kevin
Atkinson makes no representations about the suitability of this database for
any purpose. It is provided "as is" without express or implied warranty.
The Australian data:
Copyright 2016 by Benjamin Titze
Permission to use, copy, modify, distribute and sell this array, the
associated software, and its documentation for any purpose is hereby
granted without fee, provided that the above copyright notice appears
in all copies and that both that copyright notice and this permission
notice appear in supporting documentation. Benjamin Titze makes no
representations about the suitability of this array for any
purpose. It is provided "as is" without express or implied warranty.
The affix files, a modified version of Geoff Kuenning's Ispell english.aff:
Copyright 1993, Geoff Kuenning, Granada Hills, CA
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. All modifications to the source code must be clearly marked as
such. Binary redistributions based on modified source code
must be clearly marked as modified versions in the documentation
and/or other materials provided with the distribution.
(clause 4 removed with permission from Geoff Kuenning)
5. The name of Geoff Kuenning may not be used to endorse or promote
products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY GEOFF KUENNING AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL GEOFF KUENNING OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
- Polish hyphenation patterns (craft-i18n language-data/pl/hyphenation.pat) — hyph-pl.tex from the hyph-utf8
package, Copyright (C) 1987-1995 Hanna Kołodziejska, Bogusław Jackowski, Marek Ryćko, bundled
unmodified and used under the MIT License; the copyright and permission notice is in the file.
+2 -1
View File
@@ -233,6 +233,7 @@ Imported Word 97–2003 `.doc`/`.dot` files now ask for a supported DOCX target
- 2026-10-15: Find opens Navigation on Results; editing the query restores Results after manual Headings/Pages navigation. Typed and selected-text searches retain document contents (#2096).
| Date | What landed |
| 2026-11-01 | **English spelling reads SCOWL 2026 (CP2, #40, #520, #1281, #1045):** en-US, en-GB (also en-AU, en-NZ, en-IE, en-IN…) and en-CA each check against their own SCOWL `rel-2026.02.25` Hunspell dictionary from craft-i18n, embedded and read by craft-proof's affix engine (which now understands `COMPOUNDRULE`, so ordinals like `21st` are words). Suggestions come from the dialect's own dictionary; our American/British policy (`en-variants.txt`) still decides the other dialect's spellings, because Word accepts more than SCOWL's one spelling per dialect (`organize` and `organise` in en-GB). Rare words the 1990s Moby list accepted (`aposiopesis`) are now flagged. The Moby list stays for hyphenation and as a fallback. The build carries 1.5 MB more Language data. |
| 2026-11-01 | Proofing moved to the shared libraries, with nothing users see changing: the code is `craft-proof` in storytold/craft-libs (with its history) and the spelling and hyphenation data (the Moby list, our English patterns and word lists, the German, Polish, Portuguese and Italian patterns, `ru-extra`) is craft-i18n's `language-data/`, embedded from `CRAFT_I18N_DIR` at the commit in `craft-i18n.rev`. Before/after `wordcraft-cli` runs on a proofing document give the same issues, suggestions and hyphenated PDF (CP1). |
| 2026-10-28 | **Arabic diacritic editing (#4757):** Backspace removes the last stored Arabic combining mark, so its base letter can stay while the mark is replaced. Caret movement and forward Delete keep their cluster rules. Synthetic command, history, protection and native/DOCX fresh-reopen checks; no native Word comparison or readiness change. |
| 2026-10-29 | Insert › Shapes shows the basic shapes as a grid of code-drawn icon tiles, each with an accessible name and tooltip, instead of a text list (#4349) |
@@ -699,7 +700,7 @@ Footer page-table height and body wrapping are corrected. Other pagination gaps
| Date | Change | Summary |
|---|---|---|
| 2026-11-02 | trivial | Progress log: alternative format chunks and MHT open |
| 2026-11-01 | trivial | Progress log: arrowheads keep their kind, width and length and are drawn at Word's sizes |
| 2026-11-01 | trivial | Progress log: English spelling reads SCOWL 2026 (CP2) || 2026-11-01 | trivial | Progress log: arrowheads keep their kind, width and length and are drawn at Word's sizes |
| 2026-11-01 | trivial | Progress log: columns for selected text draw their line between (#5178) |
| 2026-10-31 | trivial | Progress log: a Word 365 .doc in Aptos opens in Aptos (#5066); readiness unchanged |
| 2026-10-31 | trivial | Progress log: a table row doesn't split off a picture that doesn't fit (#4272) |
+1 -1
View File
@@ -82,7 +82,7 @@ pollster = "1"
# in the build through egui-winit, with the same features.
arboard = { workspace = true, features = ["image-data"] }
# The control server's random key.
getrandom = "0.4"
getrandom = "0.3"
[target.'cfg(windows)'.dependencies]
craft-update = { workspace = true }
+1 -1
View File
@@ -1 +1 @@
062a6375c322c88b96691a17f7b5fed71c51f7a8
059cbf95c2a3eb95d637ca8584faca1129d17f48
+79
View File
@@ -3631,3 +3631,82 @@ fn backspace_cannot_join_into_locked_content_control() {
assert!(s.run("text.backspace", &json!({})).is_err());
assert_eq!(s.doc, before);
}
// English spelling from SCOWL 2026 (CP2): each English reads its own SCOWL dictionary, with
// `en-variants.txt` deciding the other dialect's spellings. Typed text, as a person types it.
/// The spelling words typed text gets in `lang` (the whole document's language), with the first
/// suggestion of each.
fn typed_spelling_in(lang: &str, keys: &str) -> Vec<(String, String)> {
let mut s = s();
run(&mut s, "review.language", json!({"lang": lang, "default": true}));
typ(&mut s, keys);
let issues = s.run("review.issues", &json!({})).unwrap();
issues
.as_array()
.unwrap()
.iter()
.filter(|i| i["kind"] == "spelling")
.map(|i| (i["text"].as_str().unwrap().to_string(), i["suggestions"][0].as_str().unwrap_or("").to_string()))
.collect()
}
/// #40: the British spellings the issue lists are right in en-GB, and the American ones are
/// flagged with the British form first.
#[test]
fn issue_40_british_spellings_are_right_in_en_gb() {
if super::no_language_data("issue_40_british_spellings_are_right_in_en_gb") {
return;
}
let none: Vec<(String, String)> = Vec::new();
let text = "The judgement on the defence licence put the programme in the catalogue. ";
assert_eq!(typed_spelling_in("en-GB", text), none);
assert_eq!(typed_spelling_in("en-GB", "Its colour and centre, organised and organized, travelled. "), none);
let flagged = typed_spelling_in("en-GB", "The color of the center. ");
assert_eq!(flagged, [("color".to_string(), "colour".to_string()), ("center".to_string(), "centre".to_string())]);
}
/// #520: common modern words are right (SCOWL plus our supplement), and real misspellings of
/// them are still caught.
#[test]
fn issue_520_common_words_are_right() {
if super::no_language_data("issue_520_common_words_are_right") {
return;
}
let none: Vec<(String, String)> = Vec::new();
assert_eq!(typed_spelling_in("en-US", "My desktop email has downloads, a smartphone and a website. "), none);
// (`recieved` would be AutoCorrected as it is typed.)
let flagged = typed_spelling_in("en-US", "My desktpo emial. ");
assert_eq!(flagged.iter().map(|f| f.0.as_str()).collect::<Vec<_>>(), ["desktpo", "emial"]);
assert_eq!(flagged[0].1, "desktop");
}
/// #1281 and #1045: Canadian and Australian English (and the other British-spelling Englishes)
/// proof by their own rules; ordinals are words in every English.
#[test]
fn issues_1281_1045_english_dialects_proof_typed_text() {
if super::no_language_data("issues_1281_1045_english_dialects_proof_typed_text") {
return;
}
let none: Vec<(String, String)> = Vec::new();
// Canada: British -our and -re, American -ize.
assert_eq!(typed_spelling_in("en-CA", "We organize the colour in the centre. "), none);
assert_eq!(
typed_spelling_in("en-CA", "We organise the color. "),
[("organise".to_string(), "organize".to_string()), ("color".to_string(), "colour".to_string())]
);
// Australia, New Zealand, India: British spelling.
for lang in ["en-AU", "en-NZ", "en-IN"] {
assert_eq!(typed_spelling_in(lang, "We analyse the colour of the theatre. "), none, "{lang}");
assert_eq!(typed_spelling_in(lang, "We analyze it. "), [("analyze".to_string(), "analyse".to_string())], "{lang}");
}
// US English flags British spellings with the American form first.
assert_eq!(typed_spelling_in("en-US", "The colour. "), [("colour".to_string(), "color".to_string())]);
// SCOWL's ordinals (COMPOUNDRULE) are words, even where numbers are checked.
let mut s = s();
run(&mut s, "file.options", json!({"ignoreNumbers": false}));
typ(&mut s, "The 21st and 112th times, not the 21th. ");
let issues = s.run("review.issues", &json!({})).unwrap();
let words: Vec<&str> = issues.as_array().unwrap().iter().filter(|i| i["kind"] == "spelling").filter_map(|i| i["text"].as_str()).collect();
assert_eq!(words, ["21th"]);
}
+2 -2
View File
@@ -26,6 +26,6 @@ chrono = { workspace = true }
js-sys = "0.3"
[dev-dependencies]
hayro-syntax = "0.8.0"
hayro-interpret = { version = "0.8.0", default-features = false, features = ["embed-fonts"] }
hayro-syntax = "0.7.2"
hayro-interpret = { version = "0.7.0", default-features = false, features = ["embed-fonts"] }
hayro-cmap = "0.1"
+2 -1
View File
@@ -1,6 +1,6 @@
# WordCraft architecture
> **Last reviewed:** 2026-10-28 · **Last updated:** 2026-11-01 · **Change:** minor (proofing moved out: `wordcraft-proof` is craft-libs' `craft-proof`, its Language data craft-i18n's `language-data/` embedded from `CRAFT_I18N_DIR`; previously major: crate and layer inventory, source counts, proofing languages and module boundaries re-measured from this checkout; previously minor: `proof` is per language: English and Polish; previously major: first committed version; `plan/architecture.md` is local-only) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
> **Last reviewed:** 2026-10-28 · **Last updated:** 2026-11-02 · **Change:** trivial (craft-proof's row says what a build without the Language data keeps: English spelling from an installed Hunspell English or the built-in list, rule hyphenation for Bulgarian, Turkish and Russian; previously minor: proofing moved out: `wordcraft-proof` is craft-libs' `craft-proof`, its Language data craft-i18n's `language-data/` embedded from `CRAFT_I18N_DIR`; previously major: crate and layer inventory, source counts, proofing languages and module boundaries re-measured from this checkout; previously minor: `proof` is per language: English and Polish; previously major: first committed version; `plan/architecture.md` is local-only) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
How WordCraft is built today. The longer design notes in
`plan/architecture.md` are gitignored and local to the original author's machine; this file is the
@@ -69,6 +69,7 @@ crate name links to its source tree.
| Date | Change | Summary |
|---|---|---|
| 2026-11-02 | trivial | craft-proof's row: without the Language data English spelling falls back to an installed Hunspell English or the built-in Moby list, and only pattern hyphenation is off (#5202 review) |
| 2026-11-01 | minor | `proof` left the workspace: it is `craft-proof` in storytold/craft-libs (with its history), and the spelling and hyphenation data is craft-i18n's `language-data/` (`CRAFT_I18N_DIR`); `assets/spelling` and `assets/hyphenation` are gone |
| 2026-10-28 | major | Recounted workspace crates, layers and Rust source lines; refreshed proofing languages and documented current engine/layout module boundaries and source links |
| 2026-10-10 | minor | `proof`: proofing languages (English, Polish), affix engine, Polish patterns; layout and engine route each run by its language |
+3 -4
View File
File diff suppressed because one or more lines are too long
+3 -2
View File
@@ -1,6 +1,6 @@
# Localization parity with Microsoft Word
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-01 · **Change:** trivial (proofing file paths point at craft-proof in craft-libs and craft-i18n `language-data/`, #5202); previously trivial (word count counts each Han ideograph and kana as a word, #4547; previously trivial: the Traditional Chinese interface draws hanzi to the Taiwan standard with an installed Traditional Chinese font first: PingFang TC, Microsoft JhengHei, Noto Sans CJK TC; previously minor: the egui 0.37 migration preserves the equation “Delete Around Caret in Equation” translation in all 27 catalogs through the shared catalog pin; previously minor: Spanish proofing: es-ES, es-MX, es-419 and es-UY from the installed Hunspell dictionaries, Uruguayan `vos` forms, opening `¿`/`¡` checks, #3360, #3553; previously minor: the interface catalogs moved to storytold/craft-i18n and are looked up through the `craft-i18n` crate, embedded at build time from the commit in `craft-i18n.rev`; previously trivial: interface-language tests: a missing translation never fails a test, `cargo xtask i18n-report` in `cargo xtask ci` prints the strings each language lacks, and lookup and template tests use inline fixture catalogs or the pseudo-language; previously trivial: interface audit: missing catalog entries are reported per language and don't fail the audit; previously minor: disabled-control reasons in ribbon hints translated in every catalog, #2678; previously trivial: Slovenian interface catalog: every key of every other catalog, 2,614 entries; previously minor: Romanian interface catalog; previously trivial: the File › Home greeting is translated in every catalog; previously trivial: Japanese row: ruby (Phonetic Guide) is supported and HTML export/import keeps it, #1681; previously trivial: Russian sorting keeps ё with е and recognises decomposed ё/й; previously minor: English dialects: en-GB, en-CA, en-AU and the other British-spelling Englishes proof their own spellings and flag the other dialect's, #1281, #1045; previously minor: how to install the Hunspell dictionaries on Windows, macOS and Linux: `docs/spelling-dictionaries.md`; previously minor: Read Aloud speaks each sentence in its own language, #1843; previously minor: Indonesian proofing: id-ID spelling from the installed Hunspell dictionary, dictionary-driven suggestions, generic checks with Indonesian messages, #498; previously trivial: print-area strings translated in every catalog; previously trivial: Italian: the interface audit checks the Italian catalog, `Privacy Settings` wording; previously trivial: Italian grammar: `po'`, `qual è`, `È`, `un`/`un'` rules; more elisions and truncations in spelling; previously trivial: Czech interface catalog completed, 2,447 entries; previously trivial: interface audit runs in CI again: size labels translated, 20 strings in every catalog, Read Aloud error race fixed, #1128; previously trivial: Review › Language reaches every language again — Set Proofing Language… and Set As Default, #860; previously minor: Italian proofing: it-IT spelling from the installed Hunspell dictionary, accent-first suggestions, conservative grammar with Italian messages; previously minor: Portuguese proofing; previously trivial: Turkish interface catalog completed, 2,325 entries, #774; previously minor: Hungarian interface added; previously trivial: sorting and table numbers follow the text's language, #836, #837; previously minor: Polish interface; Polish proofing — spelling, grammar, hyphenation — and a proofing language per run; previously minor: Turkish interface added; previously major: first version; catalogs measured from `crates/ui-egui/src/i18n`, Word's languages from its bundle listing) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-01 · **Change:** minor (English spelling reads SCOWL 2026 per English, CP2; previously trivial: proofing file paths point at craft-proof in craft-libs and craft-i18n `language-data/`, #5202; previously trivial: word count counts each Han ideograph and kana as a word, #4547; previously trivial: the Traditional Chinese interface draws hanzi to the Taiwan standard with an installed Traditional Chinese font first: PingFang TC, Microsoft JhengHei, Noto Sans CJK TC; previously minor: the egui 0.37 migration preserves the equation “Delete Around Caret in Equation” translation in all 27 catalogs through the shared catalog pin; previously minor: Spanish proofing: es-ES, es-MX, es-419 and es-UY from the installed Hunspell dictionaries, Uruguayan `vos` forms, opening `¿`/`¡` checks, #3360, #3553; previously minor: the interface catalogs moved to storytold/craft-i18n and are looked up through the `craft-i18n` crate, embedded at build time from the commit in `craft-i18n.rev`; previously trivial: interface-language tests: a missing translation never fails a test, `cargo xtask i18n-report` in `cargo xtask ci` prints the strings each language lacks, and lookup and template tests use inline fixture catalogs or the pseudo-language; previously trivial: interface audit: missing catalog entries are reported per language and don't fail the audit; previously minor: disabled-control reasons in ribbon hints translated in every catalog, #2678; previously trivial: Slovenian interface catalog: every key of every other catalog, 2,614 entries; previously minor: Romanian interface catalog; previously trivial: the File › Home greeting is translated in every catalog; previously trivial: Japanese row: ruby (Phonetic Guide) is supported and HTML export/import keeps it, #1681; previously trivial: Russian sorting keeps ё with е and recognises decomposed ё/й; previously minor: English dialects: en-GB, en-CA, en-AU and the other British-spelling Englishes proof their own spellings and flag the other dialect's, #1281, #1045; previously minor: how to install the Hunspell dictionaries on Windows, macOS and Linux: `docs/spelling-dictionaries.md`; previously minor: Read Aloud speaks each sentence in its own language, #1843; previously minor: Indonesian proofing: id-ID spelling from the installed Hunspell dictionary, dictionary-driven suggestions, generic checks with Indonesian messages, #498; previously trivial: print-area strings translated in every catalog; previously trivial: Italian: the interface audit checks the Italian catalog, `Privacy Settings` wording; previously trivial: Italian grammar: `po'`, `qual è`, `È`, `un`/`un'` rules; more elisions and truncations in spelling; previously trivial: Czech interface catalog completed, 2,447 entries; previously trivial: interface audit runs in CI again: size labels translated, 20 strings in every catalog, Read Aloud error race fixed, #1128; previously trivial: Review › Language reaches every language again — Set Proofing Language… and Set As Default, #860; previously minor: Italian proofing: it-IT spelling from the installed Hunspell dictionary, accent-first suggestions, conservative grammar with Italian messages; previously minor: Portuguese proofing; previously trivial: Turkish interface catalog completed, 2,325 entries, #774; previously minor: Hungarian interface added; previously trivial: sorting and table numbers follow the text's language, #836, #837; previously minor: Polish interface; Polish proofing — spelling, grammar, hyphenation — and a proofing language per run; previously minor: Turkish interface added; previously major: first version; catalogs measured from `crates/ui-egui/src/i18n`, Word's languages from its bundle listing) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
Interface languages, script support and proofing per language. How translation works (adding a
language, the embedded catalogs): `crates/ui-egui/src/i18n.rs`. The catalogs, their format and
@@ -128,7 +128,7 @@ Set Proofing Language › Set As Default keeps the chosen language in user prefe
| Language | Spelling | Suggestions | Grammar | Hyphenation |
|---|---|---|---|---|
| English: American (`en-US`, other regions, text with no language), British spelling (`en-GB`, `en-AU`, `en-NZ`, `en-IE`, `en-ZA`, `en-IN`…), Canadian (`en-CA`) | Moby word list (public domain, ~160k words) with inflection rules, plus our list of ~280 American/British pairs (craft-i18n [`language-data/en-us/en-variants.txt`](https://github.com/storytold/craft-i18n/blob/main/language-data/en-us/en-variants.txt)) with inflections by rule: each English flags the other dialect's spellings (`colour` in en-US; `color`, `center`, `analyze` in en-GB; `organise` in en-CA), British English accepts `-ize` and `-ise` (Oxford spelling), and a dialect's form of a known word is right even if the list lacks it (`realisation`). No system dictionary needed | the dialect's own spelling first (`colour` → `color`), then edit distance with the shared suggestions in the dialect's spelling | repeated word, `a`/`an`, sentence capital, space before punctuation, double space | Moby dictionary, our Liang patterns, heuristic |
| English: American (`en-US`, other regions, text with no language), British spelling (`en-GB`, `en-AU`, `en-NZ`, `en-IE`, `en-ZA`, `en-IN`…), Canadian (`en-CA`) | SCOWL 2026 (`rel-2026.02.25`, size 60) Hunspell dictionaries, one per English: en-US, en-GB `-ise` (also the other British-spelling Englishes) and en-CA, embedded from craft-i18n `language-data/` and read by the affix engine (ordinals such as `21st` and `112th` by `COMPOUNDRULE`). A word is right when the English's own dictionary or our supplement (`en-extra.txt`) knows it (never because another English's does: `colourblind` is wrong in en-US), unless our list of ~280 American/British pairs (craft-i18n [`language-data/en-us/en-variants.txt`](https://github.com/storytold/craft-i18n/blob/main/language-data/en-us/en-variants.txt)) marks it as the other dialect's: each English flags the other dialect's spellings (`colour` in en-US; `color`, `center`, `analyze` in en-GB; `organise` in en-CA), British English accepts `-ize` and `-ise` (Oxford spelling, as Word does; SCOWL's en-GB `-ise` alone would flag `organize`), and a dialect's form of a known word is right even if the list lacks it (`realisation`). Text with no language takes any English's word. An English Hunspell dictionary in File › Options › Proofing › Dictionaries folder comes first (the document's own English); without the SCOWL files, an installed Hunspell English, then the Moby word list (public domain, ~165k words) built into craft-proof. No system dictionary needed | the dialect's own spelling first (`colour` → `color`), then the dialect's SCOWL dictionary's suggestions (its TRY/REP tables, one typo, a stem scan; a missing space only between two words of 3+ letters, last), in the dialect's spelling | repeated word, `a`/`an`, sentence capital, space before punctuation, double space | Moby dictionary, our Liang patterns, heuristic |
| Russian (`ru`) | A Russian Hunspell dictionary installed on the system (`ru_RU` from the OS, a package manager, LibreOffice's `dict-ru` or the `WORDCRAFT_DICTIONARIES` folder; UTF-8, KOI8-R or Windows-1251; not bundled, so no Russian spelling marks without it), read by the same affix engine; `ё` optional (`елка`/`ёлка`, `еще`/`ещё`); hyphenated words whole, then by parts (`кто-то`, `по-русски`, `кое-где`, `северо-западный`, `ИИ-консультант`); solid compounds (`высокоэластичный`), `не` with adjectives, participles and verbal nouns (not verbs), productive prefixes (`ультра-`, `эко-`) and prefixed verbs; abbreviations with endings (`ГИПа`) and camel case left alone; our supplement of ~200 modern words with their declensions (craft-i18n [`language-data/ru/ru-extra.txt`](https://github.com/storytold/craft-i18n/blob/main/language-data/ru/ru-extra.txt): `маркетплейс`, `промокод`, `интеграция`, `колеровать`) | `ё`/`е` first, then slips within letter groups (unstressed vowels, voiced and voiceless pairs, `ь`/`ъ`), the common confusions (`жы`, `чя`, `тся`/`ться`, doubled consonants, unpronounced consonants: `здраствуй` → `здравствуй`), a missing space (`незнаю` → `не знаю`; not a preposition before a verb), one typo, then a stem scan | Russian messages: repeated word, space before punctuation, double space, sentence capital (knows `т. е.`, `г.`, `руб.`, `ул.`, initials, numbers, dialogue dashes), possibly missing comma before `что`/`чтобы`/`если`/`хотя`/`поскольку`/`который` and before `потому что` (not after conjunctions and particles such as `и`, `только`, `даже`, `так`, `для того`; not after a preposition; not in `хотя бы`, `что-то`), doubled punctuation | The rules of Russian word division as code (no pattern file): a vowel on each side, two letters at least, `ь`/`ъ`/`й` kept with the letter before, a break after `ъ`, a consonant cluster divided after its first consonant |
| Polish (`pl`) | The Hunspell `pl_PL` dictionary installed on the system (OS package, Homebrew, LibreOffice, the folder set in File › Options › Proofing › Dictionaries folder, or `WORDCRAFT_DICTIONARIES`; not bundled, so no Polish spelling marks without it; the same pane shows which file each language found), read at runtime by a Hunspell-style affix engine (craft-proof [`src/affix.rs`](https://github.com/storytold/craft-libs/blob/main/crates/proof/src/affix.rs) in craft-libs); names capitalized, compounds part by part, `Kennedy'ego` | missing diacritics first (`zolw` → `żółw`), the dictionary's confusion table (`żeka` → `rzeka`, `chuśtawka` → `huśtawka`), missing space (`napewno` → `na pewno`), one typo, then a stem scan within two typos | Polish messages: repeated word, space before punctuation, double space, sentence capital (knows `np.`, `r.`, initials, ordinals, dialogue dashes), missing comma before `że`/`który`/`ponieważ`/`gdyż`/`aby`/`żeby`/`jeśli`/`jeżeli`/`gdyby`/`lecz` (not after `mimo`, `chyba`, `tak`, prepositions…), `we`/`ze` (`we wtorek`, `ze szkoły`), doubled punctuation | TeX Polish patterns (Kołodziejska, Jackowski, Ryćko; MIT option) with their 20 exception words; a Polish syllable heuristic for letters outside the alphabet |
| Portuguese (`pt`, any region) | The Hunspell `pt_BR` dictionary installed on the system — VERO and its derivatives (same places as Polish; not bundled, LGPL/MPL), read at runtime by the same affix engine, which reads its `FLAG UTF-8`, 106 flags, continuation classes and `FORBIDDENWORD` spellings; names capitalized, compounds part by part (`guarda-roupa`, `ex-marido`) | missing accents first (`coraçao` → `coração`, `saude` → `saúde`), the dictionary's confusion table (`seje` → `seja`, `excessão` → `exceção`), missing space (`nãoé` → `não é`), one typo, then an accent-folding stem scan | Portuguese messages: repeated word (the emphatic doubles are allowed), space before punctuation, double space, sentence capital (knows `etc.`, `pág.`, `Dr.`, initials, ordinals, dialogue dashes), doubled punctuation; no comma rule — `que` opens a clause only sometimes | TeX Portuguese patterns (Rezende, Almeida, Araujo, Benevides; BSD 3-clause) with their 2 exception words |
@@ -227,6 +227,7 @@ WordCraft keeps 2,54 cm).
| Date | Change | Summary |
|---|---|---|
| 2026-11-01 | minor | English spelling reads SCOWL 2026 per English (en-US, en-GB and the British-spelling Englishes, en-CA) through the affix engine, ordinals included; `en-variants.txt` still sets each dialect's policy; Moby is the fallback and the hyphenation list (CP2, #40, #520, #1281, #1045) |
| 2026-11-01 | trivial | Proofing paths updated for the move: the affix engine is craft-proof's `src/affix.rs` in storytold/craft-libs, the English variants and Russian supplement are craft-i18n `language-data/` files (#5202). |
| 2026-10-28 | trivial | Traditional Chinese interface: an installed Traditional Chinese font (PingFang TC, Microsoft JhengHei, Noto Sans CJK TC; the TC face of a pan-CJK collection) goes before the embedded Noto Sans CJK SC, whose mainland glyph shapes looked wrong to Taiwan readers; native only, wasm unchanged; estimates unchanged |
| 2026-10-24 | minor | Preserved “Delete Around Caret in Equation” in all 27 shared WordCraft catalogs; the native/release pin and Flatpak source advance together. |
+2 -1
View File
@@ -1,6 +1,6 @@
# Turkish interface
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-23 · **Change:** trivial (the catalog moved to storytold/craft-i18n, `locales/tr/wordcraft.tsv`; previously trivial: interface-language tests: a missing translation never fails a test, `cargo xtask i18n-report` in `cargo xtask ci` prints the strings each language lacks, and lookup and template tests use inline fixture catalogs or the pseudo-language; previously minor: Turkish interface catalog completed, 2,325 entries, #774; previously minor: Turkish interface catalog and regression checks) · **Target:** WordCraft 0.5.0
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-11-01 · **Change:** trivial (Turkish proofing's code is craft-proof's `crates/proof/src/tr` in storytold/craft-libs, #5202; previously trivial: the catalog moved to storytold/craft-i18n, `locales/tr/wordcraft.tsv`; previously trivial: interface-language tests: a missing translation never fails a test, `cargo xtask i18n-report` in `cargo xtask ci` prints the strings each language lacks, and lookup and template tests use inline fixture catalogs or the pseudo-language; previously minor: Turkish interface catalog completed, 2,325 entries, #774; previously minor: Turkish interface catalog and regression checks) · **Target:** WordCraft 0.5.0
Choose **File › Options › Interface language › Türkçe**, or follow a Turkish system display language
(`tr-TR`, `tr-CY`, `tr_TR.UTF-8`). The catalog code is `tr`; `ui.language` with `{"value":"tr"}`
@@ -60,6 +60,7 @@ checks (reduplications, conjunction commas, capitalization), and syllable hyphen
| Date | Change | Summary |
|---|---|---|
| 2026-11-01 | trivial | Turkish proofing's code moved with craft-proof to storytold/craft-libs (`crates/proof/src/tr`); its path here says so (#5202) |
| 2026-10-23 | trivial | The catalog moved to storytold/craft-i18n (`locales/tr/wordcraft.tsv`) |
| 2026-10-23 | trivial | Lookup, context, template, style-name and command-search tests use inline fixture catalogs or the pseudo-language; tests that asserted one language's catalog wording removed |
| 2026-10-23 | trivial | Interface-language tests: a missing translation falls back to English and never fails a test; `cargo xtask i18n-report` (part of `cargo xtask ci`) prints the strings each language lacks; single-language coverage tests removed |
+15 -1
View File
File diff suppressed because one or more lines are too long
@@ -126,6 +126,6 @@ modules:
# the two equal).
- type: git
url: https://github.com/storytold/craft-i18n
commit: 062a6375c322c88b96691a17f7b5fed71c51f7a8
commit: 059cbf95c2a3eb95d637ca8584faca1129d17f48
dest: craft-i18n
- cargo-sources.json