CP2.2: review — British English takes an -ize spelling only when en-US or en-CA spells the word so

craft-libs#483 re-review (P2): ise_spelling turned any z between i/y and a
vowel into s, so en-GB (and the other British Englishes) accepted
misspellings whose -s- form is a word: wize, rize, noize, dizease, advize,
surprize, exercize… (19 reproduced; Hunspell en-GB rejects them all). The
-ize form now counts only when the word itself is in the en-US or en-CA
SCOWL dictionary and its -ise form in en-GB's (organize, realization,
colourize). English with no dialect no longer needs the swap (it reads all
three). Test: british_ize_needs_a_real_ize_word (the 19, plus colorize, wrong
in en-GB and en-AU; organize, realization, colourize, organizing, realizes
right).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
This commit is contained in:
Martin BallandClaude Opus 5.5 committed 2026-11-01 22:21:02 +00:00
1 parent 0675d58341
commit 6e45fda67c
4 files changed
+44 -9

No files matched your search

+2 -2
View File
@@ -74,8 +74,8 @@ English spelling uses the first of these that is there; `english_source(lang)` s
dictionary knows it (or `en-extra.txt` does), never because another English's does
(`colourblind` is wrong in en-US, `colorblind` in en-GB); suggestions come from the same
dictionary. SCOWL's size-60 lists keep one spelling per dialect, and Word accepts more, so
British English also takes the `-ize` spellings of its `-ise` words (`organize`,
`realization`), and `en-variants.txt` flags the other dialect's spellings and accepts this
British English also takes the `-ize` spellings of its `-ise` words that American or Canadian
English spell so (`organize`, `realization`; never `wize` or `advize`), and `en-variants.txt` flags the other dialect's spellings and accepts this
dialect's other spellings of known words (`judgement` in en-US). English with no dialect
(`is_correct`) takes a word any of the three knows. Suggestions offer a missing space only
between two lower-case words of three letters or more, after every one-word candidate, and no
+18 -4
View File
@@ -290,7 +290,7 @@ fn generic(s: Speller) -> Speller {
match s {
Speller::Scowl(..) => {
let all: Vec<_> = [ProofLang::En, ProofLang::EnGb, ProofLang::EnCa].into_iter().filter_map(crate::scowl::dict).collect();
Speller::Scowl(all, true)
Speller::Scowl(all, false)
}
other => other,
}
@@ -301,7 +301,12 @@ impl Speller {
fn knows(&self, w: &str) -> bool {
match self {
Speller::Hunspell(d, _) => affix_correct(&[d.as_ref()], w, false),
Speller::Scowl(ds, ise) => affix_correct(ds, w, true) || (*ise && ise_spelling(w).is_some_and(|x| affix_correct(ds, &x, true))),
Speller::Scowl(ds, ise) => {
affix_correct(ds, w, true)
|| (*ise
&& ise_spelling(w).is_some_and(|x| affix_correct(ds, &x, true))
&& ize_elsewhere(w, |d, p| affix_correct(&[d], p, false)))
}
Speller::List => list_correct(w),
}
}
@@ -310,7 +315,9 @@ impl Speller {
fn knows_lower(&self, p: &str) -> bool {
match self {
Speller::Hunspell(d, _) => d.check(p),
Speller::Scowl(ds, ise) => ds.iter().any(|d| d.check(p) || (*ise && ise_spelling(p).is_some_and(|x| d.check(&x)))),
Speller::Scowl(ds, ise) => {
ds.iter().any(|d| d.check(p) || (*ise && ise_spelling(p).is_some_and(|x| d.check(&x)) && ize_elsewhere(p, |d, p| d.check(p))))
}
Speller::List => crate::known_in_word_list(p),
}
}
@@ -339,7 +346,8 @@ pub(crate) fn is_correct(word: &str, lang: ProofLang, opts: &Options, policy: bo
/// `w` with its `-ize`/`-yze` endings (and their forms: `-ization`, `-izing`…) spelled `-ise`/
/// `-yse`, when it has any: British English takes both (Word accepts `organize` and `organise` in
/// en-GB), and SCOWL's en-GB dictionary has only `-ise`. A `z` between `i`/`y` and a vowel is
/// swapped (`citizen` → `citisen`, which no dictionary knows, so that does no harm).
/// swapped; the `-ize` form counts only when American or Canadian English spells the word so
/// ([`ize_elsewhere`]), or `wize` would pass as `wise`.
pub(crate) fn ise_spelling(w: &str) -> Option<String> {
let b = w.as_bytes();
let mut out = b.to_vec();
@@ -361,6 +369,12 @@ pub(crate) fn ise_spelling(w: &str) -> Option<String> {
if changed { String::from_utf8(out).ok() } else { None }
}
/// Is `w` a word in American or Canadian English's SCOWL dictionary (`check` asks one): the
/// `-ize` spellings British English takes are theirs (`organize`, never `advize` or `wize`).
fn ize_elsewhere(w: &str, check: impl Fn(&AffixDict, &str) -> bool) -> bool {
[ProofLang::En, ProofLang::EnCa].into_iter().filter_map(crate::scowl::dict).any(|d| check(d, w))
}
/// Against affix dictionaries (any of them): the word, or each part of a hyphenated one; with
/// `supplement`, our supplement's words count too.
fn affix_correct(ds: &[&AffixDict], w: &str, supplement: bool) -> bool {
+20
View File
@@ -1781,6 +1781,26 @@ mod tests {
}
}
/// craft-libs#483 re-review: British English takes the `-ize` spelling of an `-ise` word only
/// when American or Canadian English spells it so; a misspelling whose `-s-` form is a word
/// (`wize`, `advize`) stays wrong, as in Hunspell's en-GB.
#[cfg_attr(not(craft_proof_data), ignore = "needs the Language data (CRAFT_I18N_DIR)")]
#[test]
fn british_ize_needs_a_real_ize_word() {
let wrong = [
"wize", "rize", "noize", "dizease", "advize", "rizing", "praize", "raize", "poize", "wizer", "surprize", "arize", "revize", "devize",
"mizer", "concize", "precize", "exercize", "chaize",
];
for l in [ProofLang::EnGb, ProofLang::from_tag(Some("en-AU"))] {
for w in wrong.iter().chain(&["colorize"]) {
assert!(!is_correct_in(w, l), "{w} in {l:?}");
}
for w in ["organize", "realization", "colourize", "organizing", "realizes"] {
assert!(is_correct_in(w, l), "{w} in {l:?}");
}
}
}
#[cfg_attr(not(craft_proof_data), ignore = "needs the Language data (CRAFT_I18N_DIR)")]
#[test]
fn user_dictionary_accepts_the_other_dialects_spelling() {
+4 -3
View File
@@ -7,9 +7,10 @@
//! come from its own dictionary, and a word is right when its own dictionary knows it: the other
//! dialects' dictionaries are never asked (en-US would take `colourblind` from en-GB's). SCOWL
//! picks one spelling per dialect (en-GB `-ise` has no `organize`, en-US no `judgement`), and Word
//! accepts more, so British English also takes the `-ize` spellings of its `-ise` words, and
//! `en-variants.txt` widens each dialect by its pairs (`crate::english`). An English dictionary in the dictionaries folder comes first; a SCOWL dictionary that isn't
//! embedded, or fails to load, leaves that English to the next source (`crate::english`).
//! accepts more, so British English also takes the `-ize` spellings of its `-ise` words that
//! en-US or en-CA spells so, and `en-variants.txt` widens each dialect by its pairs
//! (`crate::english`). An English dictionary in the dictionaries folder comes first; a SCOWL
//! dictionary that isn't embedded, or fails to load, leaves that English to the next source (`crate::english`).
//!
//! SCOWL is under its own permissive licence and the affix files under Ispell's BSD licence;
//! [`notice`] is the upstream text, for an About window.