From 74c32610f38a76247cda81c8d0f68ee46b751328 Mon Sep 17 00:00:00 2001 From: MegaBrutal Date: Thu, 12 Mar 2026 23:45:00 +0100 Subject: [PATCH 1/3] Tests for Hungarian locale --- tests/by-util/test_date.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 3b8bd13f83d..489f15158f8 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -1622,6 +1622,32 @@ fn test_date_locale_en_us_vs_c_difference() { } } +#[test] +#[cfg(unix)] +fn test_date_locale_hu_hungarian() { + // Regression test for uutils/coreutils#11240: the GNU modifier fast-path + // ("%-e") used to run before ICU localization, so "%b"/"%A" came out in + // English even under hu_HU.UTF-8. Pin an explicit format string so the + // assertion is deterministic across glibc versions (the default D_T_FMT + // for hu_HU differs between distros). + if !is_locale_available("hu_HU.UTF-8") { + return; + } + + let result = new_ucmd!() + .env("LC_ALL", "hu_HU.UTF-8") + .env("TZ", "UTC") + .arg("-d") + .arg("2025-12-14T13:00:00") + .arg("+%Y. %b %-e., %A, %H:%M:%S %Z") + .succeeds(); + + assert_eq!( + result.stdout_str(), + "2025. dec 14., vasárnap, 13:00:00 UTC\n" + ); +} + #[test] #[cfg(any(target_os = "linux", target_os = "android", target_vendor = "apple"))] fn test_date_locale_fr_french() { @@ -2273,6 +2299,7 @@ fn test_locale_month_names() { ("es_ES.UTF-8", "enero", "junio", "diciembre"), ("it_IT.UTF-8", "gennaio", "giugno", "dicembre"), ("pt_BR.UTF-8", "janeiro", "junho", "dezembro"), + ("hu_HU.UTF-8", "január", "június", "december"), ("ja_JP.UTF-8", "1月", "6月", "12月"), ("zh_CN.UTF-8", "一月", "六月", "十二月"), ] { From cefcc768f2ba10183fa344b00016bc626368d178 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 5 Apr 2026 22:14:17 +0200 Subject: [PATCH 2/3] date: apply locale-aware localization before GNU modifier processing Formats like "%-e" previously bypassed ICU localization of "%b"/"%A" because the modifier fast-path ran before localize_format_string(). Localize first, then run the modifier pass on the already-localized format. Fixes uutils/coreutils#11240. --- src/uu/date/src/date.rs | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/uu/date/src/date.rs b/src/uu/date/src/date.rs index 89ee23fd31e..ab7cbf680c6 100644 --- a/src/uu/date/src/date.rs +++ b/src/uu/date/src/date.rs @@ -709,31 +709,27 @@ fn format_date_with_locale_aware_months( #[cfg(feature = "i18n-datetime")] skip_localization: bool, #[cfg(not(feature = "i18n-datetime"))] _skip_localization: bool, ) -> Result { - // First check if format string has GNU modifiers (width/flags) and format if present - // This optimization combines detection and formatting in a single pass - if let Some(result) = - format_modifiers::format_with_modifiers_if_present(date, format_string, config) - { + // Apply locale-aware name substitution (month/day names) before modifier + // processing, so that formats like "%-e" don't bypass localization of "%b"/"%A". + // The owned String is kept in `localized` so `fmt` can borrow from it for the + // rest of the function without a dangling reference. + #[cfg(feature = "i18n-datetime")] + let localized: Option = (!skip_localization && should_use_icu_locale()) + .then(|| localize_format_string(format_string, date.date())); + #[cfg(feature = "i18n-datetime")] + let fmt: &str = localized.as_deref().unwrap_or(format_string); + #[cfg(not(feature = "i18n-datetime"))] + let fmt = format_string; + + // Check if format string has GNU modifiers (width/flags) and format if present + if let Some(result) = format_modifiers::format_with_modifiers_if_present(date, fmt, config) { return result.map_err(|e| e.to_string()); } let broken_down = BrokenDownTime::from(date); - - // When the i18n-datetime feature is enabled (default), use ICU locale-aware - // formatting if the locale requires it. Without the feature (e.g. wasi/wasm - // builds that use --no-default-features), skip localization entirely and - // format with the raw strftime string. - #[cfg(feature = "i18n-datetime")] - let result = if !should_use_icu_locale() || skip_localization { - broken_down.to_string_with_config(config, format_string) - } else { - let fmt = localize_format_string(format_string, date.date()); - broken_down.to_string_with_config(config, &fmt) - }; - #[cfg(not(feature = "i18n-datetime"))] - let result = broken_down.to_string_with_config(config, format_string); - - result.map_err(|e| e.to_string()) + broken_down + .to_string_with_config(config, fmt) + .map_err(|e| e.to_string()) } /// Return the appropriate format string for the given settings. From d7751ac5382a83d92cf9d53c28185608b60e7c5c Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 5 Apr 2026 23:07:49 +0200 Subject: [PATCH 3/3] ci: install hu_HU.UTF-8 (and peers) for l10n cargo test job --- .github/workflows/l10n.yml | 12 ++++++++++++ tests/by-util/test_date.rs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/l10n.yml b/.github/workflows/l10n.yml index 98504f99778..11b2c52e748 100644 --- a/.github/workflows/l10n.yml +++ b/.github/workflows/l10n.yml @@ -56,6 +56,18 @@ jobs: ubuntu-*) # selinux headers needed for testing sudo apt-get -y update ; sudo apt-get -y install libselinux1-dev + # Locales required by tests/by-util/test_date.rs and + # tests/by-util/test_dd.rs (fr_FR is the ISO-8859-1 variant + # used by test_iso8859_1_case_conversion). + sudo locale-gen --keep-existing fr_FR + sudo locale-gen --keep-existing fr_FR.UTF-8 + sudo locale-gen --keep-existing es_ES.UTF-8 + sudo locale-gen --keep-existing en_US.UTF-8 + sudo locale-gen --keep-existing fa_IR.UTF-8 # Iran + sudo locale-gen --keep-existing am_ET.UTF-8 # Ethiopia + sudo locale-gen --keep-existing th_TH.UTF-8 # Thailand + sudo locale-gen --keep-existing hu_HU.UTF-8 # Hungary + sudo update-locale ;; macos-*) # needed for testing diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 489f15158f8..7096e2040ee 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -3,7 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // -// spell-checker: ignore: AEDT AEST EEST NZDT NZST Kolkata Iseconds févr février janv janvier mercredi samedi sommes juin décembre Januar Juni Dezember enero junio diciembre gennaio giugno dicembre junho dezembro lundi dimanche Montag Sonntag Samstag sábado febr MEST KST uueuu ueuu +// spell-checker: ignore: AEDT AEST EEST NZDT NZST Kolkata Iseconds févr février janv janvier mercredi samedi sommes juin décembre Januar Juni Dezember enero junio diciembre gennaio giugno dicembre junho dezembro lundi dimanche Montag Sonntag Samstag sábado febr MEST KST uueuu ueuu vasárnap június január distros // spell-checker: ignore: uppercases use std::cmp::Ordering;