use std::{borrow::Cow, path::Path, sync::LazyLock};
use unic_langid::LanguageIdentifier;
struct EnUs;
struct SvSe;
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 + 'static> {
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 err_both_system_and_user(&self) -> Cow<'static, str> {
EnUs.err_both_system_and_user()
}
fn err_not_a_directory(&self, path: &Path) -> Cow<'static, str> {
EnUs.err_not_a_directory(path)
}
fn err_missing_required_option(&self, name: &str) -> Cow<'static, str> {
EnUs.err_missing_required_option(name)
}
fn err_run_help(&self, program: &str) -> Cow<'static, str> {
EnUs.err_run_help(program)
}
fn err_invalid_timeout(&self) -> Cow<'static, str> {
EnUs.err_invalid_timeout()
}
fn err_no_systemd_conn(&self) -> Cow<'static, str> {
EnUs.err_no_systemd_conn()
}
fn err_switch_failed(&self) -> Cow<'static, str> {
EnUs.err_switch_failed()
}
fn err_argument_missing(&self, option: &str) -> Cow<'static, str> {
EnUs.err_argument_missing(option)
}
fn err_unrecognized_option(&self, option: &str) -> Cow<'static, str> {
EnUs.err_unrecognized_option(option)
}
fn err_option_missing(&self, option: &str) -> Cow<'static, str> {
EnUs.err_option_missing(option)
}
fn err_option_duplicated(&self, option: &str) -> Cow<'static, str> {
EnUs.err_option_duplicated(option)
}
fn err_unexpected_argument(&self, option: &str) -> Cow<'static, str> {
EnUs.err_unexpected_argument(option)
}
fn err_open_system_bus(&self) -> Cow<'static, str> {
EnUs.err_open_system_bus()
}
fn err_open_user_bus(&self) -> Cow<'static, str> {
EnUs.err_open_user_bus()
}
fn err_open_user_bus_alt(&self, bus_path: &str) -> Cow<'static, str> {
EnUs.err_open_user_bus_alt(bus_path)
}
fn err_no_bus_socket(&self, bus_path: &str) -> Cow<'static, str> {
EnUs.err_no_bus_socket(bus_path)
}
fn err_bus_failure(&self) -> Cow<'static, str> {
EnUs.err_bus_failure()
}
fn err_bus_failure_alt(&self, bus_path: &str) -> Cow<'static, str> {
EnUs.err_bus_failure_alt(bus_path)
}
fn warn_alternate_bus(&self, bus_path: &str) -> Cow<'static, str> {
EnUs.warn_alternate_bus(bus_path)
}
fn help_brief(&self, package_version: &str, program: &str) -> Cow<'static, str> {
EnUs.help_brief(package_version, program)
}
fn help_system(&self) -> Cow<'static, str> {
EnUs.help_system()
}
fn help_user(&self) -> Cow<'static, str> {
EnUs.help_user()
}
fn help_new_units(&self) -> Cow<'static, str> {
EnUs.help_new_units()
}
fn help_old_units(&self) -> Cow<'static, str> {
EnUs.help_old_units()
}
fn help_dry_run(&self) -> Cow<'static, str> {
EnUs.help_dry_run()
}
fn help_timeout(&self) -> Cow<'static, str> {
EnUs.help_timeout()
}
fn help_force_systemctl(&self) -> Cow<'static, str> {
EnUs.help_force_systemctl()
}
fn help_verbose(&self) -> Cow<'static, str> {
EnUs.help_verbose()
}
fn help_help(&self) -> Cow<'static, str> {
EnUs.help_help()
}
fn help_version(&self) -> Cow<'static, str> {
EnUs.help_version()
}
fn enable_verbose_output(&self) -> Cow<'static, str> {
EnUs.enable_verbose_output()
}
fn performing_dry_run(&self) -> Cow<'static, str> {
EnUs.performing_dry_run()
}
}
impl Messages for EnUs {
fn err_both_system_and_user(&self) -> Cow<'static, str> {
"Cannot provide both --system and --user".into()
}
fn err_not_a_directory(&self, path: &Path) -> Cow<'static, str> {
format!("{} is not a directory", path.display()).into()
}
fn err_missing_required_option(&self, name: &str) -> Cow<'static, str> {
format!("Required option '{name}' missing.").into()
}
fn err_run_help(&self, program: &str) -> Cow<'static, str> {
format!("Run '{program} --help' for help.").into()
}
fn err_invalid_timeout(&self) -> Cow<'static, str> {
"Invalid timeout value, expected positive whole number.".into()
}
fn err_no_systemd_conn(&self) -> Cow<'static, str> {
"Failed to connect to systemd using D-Bus or systemctl".into()
}
fn err_switch_failed(&self) -> Cow<'static, str> {
"Error switching systemd units".into()
}
fn err_argument_missing(&self, option: &str) -> Cow<'static, str> {
format!("Argument to option '{option}' missing").into()
}
fn err_unrecognized_option(&self, option: &str) -> Cow<'static, str> {
format!("Unrecognized option: '{option}'").into()
}
fn err_option_missing(&self, option: &str) -> Cow<'static, str> {
format!("Required option '{option}' missing").into()
}
fn err_option_duplicated(&self, option: &str) -> Cow<'static, str> {
format!("Option '{option}' given more than once").into()
}
fn err_unexpected_argument(&self, option: &str) -> Cow<'static, str> {
format!("Option '{option}' does not take an argument").into()
}
fn err_open_system_bus(&self) -> Cow<'static, str> {
"Failed to open system D-Bus connection".into()
}
fn err_open_user_bus(&self) -> Cow<'static, str> {
"Failed to open user session D-Bus connection".into()
}
fn err_open_user_bus_alt(&self, bus_path: &str) -> Cow<'static, str> {
format!("Failed to open session D-Bus connection at {bus_path}").into()
}
fn err_no_bus_socket(&self, bus_path: &str) -> Cow<'static, str> {
format!("No D-Bus socket found at {bus_path}").into()
}
fn err_bus_failure(&self) -> Cow<'static, str> {
"Cannot reach running systemd on standard D-Bus".into()
}
fn err_bus_failure_alt(&self, bus_path: &str) -> Cow<'static, str> {
format!("Failed to open session D-Bus connection at {bus_path}").into()
}
fn warn_alternate_bus(&self, bus_path: &str) -> Cow<'static, str> {
format!(
"Connected to systemd on D-Bus socket {bus_path}.\n\
This is different from what is in ${{DBUS_SESSION_BUS_ADDRESS}},\n\
perhaps you have multiple D-Bus sessions running?"
)
.into()
}
fn help_brief(&self, package_version: &str, program: &str) -> Cow<'static, str> {
format!(
"{package_version}\n\
\n\
Given two directories of systemd unit files, this tool will stop,\n\
start, restart, etc. services in the first directory to match the\n\
units in the second directory.\n\
\n\
Usage: {program} [options]"
)
.into()
}
fn help_system(&self) -> Cow<'static, str> {
"Connect to system bus.".into()
}
fn help_user(&self) -> Cow<'static, str> {
"Connect to user bus (the default).".into()
}
fn help_new_units(&self) -> Cow<'static, str> {
"Path to target directory of systemd unit files.".into()
}
fn help_old_units(&self) -> Cow<'static, str> {
"Path to reference directory of systemd unit files.".into()
}
fn help_dry_run(&self) -> Cow<'static, str> {
"Print, but do not perform, the switch actions.".into()
}
fn help_timeout(&self) -> Cow<'static, str> {
"The number of milliseconds to wait for units to start, \
stop, reload, etc. Default is 120000 (2 minutes)."
.into()
}
fn help_force_systemctl(&self) -> Cow<'static, str> {
"Force use of systemctl, even if D-Bus is available.".into()
}
fn help_verbose(&self) -> Cow<'static, str> {
"Log all actions.".into()
}
fn help_help(&self) -> Cow<'static, str> {
"Print command help.".into()
}
fn help_version(&self) -> Cow<'static, str> {
"program version.".into()
}
fn enable_verbose_output(&self) -> Cow<'static, str> {
"Enabling verbose output".into()
}
fn performing_dry_run(&self) -> Cow<'static, str> {
"Performing dry-run".into()
}
}
impl Messages for SvSe {
fn err_both_system_and_user(&self) -> Cow<'static, str> {
"Kan inte ange både --system och --user".into()
}
fn err_not_a_directory(&self, path: &Path) -> Cow<'static, str> {
format!("{} är inte en katalog", path.display()).into()
}
fn err_missing_required_option(&self, name: &str) -> Cow<'static, str> {
format!("Obligatoriska flaggan '{name}' saknas.").into()
}
fn err_run_help(&self, program: &str) -> Cow<'static, str> {
format!("Kör '{program} --help' för hjälp.").into()
}
fn err_invalid_timeout(&self) -> Cow<'static, str> {
"Ogiltigt timeout-värde, förväntade ett positivt heltal".into()
}
fn err_no_systemd_conn(&self) -> Cow<'static, str> {
"Lyckades inte koppla till systemd genom D-Bus eller systemctl".into()
}
fn err_switch_failed(&self) -> Cow<'static, str> {
"Fel vid byte av systemd-enheter".into()
}
fn err_argument_missing(&self, option: &str) -> Cow<'static, str> {
format!("Argument till flaggan '{option}' saknas").into()
}
fn err_unrecognized_option(&self, option: &str) -> Cow<'static, str> {
format!("Okänd flagga: '{option}'").into()
}
fn err_option_missing(&self, option: &str) -> Cow<'static, str> {
format!("Obligatorisk flagga '{option}' saknas").into()
}
fn err_option_duplicated(&self, option: &str) -> Cow<'static, str> {
format!("Flagga '{option}' gavs fler än en gång").into()
}
fn err_unexpected_argument(&self, option: &str) -> Cow<'static, str> {
format!("Flagga '{option}' tar inget argument").into()
}
fn err_open_system_bus(&self) -> Cow<'static, str> {
"Lyckades inte öppna en koppling till systemets D-Bus".into()
}
fn err_open_user_bus(&self) -> Cow<'static, str> {
"Lyckades inte öppna en koppling till användarsessionens D-Bus".into()
}
fn err_open_user_bus_alt(&self, bus_path: &str) -> Cow<'static, str> {
format!("Lyckades inte öppna en koppling till D-Bus-socketen {bus_path}").into()
}
fn err_no_bus_socket(&self, bus_path: &str) -> Cow<'static, str> {
format!("Kunde inte hitta en D-Bus-socket på {bus_path}").into()
}
fn err_bus_failure(&self) -> Cow<'static, str> {
"Kan inte nå en körande systemd på vanliga D-Bus".into()
}
fn err_bus_failure_alt(&self, bus_path: &str) -> Cow<'static, str> {
format!("Kan inte nå en körande systemd på D-Bus-socketen {bus_path}").into()
}
fn warn_alternate_bus(&self, bus_path: &str) -> Cow<'static, str> {
format!(
"Kopplad till systemd på D-Bus-socketen {bus_path}.\n\
Detta är annorlunda från värdet i ${{DBUS_SESSION_BUS_ADDRESS}},\n\
kanske du kör flera D-Bus-sessioner samtidigt?"
)
.into()
}
fn help_brief(&self, package_version: &str, program: &str) -> Cow<'static, str> {
format!(
"{package_version}\n\
\n\
Givet två kataloger med systemd-enheter så stoppar, startar,\n\
omstartar, osv. detta verktyg enheter de två katalogerna så att\n\
systemet matchar andra katalogen.\n\
\n\
Användning: {program} [flaggor]"
)
.into()
}
fn help_system(&self) -> Cow<'static, str> {
"Koppla till systembussen.".into()
}
fn help_user(&self) -> Cow<'static, str> {
"Koppla till användarbussen (förvalt).".into()
}
fn help_new_units(&self) -> Cow<'static, str> {
"Sökväg till målkatalogen med systemd-enheter.".into()
}
fn help_old_units(&self) -> Cow<'static, str> {
"Sökväg till referenskatalog med systemd-enheter.".into()
}
fn help_dry_run(&self) -> Cow<'static, str> {
"Skriv ut, men utför inte, aktiveringen av enheter.".into()
}
fn help_timeout(&self) -> Cow<'static, str> {
"Antalet millisekunder att vänta på enheter att starta, stoppa, ladda om, etc. \
Förvalt värde är 120000 (2 minuter)."
.into()
}
fn help_force_systemctl(&self) -> Cow<'static, str> {
"Tvinga användning av systemctl, även om D-Bus är tillgänglig.".into()
}
fn help_verbose(&self) -> Cow<'static, str> {
"Logga alla händelser.".into()
}
fn help_help(&self) -> Cow<'static, str> {
"Skriv ut kommandohjälpen.".into()
}
fn help_version(&self) -> Cow<'static, str> {
"Skriv ut programversionen.".into()
}
fn enable_verbose_output(&self) -> Cow<'static, str> {
"Aktiverar detaljerad utskrift".into()
}
fn performing_dry_run(&self) -> Cow<'static, str> {
"Utför simulerad körning".into()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn can_handle_no_locales() {
let langs = vec![].into_iter();
assert_eq!(init_messages(langs).help_help(), EnUs.help_help());
}
#[test]
fn can_initialize_known_locale() {
let langs = vec!["sv-SE".to_string()].into_iter();
assert_eq!(init_messages(langs).help_help(), SvSe.help_help());
}
#[test]
fn ignores_unparseable_locale() {
let langs = vec!["C".to_string()].into_iter();
assert_eq!(init_messages(langs).help_help(), EnUs.help_help());
}
}