// NOTE: Ts file contains setting localisation by environment variables // Main logic implemented but how i think it can contain with broken logic or checks // At least if check failed it set C.UTF8 (fallback locale) // And why is std::env::set_var unsafe???? use crate::host::timezone::set_timezone; use crate::log::{log_success, log_warning}; use std::fs; use std::io::Write; use std::process::Command; /// Main function which setting system locale. /// /// Logic && Checks /// 1. Reading /etc/default/locale to find needed language. /// If it broken/has syntax errors skipping this step /// 2. Checking for locale avalible (also switching `-` and `_`), /// if not uses fallback locale. /// pub fn set_locale(locale: Option) -> Result<(), Box> { 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> { 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> { 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, locale: Option, ) -> Result<(), Box> { 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(()) }