Skip to content

Type initialization for Culture fails if installed cultures contains invalid neutral ancestry #82

@General-Fault

Description

@General-Fault

The Gu.Localization.Culture static initializer throws a KeyNotFoundException while setting the NeutralCultrureRegionMap if the computer has a neutral culture installed (or one incorrectly marked as neutral) without a corresponding specific culture.

I have not been able to determine the full steps to reproduce simply because I don't know how the clients computer got into this state. However I can describe the state and perhaps someone with more knowledge about configuring CultureInfo's on the system can share steps to create the state.

Essentially, the computer had two cultures marked as neutral "bal" and "bal-Arab". Perhaps "bal-Arab" should not be marked as neutral. When the static class Gu.Localization.Culture is initialized, it creates a NeutralCultureRegionMap by iterating the neutral cultures (in this case both "bal" and "bal-Arab") and creates "specific" cultures. So for the neutral "en" culture, it creates "en-US" as the specific culture, then it attempts to find that culture in Gu.Localization.Culture.NameCultureMap using the indexer. For the client computer, neither "bal" and "bal-Arab" neutral cultures have an associated specific culture.

private static readonly Dictionary<CultureInfo, RegionInfo> NeutralCultureRegionMap =
            AllCultures
                .Where(x => x.IsNeutralCulture)
                .Select(x => NameCultureMap[CultureInfo.CreateSpecificCulture(x.Name).Name])
                .Distinct(CultureInfoComparer.ByTwoLetterIsoLanguageName)
                .ToDictionary(
                    x => x.Parent,
                    x => CultureRegionMap[x],
                    CultureInfoComparer.ByTwoLetterIsoLanguageName);

This script

 [System.Globalization.CultureInfo]::GetCultures([System.Globalization.CultureTypes]::AllCultures) | ? {$_.Name.StartsWith("bal")} | fl *

Produced this output (with some irrelevant info striped):

Parent : bal
LCID : 8192
Name : bal-Arab
IetfLanguageTag : bal-Arab
DisplayName : Unknown Language (bal-Arab)
ThreeLetterWindowsLanguageName : ZZZ
TwoLetterISOLanguageName : bal
IsNeutralCulture : True
CultureTypes : NeutralCultures, InstalledWin32Cultures <-- Note incorrect CultureType
UseUserOverride : True
IsReadOnly : False

Parent : bal-Arab
LCID : 12288
Name : bal-Arab-001
DisplayName : Unknown Locale (bal-Arab-001)
TwoLetterISOLanguageName : bal
ThreeLetterWindowsLanguageName : ZZZ
IsNeutralCulture : False
CultureTypes : SpecificCultures, InstalledWin32Cultures
UseUserOverride : True
IsReadOnly : False

Parent :
LCID : 13312
Name : bal
DisplayName : Unknown Language (bal)
TwoLetterISOLanguageName : bal
ThreeLetterWindowsLanguageName : ZZZ
IsNeutralCulture : True
CultureTypes : NeutralCultures, InstalledWin32Cultures
UseUserOverride : True
IsReadOnly : False

When Gu.Localization is used in any way, this error will be thrown:

System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at Gu.Localization.Culture.<>c.<.cctor>b__12_12(CultureInfo x)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Enumerable.<DistinctIterator>d__64`1.MoveNext()
   at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
   at Gu.Localization.Culture..cctor() -- System.TypeInitializationException: The type initializer for 'Gu.Localization.Translator' threw an exception. ---> System.TypeInitializationException: The type initializer for 'Gu.Localization.Culture' threw an exception. ---> System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at Gu.Localization.Culture.<>c.<.cctor>b__12_12(CultureInfo x)
   at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
   at System.Linq.Enumerable.<DistinctIterator>d__64`1.MoveNext()
   at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
   at Gu.Localization.Culture..cctor()
   --- End of inner exception stack trace ---
   at Gu.Localization.Culture.TryGet(String name, CultureInfo& culture)
   at Gu.Localization.ResourceCultures.GetAllCultures(DirectoryInfo executingDirectory)
   at Gu.Localization.Translator.GetAllCultures()
   at Gu.Localization.Translator..cctor()
   --- End of inner exception stack trace ---
   at Gu.Localization.Translator.ContainsCulture(CultureInfo language)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions