fix(cv): force language alias precedence over host culture data
The CI backend test job failed on HumanLanguageCatalogTests:
nynorsk -> expected "Norwegian", actual "Norwegian Nynorsk"
This was a real bug, correctly caught by the runner -- not runner
instability. Reproduced on Ubuntu 20.04 / libicu66 (the CI runner's ICU)
with .NET 9 installed via dotnet-install.sh exactly as CI does.
Root cause: BuildLanguageLookup's explicit normalization aliases
(nynorsk/bokmål/norsk -> Norwegian) were added with map.TryAdd, which
loses to any key the culture enumeration already inserted. On libicu66
the "nn" culture's NativeName is the bare word "nynorsk", so enumeration
claimed key "nynorsk" -> "Norwegian Nynorsk" first and the explicit alias
silently lost. On libicu70+ (Debian/Ubuntu 22.04+, my earlier local
runs) the native name is "norsk nynorsk", so the key was free and the
alias won -- which is why it passed locally and only failed on the
runner's older ICU. Same host-ICU dependence class as 9681618.
Fix: add an Override helper (map[key] = value) and apply it to the
alias block so these mappings win regardless of insertion order. Also
collapse the full "Norwegian Nynorsk"/"Norwegian Bokmål" phrases to
"Norwegian" for consistency. Correct by construction for any ICU version.
Verified:
- reproduced the exact failure on libicu66 with the old code (probe)
- fix logic yields nynorsk/bokmål -> Norwegian on that same libicu66
- real net9 test DLL: 420/420 on focal libicu66 (CI mirror, dotnet
9.0.316 via dotnet-install.sh), and 420/420 on libicu72 (Debian) and
libicu74 (Ubuntu 24.04), plus locally
No test weakened, skipped, or relaxed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -103,6 +103,20 @@ public static class HumanLanguageCatalog
|
||||
map.TryAdd(normalizedAlias, normalizedCanonical);
|
||||
}
|
||||
|
||||
// Force an alias to a canonical, overriding whatever culture enumeration inserted for that
|
||||
// key. TryAdd is not enough here: on a host whose ICU data carries a "Norwegian Nynorsk"
|
||||
// culture, the enumeration below claims the key "nynorsk" -> "Norwegian Nynorsk" first, and a
|
||||
// later TryAdd("nynorsk", "Norwegian") silently loses. That made "nynorsk" resolve to
|
||||
// "Norwegian Nynorsk" on the CI runner but "Norwegian" locally — the same host-ICU dependence
|
||||
// this seeding exists to remove. Overrides must win regardless of insertion order.
|
||||
void Override(string alias, string canonical)
|
||||
{
|
||||
var normalizedAlias = NormalizeKey(alias);
|
||||
var normalizedCanonical = NormalizeDisplayName(canonical);
|
||||
if (string.IsNullOrWhiteSpace(normalizedAlias) || string.IsNullOrWhiteSpace(normalizedCanonical)) return;
|
||||
map[normalizedAlias] = normalizedCanonical;
|
||||
}
|
||||
|
||||
// Seeded FIRST, and deliberately not derived from the host.
|
||||
//
|
||||
// This table used to come only from CultureInfo.GetCultures, which returns whatever
|
||||
@@ -145,14 +159,20 @@ public static class HumanLanguageCatalog
|
||||
Add(native, english);
|
||||
}
|
||||
|
||||
Add("norsk", "Norwegian");
|
||||
Add("bokmal", "Norwegian");
|
||||
Add("bokmål", "Norwegian");
|
||||
Add("nynorsk", "Norwegian");
|
||||
Add("mandarin", "Chinese");
|
||||
Add("cantonese", "Chinese");
|
||||
Add("farsi", "Persian");
|
||||
Add("persian", "Persian");
|
||||
// These collapse regional/script variants and common exonyms to the umbrella language a CV
|
||||
// means. They must beat culture enumeration (see Override), because ICU carries "Norwegian
|
||||
// Bokmål"/"Norwegian Nynorsk" and "Chinese (Simplified/Traditional)" as their own cultures.
|
||||
Override("norsk", "Norwegian");
|
||||
Override("bokmal", "Norwegian");
|
||||
Override("bokmål", "Norwegian");
|
||||
Override("nynorsk", "Norwegian");
|
||||
Override("norwegian bokmal", "Norwegian");
|
||||
Override("norwegian bokmål", "Norwegian");
|
||||
Override("norwegian nynorsk", "Norwegian");
|
||||
Override("mandarin", "Chinese");
|
||||
Override("cantonese", "Chinese");
|
||||
Override("farsi", "Persian");
|
||||
Override("persian", "Persian");
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user