use super::config::{Lang, LangConfig};
pub fn detect_lang(text: &str) -> Lang {
let mut cyrillic = 0u32;
let mut arabic = 0u32;
let mut han = 0u32;
let mut kana = 0u32;
let mut hangul = 0u32;
let mut latin_accent = 0u32;
let mut total_alpha = 0u32;
for ch in text.chars().take(500) {
if ch.is_alphabetic() {
total_alpha += 1;
if ('\u{0400}'..='\u{04FF}').contains(&ch) {
cyrillic += 1;
} else if is_arabic(ch) {
arabic += 1;
} else if is_han(ch) {
han += 1;
} else if is_kana(ch) {
kana += 1;
} else if is_hangul(ch) {
hangul += 1;
} else if ('\u{00C0}'..='\u{024F}').contains(&ch) {
latin_accent += 1;
}
}
}
if total_alpha == 0 {
return Lang::En;
}
if cyrillic * 5 > total_alpha {
return Lang::Ru;
}
if arabic * 5 > total_alpha {
return Lang::Ar;
}
if han * 5 > total_alpha && kana == 0 && hangul == 0 {
return Lang::Zh;
}
if latin_accent > 0 {
if text.contains('ã')
|| text.contains('õ')
|| text.contains('ç')
|| text.contains('Ã')
|| text.contains('Õ')
|| text.contains('Ç')
{
return Lang::Pt;
}
if text.contains('ñ') || text.contains('Ñ') || text.contains('¿') || text.contains('¡')
{
return Lang::Es;
}
if text.contains('à')
|| text.contains('â')
|| text.contains('é')
|| text.contains('è')
|| text.contains('ê')
|| text.contains('ë')
|| text.contains('î')
|| text.contains('ï')
|| text.contains('ô')
|| text.contains('û')
|| text.contains('ù')
|| text.contains('ü')
|| text.contains('ÿ')
{
return Lang::Fr;
}
}
Lang::En
}
fn is_arabic(ch: char) -> bool {
matches!(ch,
'\u{0600}'..='\u{06FF}' | '\u{0750}'..='\u{077F}' | '\u{08A0}'..='\u{08FF}')
}
fn is_han(ch: char) -> bool {
matches!(ch,
'\u{4E00}'..='\u{9FFF}' | '\u{3400}'..='\u{4DBF}' | '\u{F900}'..='\u{FAFF}')
}
fn is_kana(ch: char) -> bool {
matches!(ch, '\u{3040}'..='\u{309F}' | '\u{30A0}'..='\u{30FF}')
}
fn is_hangul(ch: char) -> bool {
matches!(ch,
'\u{AC00}'..='\u{D7AF}' | '\u{1100}'..='\u{11FF}' | '\u{3130}'..='\u{318F}')
}
pub fn detect_language(text: &str) -> &'static LangConfig {
detect_lang(text).pack()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn detection_keeps_its_character_set_routing() {
assert_eq!(detect_lang("Давайте проверю логи"), Lang::Ru);
assert_eq!(detect_lang("سأفحص الملف وأصلح الخطأ"), Lang::Ar);
assert_eq!(detect_lang("ملف"), Lang::Ar);
assert_eq!(detect_lang("我会检查配置文件"), Lang::Zh);
assert_eq!(detect_lang("我會檢查配置文件"), Lang::Zh);
assert_eq!(detect_lang("設定ファイルを確認します"), Lang::En);
assert_eq!(detect_lang("설정 파일을 확인하겠습니다"), Lang::En);
assert_eq!(detect_lang("planejamento com ã"), Lang::Pt);
assert_eq!(detect_lang("¿cómo estás?"), Lang::Es);
assert_eq!(detect_lang("résumé à la carte"), Lang::Fr);
assert_eq!(detect_lang("hello world"), Lang::En);
assert_eq!(detect_lang(""), Lang::En);
}
#[test]
fn detect_language_resolves_through_the_registry() {
assert!(std::ptr::eq(
detect_language("Давайте проверю логи и исправлю ошибку"),
Lang::Ru.pack()
));
assert!(std::ptr::eq(
detect_language("no accents here"),
Lang::En.pack()
));
}
}