summaryrefslogtreecommitdiff
path: root/init/src/host/locale.rs
diff options
context:
space:
mode:
Diffstat (limited to 'init/src/host/locale.rs')
-rw-r--r--init/src/host/locale.rs133
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(())
+}