mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-24 10:16:59 -06:00
text: Georgian document language; no initial capitals for Georgian
Georgian is a Properties text language (IDML "Georgian" maps to ka). Georgian has no initial capitals: Mtavruli is only for all-caps text, so Change Case title and sentence case and index section heads leave Mkhedruli as it is (doc::capitalizes); upper case still gives Mtavruli. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YMTAbGNRxnMEzRvYnQGphF
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
19bacaadd7
commit
5d4ed2a663
@@ -190,6 +190,13 @@ impl Digits {
|
||||
}
|
||||
}
|
||||
|
||||
/// Does `c` belong to a script that capitalizes the first letter of sentences, words and headings?
|
||||
/// Georgian doesn't: Unicode maps Mkhedruli to Mtavruli capitals, but those are only for all-caps
|
||||
/// text, never for a sentence's, a title's or an index heading's first letter.
|
||||
pub fn capitalizes(c: char) -> bool {
|
||||
!matches!(c, '\u{10A0}'..='\u{10FF}' | '\u{1C90}'..='\u{1CBF}' | '\u{2D00}'..='\u{2D2F}')
|
||||
}
|
||||
|
||||
/// The BCP 47 tag of a language name as InDesign and IDML write it ("English: USA", "Chinese:
|
||||
/// Simplified", or a locale code such as "de_DE_2006"), for the shaper's localized forms (`locl`)
|
||||
/// and everything that depends on the language (quotes, hyphenation and spelling, line breaking,
|
||||
@@ -272,6 +279,7 @@ pub fn language_tag(language: &str) -> Option<&'static str> {
|
||||
"persian" | "farsi" => "fa",
|
||||
"urdu" => "ur",
|
||||
"hebrew" => "he",
|
||||
"georgian" => "ka",
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
@@ -1004,6 +1012,7 @@ mod tests {
|
||||
assert_eq!(language_tag("English: USA"), Some("en-US"));
|
||||
assert_eq!(language_tag("English: Australian"), Some("en"));
|
||||
assert_eq!(language_tag("Turkish"), Some("tr"));
|
||||
assert_eq!(language_tag("Georgian"), Some("ka"));
|
||||
assert_eq!(language_tag("Japanese"), Some("ja"));
|
||||
assert_eq!(language_tag("Korean"), Some("ko"));
|
||||
assert_eq!(language_tag("Chinese"), Some("zh"));
|
||||
|
||||
+14
-1
@@ -137,7 +137,12 @@ pub fn build(spec: &IndexSpec, refs: &[Resolved], page_name: &dyn Fn(usize) -> S
|
||||
let mut heading: Option<char> = None;
|
||||
for (key, n) in &root {
|
||||
if spec.section_headings {
|
||||
let c = key.chars().next().map(|c| if c.is_alphabetic() { c.to_uppercase().next().unwrap_or(c) } else { '#' });
|
||||
// Georgian headings stay Mkhedruli (no capitals; Mtavruli is only for all-caps text).
|
||||
let c = key.chars().next().map(|c| match c {
|
||||
c if !c.is_alphabetic() => '#',
|
||||
c if crate::capitalizes(c) => c.to_uppercase().next().unwrap_or(c),
|
||||
c => c,
|
||||
});
|
||||
if c != heading {
|
||||
heading = c;
|
||||
if let Some(c) = c {
|
||||
@@ -243,4 +248,12 @@ mod tests {
|
||||
let run_in = build(&IndexSpec { run_in: true, section_headings: false, title: String::new(), ..spec }, &refs[..2], &|p| (p + 1).to_string());
|
||||
assert_eq!(run_in, [("Index Level 1".to_string(), "Typography 2\u{2013}4: kerning 5".to_string())]);
|
||||
}
|
||||
#[test]
|
||||
fn georgian_section_heads_stay_mkhedruli() {
|
||||
let refs = vec![r(&["ასო"], IndexRange::CurrentPage, Some((0, 0))), r(&["ბადე"], IndexRange::CurrentPage, Some((1, 1)))];
|
||||
let out = build(&IndexSpec::default(), &refs, &|p| (p + 1).to_string());
|
||||
let heads: Vec<&str> = out.iter().filter(|(s, _)| s == "Index Section Head").map(|(_, t)| t.as_str()).collect();
|
||||
assert_eq!(heads, ["ა", "ბ"]);
|
||||
assert!(crate::capitalizes('a') && !crate::capitalizes('ა') && !crate::capitalizes('Ა'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,6 +649,22 @@ mod text_clipboard_tests {
|
||||
assert_eq!(s.doc().unwrap().selection.text.unwrap().range(), 0..st.len());
|
||||
st.check().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn change_case_leaves_georgian_without_initial_capitals() {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({})).unwrap();
|
||||
let a = frame(&mut s, "ᲒᲐᲛᲐᲠᲯᲝᲑᲐ ᲛᲡᲝᲤᲚᲘᲝ. ᲐᲮᲐᲚᲘ word");
|
||||
let len = s.doc().unwrap().doc.story(a).unwrap().len();
|
||||
s.execute("text.select", &json!({"story": a.0, "anchor": 0, "focus": len})).unwrap();
|
||||
// Georgian has no title or sentence capitals: Mtavruli is only for all-caps text.
|
||||
s.execute("type.changeCase", &json!({"case": "title"})).unwrap();
|
||||
assert_eq!(s.doc().unwrap().doc.story(a).unwrap().text, "გამარჯობა მსოფლიო. ახალი Word");
|
||||
s.execute("type.changeCase", &json!({"case": "sentence"})).unwrap();
|
||||
assert_eq!(s.doc().unwrap().doc.story(a).unwrap().text, "გამარჯობა მსოფლიო. ახალი word");
|
||||
s.execute("type.changeCase", &json!({"case": "upper"})).unwrap();
|
||||
assert_eq!(s.doc().unwrap().doc.story(a).unwrap().text, "ᲒᲐᲛᲐᲠᲯᲝᲑᲐ ᲛᲡᲝᲤᲚᲘᲝ. ᲐᲮᲐᲚᲘ WORD");
|
||||
}
|
||||
}
|
||||
|
||||
fn paste_into(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
|
||||
@@ -1436,19 +1436,21 @@ pub(crate) fn case_map(src: &str, case: &str) -> Vec<String> {
|
||||
let word_start = !(prev.is_alphanumeric() || matches!(prev, '\'' | '\u{2019}'));
|
||||
let up = |c: char| c.to_uppercase().collect::<String>();
|
||||
let low = |c: char| c.to_lowercase().collect::<String>();
|
||||
// Title and sentence case capitalize only scripts with initial capitals (not Georgian).
|
||||
let cap = |c: char| if designcraft_doc::capitalizes(c) { up(c) } else { low(c) };
|
||||
let m = match case {
|
||||
"upper" => up(c),
|
||||
"lower" => low(c),
|
||||
"title" => {
|
||||
if word_start {
|
||||
up(c)
|
||||
cap(c)
|
||||
} else {
|
||||
low(c)
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if sentence_start && c.is_alphanumeric() {
|
||||
up(c)
|
||||
cap(c)
|
||||
} else {
|
||||
low(c)
|
||||
}
|
||||
|
||||
@@ -1257,6 +1257,7 @@ pub(crate) const LANGUAGES: &[&str] = &[
|
||||
"Greek",
|
||||
"Russian",
|
||||
"Ukrainian",
|
||||
"Georgian",
|
||||
"Turkish",
|
||||
"Japanese",
|
||||
"Chinese",
|
||||
|
||||
Reference in New Issue
Block a user