From 9614ab270dee95413f51c14a3bf889d1b696445a Mon Sep 17 00:00:00 2001 From: Martin Ball Date: Sun, 1 Nov 2026 22:21:46 +0000 Subject: [PATCH] =?UTF-8?q?CP6.13:=20hyphen.rs=20=E2=80=94=20a=20Turkish?= =?UTF-8?q?=20word=20with=20a=20suffix=20after=20an=20apostrophe=20(Ankara?= =?UTF-8?q?'dan)=20is=20hyphenated=20by=20the=20Turkish=20rules,=20part=20?= =?UTF-8?q?by=20part,=20not=20as=20English=20(CodeRabbit=20on=20craft-libs?= =?UTF-8?q?#484/#489)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2 --- crates/proof/src/hyphen.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/crates/proof/src/hyphen.rs b/crates/proof/src/hyphen.rs index e3c89daa..6bc804b2 100644 --- a/crates/proof/src/hyphen.rs +++ b/crates/proof/src/hyphen.rs @@ -148,8 +148,16 @@ fn core_breaks(core: &[char], lang: ProofLang) -> (Vec, Source) { if lang == ProofLang::Bg && core.iter().all(|&c| crate::bg::is_letter(c)) { return (crate::bg::points(core), Source::Rules); } - if lang == ProofLang::Tr && core.iter().all(|&c| crate::tr::hyphen::is_letter(c)) { - return (crate::tr::hyphen::points(core), Source::Rules); + // A suffix written after an apostrophe (`Ankara'dan`, `Türkiye'nin`) is hyphenated part by + // part; no break goes next to the apostrophe ([`word_breaks_in`] drops those). + if lang == ProofLang::Tr && core.iter().all(|&c| c == '\'' || crate::tr::hyphen::is_letter(c)) { + let mut out = Vec::new(); + let mut start = 0; + for part in core.split(|&c| c == '\'') { + out.extend(crate::tr::hyphen::points(part).into_iter().map(|p| p + start)); + start += part.len() + 1; + } + return (out, Source::Rules); } match lang { ProofLang::Pt => return core_breaks_patterns(Patterns::pt(), core), @@ -526,6 +534,18 @@ fn heuristic_points_pl(c: &[char]) -> Vec { mod tests { use super::*; + /// CodeRabbit on craft-libs#484: a Turkish word with a suffix after an apostrophe is + /// hyphenated by the Turkish rules, part by part, never next to the apostrophe. + #[test] + fn turkish_apostrophe_suffixes_follow_turkish_rules() { + let tr = |w: &str| hyphenate_word_in(w, &Limits::default(), ProofLang::Tr); + assert_eq!(tr("Ankara'dan"), "An-ka-ra'dan"); + assert_eq!(tr("Türkiye'nin"), "Tür-ki-ye'nin"); + assert_eq!(tr("İstanbul'daki"), "İs-tan-bul'da-ki"); + assert_eq!(word_breaks_in("Ankara'dan", ProofLang::Tr).1, Source::Rules); + assert_eq!(tr("Ankara"), "An-ka-ra", "no apostrophe: as before"); + } + fn h(w: &str) -> String { hyphenate_word(w, &Limits::default()) }