bckt 0.6.7

bckt is an opinionated but flexible static site generator for blogs
use std::collections::BTreeMap;

use isolang::Language;

use crate::config::SearchLanguageConfig;

pub(crate) fn build_lookup(languages: &[SearchLanguageConfig]) -> BTreeMap<String, String> {
    let mut map = BTreeMap::new();
    for entry in languages {
        let canonical = sanitize_language(&entry.id);
        if canonical.is_empty() {
            continue;
        }

        map.insert(canonical.clone(), entry.id.clone());
        for alias in language_aliases(&canonical) {
            map.entry(alias).or_insert_with(|| entry.id.clone());
        }
    }
    map
}

pub(crate) fn language_aliases(id: &str) -> Vec<String> {
    let mut aliases = Vec::new();
    let primary = id.split('-').next().unwrap_or(id);

    let language = match primary.len() {
        2 => Language::from_639_1(primary),
        3 => Language::from_639_3(primary),
        _ => None,
    };

    if let Some(lang) = language {
        if let Some(code) = lang.to_639_1() {
            aliases.push(code.to_lowercase());
        }
        aliases.push(lang.to_639_3().to_lowercase());
    }

    aliases
}

pub(crate) fn canonical_language(value: &str, map: &BTreeMap<String, String>) -> Option<String> {
    let sanitized = sanitize_language(value);
    if sanitized.is_empty() {
        return None;
    }

    if let Some(found) = map.get(&sanitized) {
        return Some(found.clone());
    }

    if let Some((primary, _rest)) = sanitized.split_once('-')
        && let Some(found) = map.get(primary)
    {
        return Some(found.clone());
    }

    Some(sanitized)
}

pub(crate) fn sanitize_language(value: &str) -> String {
    value.trim().replace('_', "-").to_ascii_lowercase()
}