use std::{borrow::Cow, path::Path, sync::LazyLock};
use unic_langid::LanguageIdentifier;
struct EnUs;
struct SvSe;
pub(crate) enum UnitAction {
Start,
Stop,
Restart,
Reload,
}
pub static MSG: LazyLock<Box<dyn Messages + Send + Sync>> =
LazyLock::new(|| init_messages(sys_locale::get_locales()));
fn init_messages(locales: impl Iterator<Item = String>) -> Box<dyn Messages + Send + Sync> {
let mut available_langs: Vec<(&str, Box<dyn Messages + Send + Sync>)> =
vec![("en", Box::new(EnUs)), ("sv", Box::new(SvSe))];
for preferred_lang in locales.filter_map(|t| t.parse::<LanguageIdentifier>().ok()) {
for (lang, msgs) in available_langs.drain(..) {
if preferred_lang.matches(
&lang
.parse::<LanguageIdentifier>()
.expect("should be valid locale string"),
false,
true,
) {
return msgs;
}
}
}
Box::new(EnUs)
}
pub(crate) trait Messages {
fn reloading_systemd(&self) -> Cow<'static, str> {
EnUs.reloading_systemd()
}
fn err_reloading_systemd(&self) -> Cow<'static, str> {
EnUs.err_reloading_systemd()
}
fn resetting_failed_units(&self) -> Cow<'static, str> {
EnUs.resetting_failed_units()
}
fn err_resetting_failed_units(&self) -> Cow<'static, str> {
EnUs.err_resetting_failed_units()
}
fn err_listing_active_units(&self) -> Cow<'static, str> {
EnUs.err_listing_active_units()
}
fn err_read_dir_entry(&self, path: &Path) -> Cow<'static, str> {
EnUs.err_read_dir_entry(path)
}
fn stopping_units(&self, units: &str) -> Cow<'static, str> {
EnUs.stopping_units(units)
}
fn starting_units(&self, units: &str) -> Cow<'static, str> {
EnUs.starting_units(units)
}
fn restarting_units(&self, units: &str) -> Cow<'static, str> {
EnUs.restarting_units(units)
}
fn reloading_units(&self, units: &str) -> Cow<'static, str> {
EnUs.reloading_units(units)
}
fn keeping_old_units(&self, units: &str) -> Cow<'static, str> {
EnUs.keeping_old_units(units)
}
fn unchanged_units(&self, units: &str) -> Cow<'static, str> {
EnUs.unchanged_units(units)
}
fn err_unit_action_failed(&self, unit: &str, action: UnitAction) -> Cow<'static, str> {
EnUs.err_unit_action_failed(unit, action)
}
}
impl Messages for EnUs {
fn reloading_systemd(&self) -> Cow<'static, str> {
"Reloading systemd".into()
}
fn err_reloading_systemd(&self) -> Cow<'static, str> {
"Failed to reload systemd".into()
}
fn resetting_failed_units(&self) -> Cow<'static, str> {
"Resetting failed units".into()
}
fn err_resetting_failed_units(&self) -> Cow<'static, str> {
"Error resetting failed units".into()
}
fn err_listing_active_units(&self) -> Cow<'static, str> {
"Failed to list active and activating units".into()
}
fn err_read_dir_entry(&self, path: &Path) -> Cow<'static, str> {
format!("Failed to read directory entry in {}", path.display()).into()
}
fn stopping_units(&self, units: &str) -> Cow<'static, str> {
format!("Stopping units: {units}").into()
}
fn starting_units(&self, units: &str) -> Cow<'static, str> {
format!("Starting units: {units}").into()
}
fn restarting_units(&self, units: &str) -> Cow<'static, str> {
format!("Restarting units: {units}").into()
}
fn reloading_units(&self, units: &str) -> Cow<'static, str> {
format!("Reloading units: {units}").into()
}
fn keeping_old_units(&self, units: &str) -> Cow<'static, str> {
format!("Keeping old units: {units}").into()
}
fn unchanged_units(&self, units: &str) -> Cow<'static, str> {
format!("Keeping unchanged units: {units}").into()
}
fn err_unit_action_failed(&self, unit: &str, action: UnitAction) -> Cow<'static, str> {
let action = match action {
UnitAction::Start => "start",
UnitAction::Stop => "stop",
UnitAction::Restart => "restart",
UnitAction::Reload => "reload",
};
format!("Failed to {action} unit {unit}").into()
}
}
impl Messages for SvSe {
fn reloading_systemd(&self) -> Cow<'static, str> {
"Laddar om systemd".into()
}
fn err_reloading_systemd(&self) -> Cow<'static, str> {
"Lyckades inte ladda om systemd".into()
}
fn resetting_failed_units(&self) -> Cow<'static, str> {
"Återställer felmarkerade enheter".into()
}
fn err_resetting_failed_units(&self) -> Cow<'static, str> {
"Lyckades inte återställa felmarkerade enheter".into()
}
fn err_listing_active_units(&self) -> Cow<'static, str> {
"Lyckades inte lista aktiva och aktiverande enheter".into()
}
fn err_read_dir_entry(&self, path: &Path) -> Cow<'static, str> {
format!("Lyckades inte läsa post i katalogen {}", path.display()).into()
}
fn stopping_units(&self, units: &str) -> Cow<'static, str> {
format!("Stoppar enheter: {units}").into()
}
fn starting_units(&self, units: &str) -> Cow<'static, str> {
format!("Startar enheter: {units}").into()
}
fn restarting_units(&self, units: &str) -> Cow<'static, str> {
format!("Startar om enheter: {units}").into()
}
fn reloading_units(&self, units: &str) -> Cow<'static, str> {
format!("Laddar om enheter: {units}").into()
}
fn keeping_old_units(&self, units: &str) -> Cow<'static, str> {
format!("Behåller gamla enheter: {units}").into()
}
fn unchanged_units(&self, units: &str) -> Cow<'static, str> {
format!("Behåller oförändrade enheter: {units}").into()
}
fn err_unit_action_failed(&self, unit: &str, action: UnitAction) -> Cow<'static, str> {
let action = match action {
UnitAction::Start => "starta",
UnitAction::Stop => "stoppa",
UnitAction::Restart => "starta om",
UnitAction::Reload => "ladda om",
};
format!("Lyckades inte {action} enheten {unit}").into()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn can_handle_no_locale() {
let langs = vec![].into_iter();
assert_eq!(
init_messages(langs).reloading_systemd(),
EnUs.reloading_systemd()
);
}
#[test]
fn can_initialize_known_locale() {
let langs = vec!["sv-SE".to_string()].into_iter();
assert_eq!(
init_messages(langs).reloading_systemd(),
SvSe.reloading_systemd()
);
}
#[test]
fn ignores_unparseable_locale() {
let langs = vec!["C".to_string()].into_iter();
assert_eq!(
init_messages(langs).reloading_systemd(),
EnUs.reloading_systemd()
);
}
}