mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-22 00:02:23 +00:00
fix(pane): the macOS locale fallback must set LANG, not LC_CTYPE (#280)
When a pane inherits no locale at all — the usual case for a GUI-launched process on macOS — we derive an installed UTF-8 locale and inject it. But we injected it as LC_CTYPE, which backs only character handling. Collation, time and numbers stayed at C, and a shell that asks setlocale(cat, "") per category finds no variable for the rest: bash warns setlocale: LC_COLLATE: cannot change locale () once per category on every launch. zsh and fish swallow the failure, so they merely look fine while being just as half-configured. LANG backs every category and still loses to any LC_* the user's own rc files set afterwards, which is what a fallback should do. LC_ALL would also cover everything but would override those. Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com>
This commit is contained in:
@@ -210,6 +210,19 @@ const LOCALE_DEFINITION_DIR: &str = "/usr/share/locale";
|
||||
#[cfg(any(target_os = "macos", test))]
|
||||
const FALLBACK_CHARACTER_LOCALES: [&str; 2] = ["C.UTF-8", "en_US.UTF-8"];
|
||||
|
||||
/// The variable the locale fallback sets.
|
||||
///
|
||||
/// It has to be one a shell consults for *every* category. `LC_CTYPE` alone
|
||||
/// fixes character handling and leaves collation, time and numbers at `C`; a
|
||||
/// shell that then asks `setlocale(LC_COLLATE, "")` finds no variable to read
|
||||
/// and bash warns `setlocale: LC_COLLATE: cannot change locale ()` once per
|
||||
/// category. (zsh and fish swallow the failure, so they look fine while being
|
||||
/// just as half-configured.) `LC_ALL` would also cover everything, but it wins
|
||||
/// over every `LC_*` the user's own rc files set afterwards — `LANG` loses to
|
||||
/// them, which is what a fallback should do.
|
||||
#[cfg(any(target_os = "macos", test))]
|
||||
const LOCALE_FALLBACK_KEY: &str = "LANG";
|
||||
|
||||
#[cfg(any(target_os = "macos", test))]
|
||||
fn character_locale(identifier: Option<&str>, exists: impl Fn(&str) -> bool) -> Option<String> {
|
||||
identifier
|
||||
@@ -350,7 +363,7 @@ fn apply_common_command_setup(
|
||||
.is_dir()
|
||||
})
|
||||
{
|
||||
cmd.env("LC_CTYPE", locale);
|
||||
cmd.env(LOCALE_FALLBACK_KEY, locale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4220,6 +4233,22 @@ mod tests {
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn locale_fallback_sets_a_variable_that_backs_every_category() {
|
||||
let injected =
|
||||
std::iter::once((LOCALE_FALLBACK_KEY.to_string(), "en_US.UTF-8".to_string()))
|
||||
.collect::<std::collections::HashMap<_, _>>();
|
||||
|
||||
// Whatever we inject has to satisfy the check that gated it, or every
|
||||
// pane would keep re-deriving a fallback that is already in place.
|
||||
assert!(!locale_fallback_is_needed(&injected, |_| None));
|
||||
|
||||
// And it has to back every category, not just character handling — see
|
||||
// LOCALE_FALLBACK_KEY. LC_CTYPE here would leave a shell warning about
|
||||
// LC_COLLATE and friends on every launch.
|
||||
assert_eq!(LOCALE_FALLBACK_KEY, "LANG");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn posix_locale_stem_drops_script_and_keyword_subtags() {
|
||||
let stem = |id: &str| posix_locale_stem(id);
|
||||
|
||||
Reference in New Issue
Block a user