Her apostrophe was cutting French words in half
Typography.ts rewrites every ' typed in the editor into a curly ’, but both word regexes only counted the straight one. So "aujourd’hui" reached the dictionary as "aujourd" + "hui", neither of them a French word, and one of the commonest words in the language came back wearing two red underlines. Same for quelqu’un, presqu’île, prud’homme. l’arbre only survived by accident, because "l" happens to be a bare entry. withElision, written for exactly this, could only ever fire on pasted text. Both marks are word characters now, and combine() straightens on lookup — the one place every lookup passes through — since the shipped word lists spell theirs straight. Suggestions come back wearing whichever mark she actually used, so accepting a pill never swaps her apostrophe. œ was untokenizable too: U+0152/U+0153 sit outside the Latin-1 ranges, so "cœur" split into "c" + "ur" and the orphan was long enough to underline. 586 œ forms ship in fr.dic.gz and not one of them was reachable. In the dictionary builder, the two cross-product paths added their forms without the NEEDAFFIX check the single-affix paths apply, so a doubly-affixed form that is still "not a word on its own" was accepted anyway — the exact class of error the FLAG-aware rewrite exists to close. PFX and SFX are also separate flag namespaces, and one shared `cross` dict let the second block overwrite the first. Odd-length long-flag strings now stop the build instead of dropping a character and expanding through the wrong paradigm. The pt-PT and Québécois greps were case-sensitive against sentence-cased copy, which let a leading "Actualmente…" through the guard added to catch it. Note: this changes what the expander produces, but fr.dic.gz and pt-PT.dic.gz are vendored and were built with the old behaviour. Both want regenerating on a box that can fetch the upstream .deb, and BUILD_PLAN Phase 24's "pt-PT rebuild is byte-identical" claim re-checked — if those bytes move, the NEEDAFFIX gap was live in the Portuguese list too. Claude-Session: https://claude.ai/code/session_016y6gyuHkQXPiEuW8RGQyua
This commit is contained in:
@@ -252,6 +252,19 @@ export function interleave(lists: string[][]): string[] {
|
||||
return out
|
||||
}
|
||||
|
||||
// Typography.ts turns every apostrophe typed in the editor into a curly U+2019,
|
||||
// and every word list Petal ships spells its apostrophes straight ("aujourd'hui",
|
||||
// "don't", and the elision heads in FR_ELISION). Normalising here — the one place
|
||||
// every lookup passes through — keeps that a rendering detail rather than a
|
||||
// spelling one; corrections come back wearing whichever mark she actually used,
|
||||
// so accepting a pill never swaps her curly apostrophe for a straight one.
|
||||
const CURLY_APOSTROPHE = /’/g
|
||||
const STRAIGHT_APOSTROPHE = /'/g
|
||||
|
||||
function straighten(word: string): string {
|
||||
return word.replace(CURLY_APOSTROPHE, "'")
|
||||
}
|
||||
|
||||
// combine is the both-dictionaries rule itself, separated from the loading so it
|
||||
// can be reasoned about (and tested) on its own. `dicts` is a getter because the
|
||||
// writer's dictionary lands after English and the checker must see it when it
|
||||
@@ -266,9 +279,14 @@ export function combine(dicts: () => Loaded[]): SpellChecker {
|
||||
correct: (w) => {
|
||||
const loaded = dicts()
|
||||
if (loaded.length === 0) return true
|
||||
return loaded.some((d) => d.spell.correct(w))
|
||||
const word = straighten(w)
|
||||
return loaded.some((d) => d.spell.correct(word))
|
||||
},
|
||||
suggest: (w) => {
|
||||
const word = straighten(w)
|
||||
const out = interleave(dicts().map((d) => d.spell.suggest(word)))
|
||||
return word === w ? out : out.map((s) => s.replace(STRAIGHT_APOSTROPHE, '’'))
|
||||
},
|
||||
suggest: (w) => interleave(dicts().map((d) => d.spell.suggest(w))),
|
||||
// A getter, not a snapshot. The alphabet is read by every surface that
|
||||
// resolves a word, and if it were captured when the checker was built it
|
||||
// would still say A-Z after her dictionary arrived — so a pt-PT writer's
|
||||
|
||||
Reference in New Issue
Block a user