use hyphenation::{Hyphenator, Language, Load, Standard};
use lightweight_pdf_core::HyphenationLanguage;
use std::sync::OnceLock;
fn dictionary_for(lang: HyphenationLanguage) -> &'static Standard {
static EN_US: OnceLock<Standard> = OnceLock::new();
static GERMAN: OnceLock<Standard> = OnceLock::new();
match lang {
HyphenationLanguage::EnglishUs => {
EN_US.get_or_init(|| Standard::from_embedded(Language::EnglishUS).expect("embedded en-US hyphenation dictionary"))
}
HyphenationLanguage::German => {
GERMAN.get_or_init(|| Standard::from_embedded(Language::German1996).expect("embedded de-1996 hyphenation dictionary"))
}
}
}
fn hyphenate_word(dict: &Standard, word: &str) -> String {
if word.contains('\u{AD}') {
return word.to_string();
}
let segments: Vec<&str> = dict.hyphenate(word).into_iter().segments().collect();
segments.join("\u{AD}")
}
pub fn auto_hyphenate(text: &str, lang: HyphenationLanguage) -> String {
let dict = dictionary_for(lang);
let mut out = String::with_capacity(text.len());
let mut word_start = None;
for (i, ch) in text.char_indices() {
if ch.is_whitespace() {
if let Some(start) = word_start.take() {
out.push_str(&hyphenate_word(dict, &text[start..i]));
}
out.push(ch);
} else if word_start.is_none() {
word_start = Some(i);
}
}
if let Some(start) = word_start {
out.push_str(&hyphenate_word(dict, &text[start..]));
}
out
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn inserts_soft_hyphens_at_dictionary_break_points_in_a_long_word() {
let hyphenated = auto_hyphenate("Silbentrennung", HyphenationLanguage::German);
assert!(
hyphenated.contains('\u{AD}'),
"expected at least one soft hyphen, got {hyphenated:?}"
);
assert_eq!(
hyphenated.replace('\u{AD}', ""),
"Silbentrennung",
"hyphenation must not change the word itself"
);
}
#[test]
fn preserves_whitespace_and_word_boundaries() {
let hyphenated = auto_hyphenate("Hyphenation example", HyphenationLanguage::EnglishUs);
assert_eq!(hyphenated.replace('\u{AD}', ""), "Hyphenation example");
assert!(hyphenated.contains(' '), "the space between words must survive untouched");
}
}