From d1cebf89eb8cb195b2127b8f403570587730f7cd Mon Sep 17 00:00:00 2001 From: Martin Ball Date: Sun, 1 Nov 2026 22:24:44 +0000 Subject: [PATCH] =?UTF-8?q?CP6.13:=20tr=20suggest=20=E2=80=94=20suggestion?= =?UTF-8?q?s=20in=20capitals=20use=20Turkish=20capitals=20(K=C4=B0TAP,=20n?= =?UTF-8?q?ot=20KITAP);=20three=20table=20entries=20that=20suggested=20the?= =?UTF-8?q?=20word=20itself=20are=20gone=20(CodeRabbit=20on=20craft-libs#4?= =?UTF-8?q?84/#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/tr/suggest.rs | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/crates/proof/src/tr/suggest.rs b/crates/proof/src/tr/suggest.rs index 08874420..4f8bd68d 100644 --- a/crates/proof/src/tr/suggest.rs +++ b/crates/proof/src/tr/suggest.rs @@ -28,12 +28,9 @@ const COMMON_REPLACEMENTS: &[(&str, &str)] = &[ ("sarmısak", "sarımsak"), ("makina", "makine"), ("ünvan", "unvan"), - ("rastlantı", "rastlantı"), ("labaratuvar", "laboratuvar"), ("laboratuar", "laboratuvar"), - ("kravat", "kravat"), ("gardolap", "gardırop"), - ("egzoz", "egzoz"), ("egzozt", "egzoz"), ("egsoz", "egzoz"), ("gelcen", "geleceksin"), @@ -258,10 +255,23 @@ pub fn turkish_to_lower(s: &str) -> String { out } +/// Turkish uppercase with dotted/dotless I support (`i` -> `İ`, `ı` -> `I`). +pub fn turkish_to_upper(s: &str) -> String { + let mut out = String::with_capacity(s.len()); + for c in s.chars() { + match c { + 'i' => out.push('İ'), + 'ı' => out.push('I'), + other => out.extend(other.to_uppercase()), + } + } + out +} + /// Match original casing on suggestion. fn match_casing(orig: &str, cand: &str) -> String { if orig.chars().all(char::is_uppercase) { - cand.to_uppercase() + turkish_to_upper(cand) } else if orig.chars().next().is_some_and(char::is_uppercase) { super::grammar::turkish_capitalize(cand) } else { @@ -273,6 +283,19 @@ fn match_casing(orig: &str, cand: &str) -> String { mod tests { use super::*; + /// CodeRabbit on craft-libs#484/#489: a suggestion in capitals uses Turkish capitals + /// (`İ`, not `I`), and no table entry suggests the word itself. + #[test] + fn capitals_are_turkish_and_no_entry_suggests_itself() { + assert_eq!(match_casing("KİTAPP", "kitap"), "KİTAP"); + assert_eq!(match_casing("ISTANBUL", "istanbul"), "İSTANBUL"); + assert_eq!(match_casing("KAPI", "kapı"), "KAPI"); + assert_eq!(turkish_to_upper("ıiçşğüö"), "IİÇŞĞÜÖ"); + let d = TrDict::from_hunspell("SET UTF-8\n", "2\nkitap\nistanbul\n").unwrap(); + assert!(suggest_with(&d, "KİTAPP", 3).contains(&"KİTAP".to_string())); + assert!(COMMON_REPLACEMENTS.iter().all(|(a, b)| a != b)); + } + #[test] fn common_replacements_are_suggested() { let sugs = suggest("yalnış", 3);