mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-08 19:42:12 +00:00
CP6.13: craft-libs#495 review — tr grammar: Turkish case folding (İst., Işık ışık), initials (A.Ş., T.C.) end no sentence, and a repeated word with an apostrophe (Ankara'da Ankara'da) is marked again
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FypgCX8LsYYE8fsj4byBm2
This commit is contained in:
1 parent
d2d5c737a6
commit
724d541856
1 file changed
+25
-7
@@ -10,6 +10,7 @@
|
||||
//! `ne ... ne` conjunctions should not have commas immediately before or after them.
|
||||
//! - **Doubled punctuation** (`..`, `,,`, `;;`).
|
||||
|
||||
use super::suggest::turkish_to_lower;
|
||||
use crate::{Issue, IssueKind, ProofLang, words};
|
||||
|
||||
/// Turkish reduplications and emphatic word pairings that are intentionally repeated.
|
||||
@@ -120,8 +121,8 @@ const ALLOWED_REPEATS: &[&str] = &[
|
||||
/// Turkish abbreviations that end with a period and after which lower case may continue.
|
||||
const ABBREVIATIONS: &[&str] = &[
|
||||
"vb", "vs", "vd", "bkz", "bknz", "ör", "örnek", "mad", "md", "s", "sf", "sn", "dk", "sa", "yy", "m", "km", "cm", "mm", "gr", "kg", "mg", "dr",
|
||||
"prof", "doç", "yrd", "av", "ist", "ank", "izm", "cad", "sok", "mah", "apt", "no", "tel", "faks", "tl", "kr", "krş", "a.ş", "ltd", "şti", "t.c",
|
||||
"tbmm", "meb", "möt", "mö", "ms",
|
||||
"prof", "doç", "yrd", "av", "ist", "ank", "izm", "cad", "sok", "mah", "apt", "no", "tel", "faks", "tl", "kr", "krş", "ltd", "şti", "tbmm", "meb",
|
||||
"möt", "mö", "ms",
|
||||
];
|
||||
|
||||
/// Conjunctions that must not be preceded by a comma.
|
||||
@@ -152,9 +153,11 @@ pub fn check_with(text: &str, capital_first: bool) -> Vec<Issue> {
|
||||
None => continue,
|
||||
};
|
||||
let only_spaces = gap.chars().all(|c| c == ' ' || c == '\t');
|
||||
let lower1 = w1.to_lowercase();
|
||||
let lower2 = w2.to_lowercase();
|
||||
if only_spaces && w1.chars().all(char::is_alphabetic) && lower1 == lower2 && !ALLOWED_REPEATS.contains(&lower1.as_str()) {
|
||||
let lower1 = turkish_to_lower(w1);
|
||||
let lower2 = turkish_to_lower(w2);
|
||||
// Words, not numbers or codes (`1 1`, `A1 A1`); `Ankara'da Ankara'da` is one.
|
||||
let word = w1.chars().any(char::is_alphabetic) && !w1.chars().any(|c| c.is_numeric());
|
||||
if only_spaces && word && lower1 == lower2 && !ALLOWED_REPEATS.contains(&lower1.as_str()) {
|
||||
v.push(Issue {
|
||||
start: pair[1].0,
|
||||
end: pair[1].1,
|
||||
@@ -226,7 +229,7 @@ pub fn check_with(text: &str, capital_first: bool) -> Vec<Issue> {
|
||||
// 3. Comma before or after conjunctions (`ali, ve veli` or `ve, veli`)
|
||||
for (i, &(w_start, w_end)) in ws.iter().enumerate() {
|
||||
let word = match text.get(w_start..w_end) {
|
||||
Some(w) => w.to_lowercase(),
|
||||
Some(w) => turkish_to_lower(w),
|
||||
None => continue,
|
||||
};
|
||||
// Check comma before conjunction
|
||||
@@ -293,11 +296,14 @@ pub fn check_with(text: &str, capital_first: bool) -> Vec<Issue> {
|
||||
// number before a period is an ordinal (`5. sınıf`, `21. yüzyıl`).
|
||||
let spaced = gap.rfind(['.', '?', '!']).and_then(|m| gap.get(m + 1..)).is_some_and(|rest| rest.contains(char::is_whitespace));
|
||||
let ordinal = trimmed.ends_with('.') && prev_word.chars().any(|c| c.is_ascii_digit());
|
||||
// An initial (`A.Ş.`, `T.C.`, `M. Kemal`) ends no sentence.
|
||||
let initial = trimmed.starts_with('.') && prev_word.chars().count() == 1;
|
||||
if (trimmed.ends_with('.') || trimmed.ends_with('?') || trimmed.ends_with('!'))
|
||||
&& spaced
|
||||
&& !ordinal
|
||||
&& !initial
|
||||
&& !trimmed.contains("...")
|
||||
&& !ABBREVIATIONS.contains(&prev_word.to_lowercase().as_str())
|
||||
&& !ABBREVIATIONS.contains(&turkish_to_lower(prev_word).as_str())
|
||||
&& let Some(w) = text.get(w_start..w_end)
|
||||
&& w.chars().next().is_some_and(char::is_lowercase)
|
||||
{
|
||||
@@ -410,6 +416,18 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// craft-libs#495 review: initials (`A.Ş.`, `T.C.`) and `İst.` end no sentence, and Turkish
|
||||
/// case folding finds `Işık ışık`; a word with an apostrophe is still a repeat.
|
||||
#[test]
|
||||
fn turkish_case_and_initials() {
|
||||
for text in ["Şirket A.Ş. bugün açıldı.", "O T.C. vatandaşı.", "Adres İst. caddesi."] {
|
||||
assert!(check(text).is_empty(), "{text}: {:?}", check(text));
|
||||
}
|
||||
for text in ["Işık ışık yandı.", "Ankara'da Ankara'da kaldık."] {
|
||||
assert_eq!(check(text).iter().filter(|i| i.message == "Yinelenen sözcük").count(), 1, "{text}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Repeated numbers are not repeated words (craft-libs#488 review).
|
||||
#[test]
|
||||
fn repeated_numbers_are_not_flagged() {
|
||||
|
||||
Reference in new issue
Block a user