Skip to content

locale: honor LC_ALL and LC_MESSAGES precedence over LANG - #13331

Open
costajohnt wants to merge 5 commits into
uutils:mainfrom
costajohnt:fix/8922-lc-all-locale-precedence
Open

costajohnt wants to merge 5 commits into
uutils:mainfrom
costajohnt:fix/8922-lc-all-locale-precedence

Conversation

@costajohnt

Copy link
Copy Markdown
Contributor

Fixes #8922.

Locale detection only read LANG, so LC_ALL and LC_MESSAGES were ignored. GNU honors all three, so LC_ALL=fr_FR.UTF-8 sleep --help prints French there but English in uutils.

This applies the POSIX message-locale precedence LC_ALL > LC_MESSAGES > LANG: the first of those that is set and non-empty wins (a set-but-empty value is treated as unset), otherwise it falls back to the existing en-US default. The winning value keeps the same .<encoding> stripping as before (fr_FR.UTF-8 -> fr_FR), so the LANG-only path is unchanged.

The precedence lives in a small pure helper that takes the env lookup as an argument, so it can be unit-tested without mutating process-global env vars (which race under parallel test threads):

fn resolve_locale_string(lookup: impl Fn(&str) -> Option<String>) -> String

detect_system_locale just calls it with std::env::var.

Behavior change

Anyone who has LC_ALL or LC_MESSAGES set to something other than LANG will now get that locale for messages instead of LANG. That is the intended fix for #8922, but noting it since it is user-visible.

Tests

Seven unit tests on the helper: LC_ALL wins, LC_MESSAGES when LC_ALL is unset, LANG still works, empty treated as unset, LC_ALL over LANG, LC_ALL over LC_MESSAGES, and nothing-set fallback.

cargo test, cargo clippy --workspace --all-targets --all-features -- -D warnings, and cargo fmt --check all pass.

@github-actions

github-actions Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

GNU testsuite comparison:

Skip an intermittent issue tests/tail/tail-n0f (fails in this run but passes in the 'main' branch)
Congrats! The gnu test tests/seq/seq-epipe is no longer failing!
Note: The gnu test tests/cp/link-heap is now being skipped but was previously passing.
Note: The gnu test tests/cut/bounded-memory is now being skipped but was previously passing.
Note: The gnu test tests/tail/pipe-f is now being skipped but was previously passing.

@codspeed

codspeed Bot commented Jul 12, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

1 warning, 1 note

⚠️ 114 benchmarks are dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

ℹ️ 1 benchmark has no flamegraph

The flamegraph wasn't generated: most of the time was spent in runtime internals, which would leave nothing useful to analyze.

See affected benchmarks

✅ 401 untouched benchmarks
⏩ 70 skipped benchmarks1


Comparing costajohnt:fix/8922-lc-all-locale-precedence (8179408) with main (366c18c)2

Open in CodSpeed

Footnotes

  1. 70 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

  2. No successful run was found on main (6f5138a) during the generation of this report, so 366c18c was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

@costajohnt
costajohnt force-pushed the fix/8922-lc-all-locale-precedence branch 2 times, most recently from 181d188 to 14822ba Compare July 20, 2026 04:45
@github-actions

Copy link
Copy Markdown

Binary size comparison:

Individual binary size comparison VS main (threshold: >=5% AND >=4 KB).

Total size of compared binaries: 147.12 MB (-4.13 MB, -2.73%)

Significant per-binary changes:
  ls     3.28 MB ->    2.11 MB  (-1.17 MB, -35.76%)

@sylvestre
sylvestre force-pushed the fix/8922-lc-all-locale-precedence branch from c557bb2 to 913aa3f Compare August 27, 2026 21:22
@costajohnt
costajohnt force-pushed the fix/8922-lc-all-locale-precedence branch from 913aa3f to 12c9701 Compare October 6, 2026 17:36
costajohnt and others added 4 commits October 24, 2026 17:38
detect_system_locale() only read LANG, ignoring LC_ALL and LC_MESSAGES.
POSIX message-locale precedence is LC_ALL > LC_MESSAGES > LANG: the first
of those that is set and non-empty wins (set-but-empty is treated as
unset), falling back to en-US when none qualify.

Extract the precedence + encoding-stripping into a pure resolve_locale_string
helper that takes an env lookup closure, so the logic is unit-tested without
mutating process-global env vars (which race under parallel test threads).
detect_system_locale() passes std::env::var through it, preserving the exact
old string handling (only which variable supplies the value changed).
The GNU testsuite -mb runs set LANGUAGE=C LANG=C before overriding
LC_ALL to fr_FR.UTF-8, and GNU tools stay English there because
gettext gives LANGUAGE priority over LC_ALL. Walk LANGUAGE for the
first usable entry (trimmed, codeset-stripped); C/POSIX entries and
a C/POSIX resolved locale (including C.UTF-8) resolve to English
explicitly. Deliberate divergences from gettext's per-catalog walk
are documented in the doc comment.

Also fix test_env_french and test_chmod_colored_output, which set
only LANG and relied on the LANG-only lookup this branch removes;
the harness's default LC_ALL=C now correctly outranks it.
Resolve LC_ALL/LC_MESSAGES/LANG plus LANGUAGE into a priority list and
try each candidate until one has a translation catalog, instead of
keeping the first entry that merely parses. A language-only entry now
also matches a catalog of the same language (fr -> fr-FR), and, like
gettext, a set LANGUAGE is no longer backed by the resolved locale: an
exhausted list means untranslated output.
@costajohnt
costajohnt force-pushed the fix/8922-lc-all-locale-precedence branch from 12c9701 to 508efc9 Compare October 25, 2026 00:41

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

l10n: LC_ALL is ignored

2 participants