diff options
Diffstat (limited to 'init/src/host/locale.rs')
| -rw-r--r-- | init/src/host/locale.rs | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/init/src/host/locale.rs b/init/src/host/locale.rs new file mode 100644 index 0000000..6dc43b2 --- /dev/null +++ b/init/src/host/locale.rs @@ -0,0 +1,133 @@ +use crate::host::timezone::set_timezone; +use crate::log::{log_success, log_warning}; +use std::fs; +use std::io::Write; +use std::process::Command; + +pub fn set_locale(locale: Option<String>) -> Result<(), Box<dyn std::error::Error>> { + let loc = match locale { + Some(l) => l, + None => { + if let Ok(content) = fs::read_to_string("/etc/default/locale") { + for line in content.lines() { + if line.starts_with("LANG=") { + let parts: Vec<&str> = line.split('=').collect(); + if parts.len() >= 2 { + let lang_val = parts[1]; + let clean_lang = lang_val.trim_matches('"').trim_matches('\''); + if !clean_lang.is_empty() { + return set_system_locale(clean_lang); + } + } + } + } + } + + if let Ok(lang_env) = std::env::var("LANG") + && !lang_env.is_empty() { + return set_system_locale(&lang_env); + + } + if locale_exists("C.UTF-8") { + "C.UTF-8".to_string() + } else if locale_exists("en_US.UTF-8") { + "en_US.UTF-8".to_string() + } else { + "C".to_string() + } + } + }; + + set_system_locale(&loc) +} +fn set_system_locale(locale: &str) -> Result<(), Box<dyn std::error::Error>> { + if !locale_exists(locale) { + log_warning(&format!( + "Locale '{}' not found in system, trying alternatives", + locale + )); + + let variants = vec![ + format!("{}.UTF-8", locale), + locale.replace('_', "-"), // Sometimes locales are in form en-US + format!("{}.UTF-8", locale.replace('_', "-")), + ]; + + for variant in variants { + if locale_exists(&variant) { + log_success(&format!("Using alternative locale: {}", variant)); + return set_system_locale_impl(&variant); + } + } + + log_warning("No matching locale found, using C.UTF-8 as fallback"); + return set_system_locale_impl("C.UTF-8"); + } + + set_system_locale_impl(locale) +} + +fn set_system_locale_impl(locale: &str) -> Result<(), Box<dyn std::error::Error>> { + unsafe { + std::env::set_var("LANG", locale); + std::env::set_var("LC_ALL", locale); + + std::env::set_var("LC_CTYPE", locale); + std::env::set_var("LC_NUMERIC", locale); + std::env::set_var("LC_TIME", locale); + std::env::set_var("LC_COLLATE", locale); + std::env::set_var("LC_MONETARY", locale); + std::env::set_var("LC_MESSAGES", locale); + std::env::set_var("LC_PAPER", locale); + std::env::set_var("LC_NAME", locale); + std::env::set_var("LC_ADDRESS", locale); + std::env::set_var("LC_TELEPHONE", locale); + std::env::set_var("LC_MEASUREMENT", locale); + std::env::set_var("LC_IDENTIFICATION", locale); + } + + if let Ok(mut file) = std::fs::OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open("/etc/default/locale") + { + writeln!(file, "# Generated by Vigil init system")?; + writeln!(file, "LANG=\"{}\"", locale)?; + writeln!(file, "LC_ALL=\"{}\"", locale)?; + file.flush()?; + } else { + log_warning("Could not write to /etc/default/locale, locale settings may not persist"); + } + + log_success(&format!("Locale set to {}", locale)); + Ok(()) +} + +fn locale_exists(locale: &str) -> bool { + if let Ok(output) = Command::new("locale").arg("-a").output() { + let output_str = String::from_utf8_lossy(&output.stdout); + output_str.lines().any(|line| line.trim() == locale) + } else { + let locale_archive_path = "/usr/lib/locale/locale-archive".to_string(); + let locale_dir_path = "/usr/lib/locale/".to_string(); + + std::path::Path::new(&locale_archive_path).exists() + || std::path::Path::new(&locale_dir_path).exists() + } +} + +pub fn set_system_localization( + timezone: Option<String>, + locale: Option<String>, +) -> Result<(), Box<dyn std::error::Error>> { + if let Err(e) = set_timezone(timezone) { + log_warning(&format!("Failed to set timezone: {}", e)); + } + + if let Err(e) = set_locale(locale) { + log_warning(&format!("Failed to set locale: {}", e)); + } + + Ok(()) +} |
