Repository: dotnet/aspnetcore
File: src/Components/WebAssembly/WebAssembly/src/Hosting/WebAssemblyCultureProvider.cs (C#)

Code before:
        await WebAssemblyCultureProviderInterop.LoadSatelliteAssemblies(culturesToLoad);
    }

    internal static string[] GetCultures(CultureInfo? cultureInfo, CultureInfo? uiCultureInfo = null)
    {
        var culturesToLoad = new List<string>();

        // Once WASM is ready, we have to use .NET's assembly loading to load additional assemblies.
        // First calculate all possible cultures that the application might want to load. We do this by
        // starting from the current culture and walking up the graph of parents.
        // At the end of the the walk, we'll have a list of culture names that look like
        // [ "fr-FR", "fr" ]
        while ((cultureInfo != null && cultureInfo != CultureInfo.InvariantCulture) || (uiCultureInfo != null && uiCultureInfo != CultureInfo.InvariantCulture))
        {
            if (cultureInfo != null && cultureInfo != CultureInfo.InvariantCulture)
            {
                culturesToLoad.Add(cultureInfo.Name);
            }

            if (uiCultureInfo?.Name != cultureInfo?.Name && uiCultureInfo != null && uiCultureInfo != CultureInfo.InvariantCulture)
            {
                culturesToLoad.Add(uiCultureInfo.Name);
            }

            cultureInfo = (cultureInfo?.Parent == cultureInfo) ? null : cultureInfo?.Parent;
            uiCultureInfo = (uiCultureInfo?.Parent == uiCultureInfo) ? null : uiCultureInfo?.Parent;
        }

        return culturesToLoad.ToArray();
    }

    private partial class WebAssemblyCultureProviderInterop
    {
        [JSImport("INTERNAL.loadSatelliteAssemblies")]
        public static partial Task LoadSatelliteAssemblies(string[] culturesToLoad);
    }
}


Review comment (bug):
The logic for detecting when to stop traversing the culture hierarchy is incorrect. When `cultureInfo.Parent == cultureInfo`, it means we've reached the root culture, but the code sets `cultureInfo` to null instead of stopping the loop. This could cause issues if the UI culture still needs processing. Consider using a flag-based approach or restructuring the loop to handle each culture independently.

Code after:

        await WebAssemblyCultureProviderInterop.LoadSatelliteAssemblies(culturesToLoad);
    }

    internal static string[] GetCultures(CultureInfo cultureInfo, CultureInfo? uiCultureInfo = null)
    {
        // Once WASM is ready, we have to use .NET's assembly loading to load additional assemblies.
        // First calculate all possible cultures that the application might want to load. We do this by
        // starting from the current culture and walking up the graph of parents.
        // At the end of the the walk, we'll have a list of culture names that look like
        // [ "fr-FR", "fr" ]

        var culturesToLoad = GetCultureHierarchy(cultureInfo);
        if (cultureInfo != uiCultureInfo)
        {
            foreach (var culture in GetCultureHierarchy(uiCultureInfo))
            {
                if (!culturesToLoad.Contains(culture))
                {
                    culturesToLoad = culturesToLoad.Append(culture);
                }
                // If the culture is in the list, we can break because we found the common parent.
                else
                {
                    break;
                }
            }
        }

        return culturesToLoad.ToArray();
    }

    private static IEnumerable<string> GetCultureHierarchy(CultureInfo? culture)
    {
        while (culture != CultureInfo.InvariantCulture && culture != null)
        {
            yield return culture.Name;
            if (culture == culture.Parent)
            {
                break;
            }
            culture = culture.Parent;
        }
    }

    private partial class WebAssemblyCultureProviderInterop
    {
        [JSImport("INTERNAL.loadSatelliteAssemblies")]
        public static partial Task LoadSatelliteAssemblies(string[] culturesToLoad);
    }
}