Skip non-English runs in proofing instead of flagging them (#100) (#741)

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
RegalDragoon200 2026-10-12 11:55:40 +02:00 committed by GitHub
parent b7aa7639a9
commit d4d28e01f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 67 additions and 0 deletions

View File

@ -125,6 +125,27 @@ fn reset_shortcuts_remove_direct_formatting_but_keep_styles() {
assert_eq!(text(&s), "Hello world—");
}
#[test]
fn non_english_runs_are_not_proofed() {
// #100: runs tagged with a proofing language that has no dictionary are skipped
// by both proofing paths; English still is proofed.
let mut s = s();
run(&mut s, "text.insert", json!({"text": "ąžuolas labas"}));
let before = run(&mut s, "review.issues", json!({}));
assert!(!before.as_array().map(|a| a.is_empty()).unwrap_or(true), "default language flags the words: {before}");
run(&mut s, "select.all", json!({}));
run(&mut s, "review.language", json!({"lang": "lt-LT"}));
let after = run(&mut s, "review.issues", json!({}));
assert_eq!(after, json!([]), "Lithuanian runs are skipped: {after}");
// English typos are still caught.
let mut e = Session::new(wordcraft_doc::Document::new());
run(&mut e, "text.insert", json!({"text": "Hello helo world"}));
let en = run(&mut e, "review.issues", json!({}));
assert_eq!(en.as_array().map(|a| a.len()).unwrap_or(0), 1, "English typo still flagged: {en}");
}
#[test]
fn typing_enter_undo() {
let mut s = s();

View File

@ -186,6 +186,19 @@ fn known_core(w: &str) -> bool {
false
}
/// Is there a proofing dictionary for this BCP 47 language tag? `None` (and empty tags) mean the
/// document default, which is en-US. Runs in a language without one are skipped (#100) instead
/// of flagging every word against another language's dictionary; see [`ProofLang::from_tag`].
pub fn has_dictionary(lang: Option<&str>) -> bool {
ProofLang::from_tag(lang) != ProofLang::Other
}
/// Is `word` spelled correctly in the run's proofing language? A language without a dictionary
/// can't be checked, so every word counts as correct (no red underlines for it).
pub fn is_correct_for(word: &str, lang: Option<&str>) -> bool {
is_correct_in(word, ProofLang::from_tag(lang))
}
/// Is `word` spelled correctly? Numbers, single letters, ALL-CAPS acronyms, URLs and words with
/// digits are accepted.
pub fn is_correct(word: &str) -> bool {
@ -688,6 +701,35 @@ mod tests {
assert!(is_correct("zxqwordcrafty"));
}
/// #100: runs are proofed when their language has a dictionary (the default language too)
/// and skipped otherwise.
#[test]
fn dictionary_lang_tags() {
for l in [None, Some(""), Some(" "), Some("en"), Some("en-US"), Some("en-GB"), Some("EN-us"), Some("en_US")] {
assert!(has_dictionary(l), "{l:?}");
}
for l in [Some("lt-LT"), Some("fr-FR"), Some("de"), Some("uk"), Some("es"), Some("-US"), Some("e")] {
assert!(!has_dictionary(l), "{l:?}");
}
// The gate follows the dictionaries, not English: every proofed language is proofed.
for d in ProofLang::PROOFED.map(ProofLang::code) {
assert!(has_dictionary(Some(d)), "{d}");
assert!(has_dictionary(Some(&format!("{}-XX", d.to_ascii_uppercase()))), "{d}");
}
}
/// #100: runs in a language without a dictionary are never flagged; English still is.
#[test]
fn non_english_words_are_not_flagged() {
for w in ["ąžuolas", "élève", "über", "labas", "bonjour"] {
assert!(is_correct_for(w, Some("lt-LT")), "{w}");
assert!(is_correct_for(w, Some("fr-FR")), "{w}");
}
assert!(!is_correct_for("helo", Some("en-US")), "English typos still flagged");
assert!(!is_correct_for("helo", None), "default language still proofed");
assert!(is_correct_for("hello", Some("en-US")));
}
/// File › Options › Proofing (#485): each "Ignore" choice turned off makes those words count.
#[test]
fn ignore_options_decide_what_is_checked() {
@ -757,6 +799,8 @@ mod tests {
let _ = check_spelling(&s);
let _ = check_grammar(&s);
let _ = suggest(&s, 3);
let _ = has_dictionary(Some(&s));
let _ = is_correct_for(&s, Some(&s));
let _ = hyphen::hyphen_points(&s, &hyphen::Limits::default());
for lang in [ProofLang::En, ProofLang::Pl, ProofLang::Other] {
let _ = check_spelling_in(&s, lang);

View File

@ -69,6 +69,7 @@ The same gaps grouped the way the parity documents are, for agents working in on
| Date | Change | Summary |
|---|---|---|
| 2026-10-11 | trivial | #8 narrowed: runs in a proofing language without a dictionary are skipped instead of flagged against the English dictionary (#100); dictionaries still English-only |
| 2026-10-11 | trivial | #16: DOCX open/save preserves independent complex-script formatting inheritance; RTL sections, tables and typography remain open |
| 2026-10-11 | trivial | `.doc` pictures, shapes and text boxes read (#551); gap #14 narrowed to the writer and Word 6/95 files |
| 2026-10-11 | trivial | Table column and row borders and the resize handle drag on the page (#217); UI/UX gap narrowed to the ruler's column markers |

View File

@ -251,6 +251,7 @@ can be used without committing Word output.
| Date | Change | Summary |
|---|---|---|
| 2026-10-11 | trivial | Proofing: runs in a language without a dictionary are skipped instead of flagged against the English dictionary (#100); no percentage change |
| 2026-10-11 | minor | Polish interface (13 UI languages) and Polish proofing with per-run languages: Proofing 35% → 40% (25–45 h → 20–40 h), Localization 25% → 27%; feature depth and readiness unchanged at this precision |
| 2026-10-11 | trivial | Tables: column and row borders and the resize handle drag on the page (#217); Tables row and interaction-fidelity evidence updated, no percentage change |
| 2026-10-11 | trivial | Review: Show revisions in balloons takes tracked deletions in the body out of the text into "Deleted: …" balloons (it drew like the comments-and-formatting mode before); Review row updated, no percentage change |