Add simple wrapper for `libc::settext()` to query system locale
Dependencies
- [2]
HCGVXOF7Add language negotiation using `fluent-langneg` - [3]
YNEOCYMGCreate `locale-select` crate - [4]
T6JEWQJ7Implement converting `PosixLocale` to `icu_locid::Locale` - [5]
LIH6JCXYImplement POSIX locale category lookup - [*]
UKFEFT6LCreate basic `Output` proc-macro - [*]
SHNZZSZGCreate `cli_macros` shim crate
Change contents
- edit in Cargo.lock at line 21[8.1208][8.1208]
"locale_select", - edit in Cargo.lock at line 206[8.3670][8.3670]
[[package]]name = "libc"version = "0.2.153"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" - edit in Cargo.lock at line 225
"libc", - edit in locale_select/Cargo.toml at line 5
[lints]workspace = true - replacement in locale_select/Cargo.toml at line 12
[lints]workspace = true[3.5554]libc = "0.2.153" - replacement in locale_select/src/unix.rs at line 3
use icu_locid::subtags::{self, Language, Variants};use icu_locid::subtags::{self, Variants}; - replacement in locale_select/src/unix.rs at line 206
.get_locales().get_locales_custom() - replacement in locale_select/src/lib.rs at line 4
mod fetch;pub mod fetch; - edit in locale_select/src/lib.rs at line 7
// TODO: this can probably be enums, not strings - replacement in locale_select/src/lib.rs at line 11
) -> Vec<LanguageIdentifier> {) -> LanguageIdentifier { - replacement in locale_select/src/lib.rs at line 13
let requested = unix::get_locales(fetch::unix::LocaleCategory::Messages);let requested = unix::get_locales(fetch::unix::LocaleCategory::LC_MESSAGES); - replacement in locale_select/src/lib.rs at line 21
// TODO: this is wasteful but avoids dealing with lifetimes for nowsupported.into_iter().cloned().collect()// TODO: properly handle this caseif let [single_locale] = supported[..] {// TODO: this is wasteful but avoids dealing with lifetimes for nowsingle_locale.to_owned()} else {todo!("Multiple locales returned, which is not yet handled. Got: {supported:#?}");} - edit in locale_select/src/fetch/unix.rs at line 2
use std::ffi::CStr;const NUL_BYTE: &[u8] = b"\0";macro_rules! repr_lc {($($variant:ident),+) => {#[derive(Clone, Copy, Debug)]#[allow(non_camel_case_types)] // Required for parity with C enumpub enum LocaleCategory {$($variant,)*}impl TryFrom<i32> for LocaleCategory {type Error = (); - replacement in locale_select/src/fetch/unix.rs at line 17
pub enum LocaleCategory {CType,Collate,Messages,Monetary,Numeric,Time,Address,Identification,Measurement,Name,Paper,Telephone,}fn try_from(value: i32) -> Result<Self, Self::Error> {match value {$(libc::$variant => Ok(Self::$variant),)*_ => Err(())}}}impl Into<i32> for LocaleCategory {fn into(self) -> i32 {match self {$(Self::$variant => libc::$variant,)*}}} - replacement in locale_select/src/fetch/unix.rs at line 34
impl LocaleCategory {fn as_str(&self) -> &str {match self {Self::CType => "LC_CTYPE",Self::Collate => "LC_COLLATE",Self::Messages => "LC_MESSAGES",Self::Monetary => "LC_MONETARY",Self::Numeric => "LC_NUMERIC",Self::Time => "LC_TIME",Self::Address => "LC_ADDRESS",Self::Identification => "LC_IDENTIFICATION",Self::Measurement => "LC_MEASUREMENT",Self::Name => "LC_NAME",Self::Paper => "LC_PAPER",Self::Telephone => "LC_TELEPHONE",impl LocaleCategory {fn as_str(&self) -> &str {match self {$(Self::$variant => stringify!($variant),)*}} - edit in locale_select/src/fetch/unix.rs at line 42
}repr_lc! {LC_ALL,LC_CTYPE,LC_COLLATE,LC_MESSAGES,LC_MONETARY,LC_NUMERIC,LC_TIME,LC_ADDRESS,LC_IDENTIFICATION,LC_MEASUREMENT,LC_NAME,LC_PAPER,LC_TELEPHONE} - edit in locale_select/src/fetch/unix.rs at line 60
// TODO: handle and document safety invariantsfn get_locale_libc(category: i32) -> String {let empty_cstr = CStr::from_bytes_with_nul(NUL_BYTE).unwrap();let locale_string_pointer = unsafe { libc::setlocale(category, empty_cstr.as_ptr()) };let locale_c_str = unsafe { CStr::from_ptr(locale_string_pointer) };locale_c_str.to_str().unwrap().to_string()}impl LocaleCategory { - replacement in locale_select/src/fetch/unix.rs at line 78
pub fn get_locales(&self) -> Vec<String> {pub fn get_locales_custom(&self) -> Vec<String> { - edit in locale_select/src/fetch/unix.rs at line 94
}pub fn get_locales_libc(self) -> Vec<String> {let global_locale = get_locale_libc(libc::LC_ALL);let locale_for_category = get_locale_libc(self.into());vec![global_locale, locale_for_category]