How to detect Globalization-Invariant mode in .NET

 
 
  • Gérald Barré

Some libraries don't work when the application is running using Globalization-Invariant mode. This mode disabled all globalization features and force the use of the Invariant culture. This mode is useful for applications that don't need globalization features and want to reduce the application size.

If your library doesn't support this mode, you may want to report a good error message to the user. So, you need to detect it correctly. Most of the time, the user will set the DOTNET_SYSTEM_GLOBALIZATION_INVARIANT environment variable to true or 1. But, the user can also set the System.Globalization.Invariant switch in the runtimeconfig.json file (this is what happen when you use the <InvariantGlobalization>true</InvariantGlobalization> property in the csproj file). The runtimeconfig.json file is a file that contains the runtime configuration of the application. Because of native AOT, some info may be stripped when publishing the application, and the only way to validate the change is to try to create a culture. This means you need to check multiple info to detect if the application is running in Globalization-Invariant mode.

C#
static bool IsGlobalizationInvariant()
{
    // Validate the AppContext switch first
    if (AppContext.TryGetSwitch("System.Globalization.Invariant", out bool isEnabled) && isEnabled)
        return true;

    // Then, check the environment variable
    var environmentValue = Environment.GetEnvironmentVariable("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT");
    if (string.Equals(environmentValue, bool.TrueString, StringComparison.OrdinalIgnoreCase) || environmentValue == "1")
        return true;

    // .NET 6 and greater will throw if the culture is not found, unless PredefinedCulturesOnly is set to false.
    // Previous versions will return the Invariant Culture. See the breaking change for more info:
    // https://learn.microsoft.com/en-us/dotnet/core/compatibility/globalization/6.0/culture-creation-invariant-mode?WT.mc_id=DT-MVP-5003978
    //
    // You can detect if a culture is the Invariant culture by checking its name or one of its properties.
    // Note: The Invariant Culture is hard-coded: https://github.com/dotnet/runtime/blob/b69fa275565ceeca8ba39f7f9bcb1e301dd68ded/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs#L547
    try
    {
        return CultureInfo.GetCultureInfo("en-US").EnglishName.Contains("Invariant", StringComparison.Ordinal);

        // Note: A user can change the settings of the culture at the OS level or ICU data, so the following comparison may be true even if the Invariant Mode is disabled.
        // return CultureInfo.GetCultureInfo("en-US").NumberFormat.CurrencySymbol == "¤";
    }
    catch (CultureNotFoundException)
    {
        // PredefinedCulturesOnly is true and the Invariant Mode is enabled
        return true;
    }
}

#Additional resources

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub