use crate::number::format_decimal;
use crate::plural::{plural_category, PluralCategory, PluralOperands};
use alloc::string::String;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RelativeUnit {
Year,
Month,
Week,
Day,
Hour,
Minute,
Second,
}
#[derive(Debug, Clone, Copy)]
pub struct RelUnit {
pub prev: Option<&'static str>,
pub cur: Option<&'static str>,
pub next: Option<&'static str>,
pub past: [Option<&'static str>; 6],
pub future: [Option<&'static str>; 6],
}
#[derive(Debug, Clone, Copy)]
pub struct RelativeSpec {
pub units: [RelUnit; 7],
}
fn spec(lang: &str) -> RelativeSpec {
use crate::unicode::generated::relative::relative_spec;
let norm: String = lang
.chars()
.map(|c| {
if c == '_' {
'-'
} else {
c.to_ascii_lowercase()
}
})
.collect();
let mut end = norm.len();
loop {
if let Some(s) = relative_spec(&norm[..end]) {
return s;
}
match norm[..end].rfind('-') {
Some(i) => end = i,
None => return relative_spec("en").expect("root relative spec present"),
}
}
}
#[must_use]
pub fn format_relative(lang: &str, value: i64, unit: RelativeUnit) -> String {
let ru = spec(lang).units[unit as usize];
if value == -1 {
if let Some(s) = ru.prev {
return String::from(s);
}
} else if value == 0 {
if let Some(s) = ru.cur {
return String::from(s);
}
} else if value == 1 {
if let Some(s) = ru.next {
return String::from(s);
}
}
let table = if value < 0 { &ru.past } else { &ru.future };
let magnitude = value.unsigned_abs();
let cat = plural_category(lang, &PluralOperands::from_int(magnitude as i64));
let pattern = table[cat as usize]
.or(table[PluralCategory::Other as usize])
.unwrap_or("{0}");
let number = format_decimal(lang, magnitude as f64);
pattern.replace("{0}", &number)
}