* #835: AutoCorrect's English replacement list applies only to English text Built-in word entries (teh, i, dont…) are replaced only when the word's language (run w:lang, style, document default) is English or unset; symbols, fractions and user entries apply in every language. Polish, Croatian, Bosnian and Serbian "i" ("and") is no longer turned into "I". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * #835 review: untagged text follows the editing language; English as proofing decides it - Text with no language at all (a .docx without w:lang) is in the editing language, so with a Polish interface `Ala i kot ` keeps its `i` there too. - `wordcraft_proof::ProofLang::from_tag` decides what is English (it also takes `eng`), so AutoCorrect and proofing agree; the local `is_english` is gone. - Tests through `set_editing_language` (the document-default path) and with no language at all. - docs/typing-parity.md: the Croatian/Bosnian/Serbian case needs the text tagged, as those interfaces set no editing language yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
parent
7d37b14679
commit
c9079196db
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
**Stage: alpha** · next: beta, ~15 points (60% → 75% ready for real work) and ~150–230 h away
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** trivial (Turkish interface catalog completed, #774; previously trivial: Turkish interface catalog completed, #774; previously trivial: Hungarian interface landed; previously trivial: independent complex-script formatting preserved across DOCX open/save; previously trivial: sorting and table numbers follow the text's language, #836, #837; previously minor: Polish interface and Polish proofing; previously trivial: Turkish interface landed; previously trivial: formatting revisions landed, #41; previously trivial: Draw tab ink, #307, and Draw Table and Eraser, #303, landed: catalog 402/434; previously minor: readiness table with hours per audience; full number back to the additive weighted sum, 60%; mainstream and essentials numbers added; alpha gate checked; previously major: full re-measure against Word for Mac 16.113.4; restructured to the craftrules progress-docs standard) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** trivial (Turkish interface catalog completed, #774; previously trivial: Turkish interface catalog completed, #774; previously trivial: Hungarian interface landed; previously trivial: Quick Access Toolbar KeyTips and a saved enable/disable option, #620; previously trivial: new documents follow the system region, #838; previously minor: Polish interface and Polish proofing; previously trivial: table borders and the resize handle drag on the page, #217; previously trivial: formatting revisions landed, #41; previously trivial: Draw tab ink, #307, and Draw Table and Eraser, #303, landed: catalog 402/434; previously minor: readiness table with hours per audience; full number back to the additive weighted sum, 60%; mainstream and essentials numbers added; alpha gate checked; previously major: full re-measure against Word for Mac 16.113.4; restructured to the craftrules progress-docs standard) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
|
||||
|
||||
WordCraft aims for complete parity with Microsoft Word, then goes further on speed, openness and
|
||||
agent control. This page is the summary; the assessment is
|
||||
|
|
@ -132,6 +132,7 @@ Ranked, to beta (detail and remaining milestones in [docs/roadmap.md](docs/roadm
|
|||
## Progress log
|
||||
|
||||
| Date | What landed |
|
||||
| 2026-10-12 | AutoCorrect keys its built-in English replacement list by language (#835): Polish, Croatian, Bosnian and Serbian `i` ("and") is no longer turned into `I`; English and untagged text unchanged |
|
||||
|---|---|
|
||||
| 2026-10-12 | Ribbon groups fit above their labels: View › Show splits its four check boxes into two columns (Hide White Space, #645, had pushed the fourth onto the "Show" label), Developer › Controls loses the gaps that ran into its label, and Layout › Paragraph (#654) no longer trips a debug assertion and sits 2.5 pt higher; a test draws every tab in every language and fails on any group taller than the ribbon |
|
||||
| 2026-10-12 | Window caption: a non-Latin file name is drawn with a document fallback face (or the CJK UI font), instead of `?` |
|
||||
|
|
@ -250,6 +251,7 @@ Ranked, to beta (detail and remaining milestones in [docs/roadmap.md](docs/roadm
|
|||
| 2026-10-12 | trivial | Progress log: new documents follow the system region (#838) |
|
||||
| 2026-10-11 | trivial | DOCX complex-script formatting inheritance fix and round-trip coverage |
|
||||
| 2026-10-11 | minor | Czech (`cs`) interface catalog added |
|
||||
| 2026-10-12 | trivial | Progress log: AutoCorrect replacement list follows the text's language (#835) |
|
||||
| 2026-10-11 | trivial | Progress log: German interface (#574) |
|
||||
| 2026-10-12 | trivial | Progress log: language-aware sorting and table numbers (#836, #837) |
|
||||
| 2026-10-12 | trivial | Progress log: Word 365 cover pages (#743) |
|
||||
|
|
|
|||
|
|
@ -60,6 +60,11 @@ pub const AUTOCORRECT: &[(&str, &str)] = &[
|
|||
("3/4", "¾"),
|
||||
];
|
||||
|
||||
/// A built-in entry that is an English word (letters and apostrophes only), not a symbol.
|
||||
fn is_english_entry(from: &str) -> bool {
|
||||
from.chars().any(char::is_alphabetic) && from.chars().all(|c| c.is_alphabetic() || c == '\'')
|
||||
}
|
||||
|
||||
/// Compare and Combine take the same settings.
|
||||
const COMPARE_PARAMS: &str = r#"{"path"?: string (revised document), "text"?: string (revised text), "original"?: string (original document; default: this one), "author"?: string (label changes with), "caseChanges"?: bool, "whiteSpace"?: bool, "formatting"?: bool (default true: differences count), "level"?: "word|character", "showIn"?: "original|revised|new" (revised/new: an untitled document), "moves"|"comments"|"tables"|"headersFooters"|"footnotes"|"textBoxes"|"fields"?: bool (accepted; not honoured yet except tables, always compared)}"#;
|
||||
|
||||
|
|
@ -162,14 +167,23 @@ impl AutoCorrectPrefs {
|
|||
self
|
||||
}
|
||||
|
||||
/// The replacement for `word`, if any: the user's entry, else a built-in one not deleted.
|
||||
/// Built-in lowercase entries also match a capitalised word ("Teh" → "The").
|
||||
/// The replacement for `word` in English text, if any: the user's entry, else a built-in
|
||||
/// one not deleted. Built-in lowercase entries also match a capitalised word ("Teh" → "The").
|
||||
pub fn replacement(&self, word: &str) -> Option<String> {
|
||||
self.replacement_in(word, true)
|
||||
}
|
||||
|
||||
/// The replacement for `word` in text that is (`english`) or isn't English: the built-in
|
||||
/// English words ("teh", "i", "dont") apply only to English text, as Word keeps a list per
|
||||
/// language (#835: Polish "i" means "and"); symbols, fractions and the user's entries apply
|
||||
/// whatever the language.
|
||||
pub fn replacement_in(&self, word: &str, english: bool) -> Option<String> {
|
||||
if let Some((_, b)) = self.entries.iter().find(|(a, _)| a == word) {
|
||||
return Some(b.clone());
|
||||
}
|
||||
AUTOCORRECT
|
||||
.iter()
|
||||
.filter(|(a, _)| english || !is_english_entry(a))
|
||||
.filter(|(a, _)| !self.removed.iter().any(|r| r == a) && !self.entries.iter().any(|(e, _)| e == a))
|
||||
.filter(|(a, _)| self.fractions || !FRACTIONS.contains(a))
|
||||
.find(|(a, _)| {
|
||||
|
|
@ -779,7 +793,15 @@ pub fn autocorrect_word(s: &mut Session, on_enter: bool) -> Result<(), CmdError>
|
|||
word = format!("{}{fixed}{}", word.get(..at).unwrap_or(""), word.get(at + letters.len()..).unwrap_or(""));
|
||||
}
|
||||
// A whole-word replacement, else "wait..." → "wait…".
|
||||
let found = if ac.replace_text { ac.replacement(&word) } else { None };
|
||||
// The word's language (run, paragraph style, document default) picks the list (#835).
|
||||
// Text with no language at all is in the editing language (a Polish interface writes Polish),
|
||||
// else English. Proofing decides what is English the same way.
|
||||
let english = s.doc.para_at(&f).is_none_or(|p| {
|
||||
let rc = s.doc.styles.resolve_char(p.props.style.as_deref(), p.props_of_char(start));
|
||||
let lang = rc.lang.as_deref().or(s.editing_lang.as_deref());
|
||||
wordcraft_proof::ProofLang::from_tag(lang) == wordcraft_proof::ProofLang::En
|
||||
});
|
||||
let found = if ac.replace_text { ac.replacement_in(&word, english) } else { None };
|
||||
let (from, rep) = match found {
|
||||
Some(r) => (start, Some(r)),
|
||||
None if ac.replace_text && word.len() > 3 && word.ends_with("...") => (start + word.len() - 3, Some("…".to_string())),
|
||||
|
|
|
|||
|
|
@ -188,6 +188,48 @@ fn autocorrect_as_you_type() {
|
|||
assert_eq!(s.doc.plain_text(StoryRef::Body), "½ cup. iPhone. See readme.txt ");
|
||||
}
|
||||
|
||||
/// #835: the English replacement list applies only to English text. Polish "i" ("and") stays
|
||||
/// lowercase; symbols still change; English and untagged text still get "I".
|
||||
#[test]
|
||||
fn autocorrect_replacement_list_follows_the_texts_language() {
|
||||
// Polish as the document's default language.
|
||||
let mut s = s();
|
||||
run(&mut s, "review.language", json!({"lang": "pl-PL", "default": true}));
|
||||
typ(&mut s, "Ala i kot. kawa i herbata teh (c) ");
|
||||
assert_eq!(s.doc.plain_text(StoryRef::Body), "Ala i kot. Kawa i herbata teh © ");
|
||||
// Polish on the run only: the word's own language counts.
|
||||
let mut s = self::s();
|
||||
typ(&mut s, "Ala");
|
||||
run(&mut s, "select.all", json!({}));
|
||||
run(&mut s, "review.language", json!({"lang": "pl-PL"}));
|
||||
run(&mut s, "caret.docEnd", json!({}));
|
||||
typ(&mut s, " i kot ");
|
||||
assert_eq!(s.doc.plain_text(StoryRef::Body), "Ala i kot ");
|
||||
// English (any region) and untagged text (the default proofing language is English).
|
||||
let mut s = self::s();
|
||||
run(&mut s, "review.language", json!({"lang": "en-GB", "default": true}));
|
||||
typ(&mut s, "so i think teh end ");
|
||||
assert_eq!(s.doc.plain_text(StoryRef::Body), "So I think the end ");
|
||||
let s = typed("so i think teh end ");
|
||||
assert_eq!(s.doc.plain_text(StoryRef::Body), "So I think the end ");
|
||||
// A Polish interface: a new document is Polish by its default language, and text with no
|
||||
// language at all (a .docx without `w:lang`) follows the editing language too.
|
||||
let mut s = self::s();
|
||||
s.set_editing_language(Some("pl-PL"));
|
||||
typ(&mut s, "Ala i kot ");
|
||||
assert_eq!(s.doc.plain_text(StoryRef::Body), "Ala i kot ", "document default from the editing language");
|
||||
let mut s = self::s();
|
||||
s.set_editing_language(Some("pl-PL"));
|
||||
s.doc.styles.default_chr.lang = None;
|
||||
typ(&mut s, "Ala i kot ");
|
||||
assert_eq!(s.doc.plain_text(StoryRef::Body), "Ala i kot ", "untagged text in the editing language");
|
||||
// `eng` is English too, as for proofing.
|
||||
let mut s = self::s();
|
||||
run(&mut s, "review.language", json!({"lang": "eng", "default": true}));
|
||||
typ(&mut s, "so i think ");
|
||||
assert_eq!(s.doc.plain_text(StoryRef::Body), "So I think ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn autocorrect_options_change_what_typing_does() {
|
||||
let mut s = s();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Typing parity with Word
|
||||
|
||||
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-12 · **Change:** minor (Correct TWo INitial CApitals, cAPS LOCK and table-cell capitals, #544; previously trivial: complex-script caret and Backspace, #604; Move Paragraph Up/Down, Promote/Demote, Go Back and Alt+X keys, #343) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
|
||||
> **Last reviewed:** 2026-10-12 · **Last updated:** 2026-10-12 · **Change:** minor (Correct TWo INitial CApitals, cAPS LOCK and table-cell capitals, #544; previously minor: right-to-left letters typed into an empty paragraph make it right-to-left, #713; previously trivial: grammar proofing: ellipses are not sentence boundaries; previously minor: AutoCorrect's English replacement list applies only to English text, #835; previously trivial: complex-script caret and Backspace, #604; Move Paragraph Up/Down, Promote/Demote, Go Back and Alt+X keys, #343; previously trivial: outline keys in Outline view, #493) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4
|
||||
|
||||
What Word does when you type, observed black-box (same keystrokes typed into Word and
|
||||
WordCraft, results read back paragraph by paragraph) and pinned by tests in
|
||||
|
|
@ -99,6 +99,15 @@ Applied when a word is finished by a space, punctuation **or Enter** (`enter_fin
|
|||
numbered lists, border lines; user entries are added, replaced or deleted (built-in ones too),
|
||||
and "don't capitalize after" exceptions extend the abbreviation list. A replacement of several
|
||||
words takes a sentence capital on its first (`autocorrect_options_change_what_typing_does`).
|
||||
- The built-in replacement list is English: its words (`teh`, `i`, `dont`…) are replaced only
|
||||
in English text (the run's `w:lang`, then its style, then the document default; text with no
|
||||
language at all is in the editing language, so with a Polish interface a `.docx` without
|
||||
`w:lang` is Polish). English is decided as proofing decides it (`ProofLang`: `en`, `eng`).
|
||||
Polish `Ala i kot` keeps its `i` ("and"); symbols (`(c)`, `->`, `1/2`) and the user's own
|
||||
entries apply in every language (#835; `autocorrect_replacement_list_follows_the_texts_language`).
|
||||
Croatian, Bosnian and Serbian `i` is kept only when the text is tagged with that language: those
|
||||
interfaces don't set an editing language yet. Per-language lists for other languages aren't
|
||||
there yet (#735).
|
||||
|
||||
¹ From Word's documented AutoFormat and AutoCorrect options; not yet keystroke-compared with
|
||||
Word.
|
||||
|
|
@ -160,7 +169,9 @@ Word.
|
|||
|---|---|---|
|
||||
| 2026-10-12 | minor | AutoCorrect: Correct TWo INitial CApitals, accidental cAPS LOCK, capitalize first letter of table cells (#544) |
|
||||
| 2026-10-11 | minor | Text direction: right-to-left letters typed into an empty paragraph make it right-to-left; existing paragraphs keep theirs (#713) |
|
||||
| 2026-10-12 | trivial | AutoCorrect: untagged text follows the editing language; English decided as proofing does (#835 review) |
|
||||
| 2026-10-11 | trivial | Grammar proofing (not AutoCorrect) no longer suggests capitalising a sentence after `...` or `…` (`proof::tests::ellipses_do_not_start_sentences`) |
|
||||
| 2026-10-12 | minor | AutoCorrect: the English replacement list applies only to English (or untagged) text; Polish `i` stays (#835) |
|
||||
| 2026-10-11 | minor | AutoFormat tables from `+---+`, arrow bullets, smileys inside words, undo after a border line (#546) |
|
||||
| 2026-10-11 | trivial | Outline view keys: expand/collapse, Show Level, moving and promoting with collapsed content (#493) |
|
||||
| 2026-10-11 | minor | Editing options: typing replaces selection, overtype and the Insert key (#485) |
|
||||
|
|
|
|||
Loading…
Reference in New Issue