rok-core 0.6.0

Core primitives for the rok ecosystem — errors, crypto, i18n, config, DI, and more
Documentation
use super::loader::LocaleStore;
use serde_json::Value;

pub fn do_translate(
    store: &LocaleStore,
    locale: &str,
    default: &str,
    key: &str,
    args: &[(&str, String)],
) -> String {
    let raw = lookup_str(store, locale, key)
        .or_else(|| {
            if locale != default {
                lookup_str(store, default, key)
            } else {
                None
            }
        })
        .unwrap_or_else(|| key.to_string());

    interpolate(&raw, args)
}

pub fn do_translate_plural(
    store: &LocaleStore,
    locale: &str,
    default: &str,
    key: &str,
    count: u64,
    args: &[(&str, String)],
) -> String {
    let form = if count == 1 { "one" } else { "other" };

    let raw = lookup_plural(store, locale, key, form)
        .or_else(|| {
            if locale != default {
                lookup_plural(store, default, key, form)
            } else {
                None
            }
        })
        .or_else(|| lookup_str(store, locale, key))
        .or_else(|| {
            if locale != default {
                lookup_str(store, default, key)
            } else {
                None
            }
        })
        .unwrap_or_else(|| key.to_string());

    let mut all_args: Vec<(&str, String)> = args.to_vec();
    if !args.iter().any(|(k, _)| *k == "count") {
        all_args.push(("count", count.to_string()));
    }

    interpolate(&raw, &all_args)
}

fn lookup_str(store: &LocaleStore, locale: &str, key: &str) -> Option<String> {
    store
        .get(locale)?
        .get(key)
        .and_then(|v| v.as_str())
        .map(String::from)
}

fn lookup_plural(store: &LocaleStore, locale: &str, key: &str, form: &str) -> Option<String> {
    let guard = store.get(locale)?;
    let obj = guard.get(key)?.as_object()?;
    obj.get(form)
        .or_else(|| obj.get("other"))
        .and_then(|v| v.as_str())
        .map(String::from)
}

pub fn interpolate(template: &str, args: &[(&str, String)]) -> String {
    let mut result = template.to_string();
    for (key, val) in args {
        result = result.replace(&format!("{{{key}}}"), val);
    }
    result
}

#[allow(dead_code)]
pub fn value_as_str(v: &Value) -> Option<&str> {
    v.as_str()
}