use std::{
env,
ffi::{OsStr, OsString},
};
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum Locale {
RuRu,
#[default]
EnUs,
}
impl Locale {
#[must_use]
pub fn from_locale_name(value: &str) -> Option<Self> {
let base = value
.split(['.', '@'])
.next()
.unwrap_or(value)
.replace('_', "-")
.to_ascii_lowercase();
match base.as_str() {
"ru" | "ru-ru" => Some(Self::RuRu),
"en" | "en-us" => Some(Self::EnUs),
_ => None,
}
}
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::RuRu => "ru-RU",
Self::EnUs => "en-US",
}
}
}
#[must_use]
pub fn resolve_locale(
cli_locale: Option<&str>,
environment_locale: Option<&str>,
system_locale: Option<&str>,
) -> Locale {
cli_locale
.or(environment_locale)
.or(system_locale)
.and_then(Locale::from_locale_name)
.unwrap_or_default()
}
#[must_use]
pub fn resolve_locale_from_environment(cli_locale: Option<&str>) -> Locale {
let environment_locale: Option<OsString> = env::var_os("ESKA_LANG");
let system_locale = sys_locale::get_locale();
resolve_locale(
cli_locale,
environment_locale.as_deref().and_then(OsStr::to_str),
system_locale.as_deref(),
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn normalizes_supported_locale_names() {
for value in ["ru", "ru-RU", "ru_RU", "ru_RU.UTF-8"] {
assert_eq!(Locale::from_locale_name(value), Some(Locale::RuRu));
}
for value in ["en", "en-US", "en_US", "en_US.UTF-8"] {
assert_eq!(Locale::from_locale_name(value), Some(Locale::EnUs));
}
}
#[test]
fn resolves_locale_in_priority_order() {
assert_eq!(
resolve_locale(Some("ru"), Some("en"), Some("en")),
Locale::RuRu
);
assert_eq!(resolve_locale(None, Some("ru"), Some("en")), Locale::RuRu);
assert_eq!(resolve_locale(None, None, Some("ru")), Locale::RuRu);
assert_eq!(resolve_locale(None, None, Some("de-DE")), Locale::EnUs);
assert_eq!(resolve_locale(None, None, None), Locale::EnUs);
}
}