use crate::phonetic::llev::RuleSetChar;
use std::sync::OnceLock;
pub fn romaji() -> &'static RuleSetChar {
static RULESET: OnceLock<RuleSetChar> = OnceLock::new();
RULESET.get_or_init(|| {
let content = include_str!("../../../data/rules/japanese/romaji.llev");
let file = crate::phonetic::llev::parse_str(content)
.expect("Invalid embedded japanese/romaji.llev - this is a bug in liblevenshtein");
RuleSetChar::from_llev(&file)
.expect("Failed to compile Japanese romaji rules - this is a bug in liblevenshtein")
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_romaji_loads() {
let rules = romaji();
assert!(
!rules.is_empty(),
"Japanese romaji rules should not be empty"
);
assert!(
rules.len() > 35,
"expected >35 romaji rules, got {}",
rules.len()
);
}
#[test]
fn test_long_vowels() {
let rules = romaji();
let result = rules.apply("ā");
assert!(
result.contains("aː") || result.contains('A'),
"ā should become aː, got: {}",
result
);
let result = rules.apply("ō");
assert!(
result.contains("oː") || result.contains('O'),
"ō should become oː, got: {}",
result
);
let result = rules.apply("ū");
assert!(
result.contains("uː") || result.contains('U'),
"ū should become uː, got: {}",
result
);
}
#[test]
fn test_romanization_variants() {
let rules = romaji();
let result = rules.apply("ti");
assert!(
result.contains("t͡ɕ") || result.contains('C'),
"ti should become t͡ɕ, got: {}",
result
);
let result = rules.apply("tu");
assert!(
result.contains("t͡s"),
"tu should become t͡s, got: {}",
result
);
let result = rules.apply("si");
assert!(
result.contains('ɕ') || result.contains('ʃ'),
"si should become ɕ, got: {}",
result
);
let result = rules.apply("hu");
assert!(
result.contains('ɸ') || result.contains('F'),
"hu should become ɸ, got: {}",
result
);
}
#[test]
fn test_digraphs() {
let rules = romaji();
let result = rules.apply("shi");
assert!(
result.contains('ɕ') || result.contains('ʃ'),
"shi should become ɕ, got: {}",
result
);
let result = rules.apply("chi");
assert!(
result.contains("t͡ɕ") || result.contains('C'),
"chi should become t͡ɕ, got: {}",
result
);
let result = rules.apply("tsu");
assert!(
result.contains("t͡s"),
"tsu should become t͡s, got: {}",
result
);
let result = rules.apply("fu");
assert!(
result.contains('ɸ') || result.contains('F'),
"fu should become ɸ, got: {}",
result
);
}
#[test]
fn test_gemination() {
let rules = romaji();
let result = rules.apply("kk");
assert!(
result.contains('K') && !result.contains("k͈"),
"kk should become K, got: {}",
result
);
let result = rules.apply("pp");
assert!(
result.contains('P') && !result.contains("pp"),
"pp should become P, got: {}",
result
);
}
#[test]
fn test_syllabic_n() {
let rules = romaji();
let result = rules.apply("n'");
assert!(
result.contains('N') || result.contains('ŋ'),
"n' should become N, got: {}",
result
);
}
#[test]
fn test_word_tokyo() {
let rules = romaji();
let result = rules.apply("Tōkyō");
assert!(
(result.contains("oː") || result.contains('O')) && result.contains('k'),
"Tōkyō should have oː markers, got: {}",
result
);
}
#[test]
fn test_word_sushi() {
let rules = romaji();
let result = rules.apply("sushi");
assert!(
result.contains('ɕ') || result.contains('ʃ'),
"sushi should have ɕ (from shi), got: {}",
result
);
}
#[test]
fn test_word_nippon() {
let rules = romaji();
let result = rules.apply("Nippon");
assert!(
result.contains('P'),
"Nippon should have P (from pp), got: {}",
result
);
}
}