C# Corner

.NET Framework 4.5 Multi-Threaded Globalization

Eric Vogel shows you how to use the CultureInfo API in .NET Framework 4.5 to simplify localization in a multi-threaded application.

The .NET Framework 4.5 includes a simplified way of setting the default culture and UI culture for an application domain. In .NET Framework 4 and earlier frameworks, if you wanted to set the Culture and UI Culture for an application, you’d typically set the culture settings on the current Thread. A small problem arose if you created multiple threads, however. By default, a new Thread will use the user’s preferred culture setting. To assign a different culture, you’d have change the culture of the Thread after creating it, or pass in the CultureInfo using a ParameterizedThreadStart constructed Thread.

To demonstrate how to conquer this conundrum, let's create a Windows Presentation Foundation C# sample application using .NET Framework 4. The UI for the demo application will display the user’s preferred culture as well as the UI culture for the newly created Threads and Task. Open up the MainWindow.xaml, and add the markup from the following code into the root <Grid> element:

<StackPanel>
    <TextBlock>User's Preferred Culture</TextBlock>
    <TextBlock Name="UserPreferredCulture" Text="{Binding DisplayName}"></TextBlock>
    <TextBlock>New Thread Parameter UI Culture</TextBlock>
    <TextBlock Name="ThreadUIParamCulture" Text="{Binding DisplayName}"></TextBlock>
    <TextBlock>New Thread Property UI Culture</TextBlock>
    <TextBlock Name="ThreadUIPropCulture" Text="{Binding DisplayName}"></TextBlock>
    <TextBlock>New Task UI Culture</TextBlock>
    <TextBlock Name="TaskUICulture" Text="{Binding DisplayName}"></TextBlock>
</StackPanel>

The cultureParameterized Thread uses a ParameterizedThreadStart setting, to pass the CultureInfo to the Thread, when it's started. The cultureAfter thread is constructed using ThreadStart. The CurrentCulture and CurrentUICulture properties are set prior to being started. If you’re working with a Task, you can pass in the needed CultureInfo as the object state as shown in Listing 1 .

Now when you run the application, you’ll see that the new Threads and Task are using the set UI culture of the calling Thread, which is French, as shown in Figure 1.


[Click on image for larger view.]
Figure 1. The .NET Framework 4 Multi-Threaded Localization Demo

In .NET Framework 4.5, you have the ability to set a default culture for the UI and for any newly created threads. The CultureInfo.DefaultThreadCurrentCulture property is used to set the default culture for any newly created threads, and the CultureInfo.DefaultThreadCurrentUICulture property is used to set the default culture for the UI thread. By using the new properties, you can ensure that any newly created Thread or Task instances will use the set default CultureInfo within the executing AppDomain. Using this approach, the .NET Framework 4 samples above could be updated to no longer need the new CultureInfo setting for the created Thread or Task, as shown in Listing 2 .

The DefaultThreadCurrentCulture and DefaultThreadCurrentUICulture settings are applicable to the current AppDomain. If you create a new AppDomain, then you’ll need to set the DefaultThreadCurrentCulture and DefaultThreadCurrentUICulture for that AppDomain.

Let’s update the existing application to create a new AppDomain and display its set default UI culture. Open up the MainWindow.xaml file for the application, and add a label and TextBlock to display the new AppDomain’s set UI culture as follows:

<TextBlock>New AppDomain UI Culture</TextBlock>
<TextBlock Name="AppDomainUICulture" Text="{Binding DisplayName}"></TextBlock>

Your completed MainWindow.xaml markup file should now resemble the code in Listing 3 .

Now add a new method named AdditionalAppDomain to the MainWindow class of the application. The method will be responsible for creating a new AppDomain with custom default CultureInfo settings. To accomplish this task, first create an AppDomainSetup instance:

AppDomainSetup domainSetup = new AppDomainSetup();

Then call the AppDomainInitializer method on the AppDomainSetup instance passing in an Action<string[]> that sets the default thread culture and UI culture as follows:

domainSetup.AppDomainInitializer = (cultures) =>
 {
     CultureInfo.DefaultThreadCurrentCulture = CultureInfo.CreateSpecificCulture(cultures[0]);
     CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture(cultures[0]);
 };

Now set the initialization arguments for the AppDomainSetup for the needed culture you would call, for example, to set the default culture to Spanish.

domainSetup.AppDomainInitializerArguments = new string[] { "es-ES" };

Now you’re ready to create the actual new AppDomain through the AppDomain.CreateDomain static factory method as follows:

 AppDomain appDomain = AppDomain.CreateDomain("TestDomain", null, domainSetup);

When you call a method on the newly created AppDomain, the default culture will be set to the given culture name, in this case Spanish. Now add a new class called AppDomainCultureData that simply returns the current UI culture for its AppDomain.

public class AppDomainCultureData : MarshalByRefObject
 {
     public CultureInfo GetCultureInfo()
        {
            return CultureInfo.CurrentUICulture;
        } 
}

Next, create a new AppDomainCultureData instance via the new AppDomain, by using the CreateInstanceAndUnwrap method on the new AppDomain object.

AppDomainCultureData appDomainData = (AppDomainCultureData)appDomain.CreateInstanceAndUnwrap
(typeof(AppDomainCultureData).Assembly.FullName,
     typeof(AppDomainCultureData).FullName); 

Update the AppDomainUICulture TextBlock to display the DisplayName property on the new AppDomain’s current UI culture as follows:

Dispatcher.Invoke(() => AppDomainUICulture.DataContext = appDomainData.GetCultureInfo());

The last step is to call the AdditionalAppDomain function from the MainWindow constructor. Your completed MainWindow class should now look like the code shown in Listing 4 .

Now when you run the application, you’ll see the new AppDomain’s set UI culture as Spanish (Spain) as shown in Figure 2.


[Click on image for larger view.]
Figure 2. The .NET Framework 4.5 Multiple App Domains Localization Demo

As you can see, by utilizing the DefaultThreadCurrentCulture and DefaultThreadCurrentUICulture CultureInfo static properties, you can reduce the complexity of dealing with localized cultures in multi-threaded and multiple AppDomain applications.

About the Author

Eric Vogel is a Senior Software Developer for Red Cedar Solutions Group in Okemos, Michigan. He is the president of the Greater Lansing User Group for .NET. Eric enjoys learning about software architecture and craftsmanship, and is always looking for ways to create more robust and testable applications. Contact him at [email protected].

comments powered by Disqus

Featured

  • Full Stack Hands-On Development with .NET

    In the fast-paced realm of modern software development, proficiency across a full stack of technologies is not just beneficial, it's essential. Microsoft has an entire stack of open source development components in its .NET platform (formerly known as .NET Core) that can be used to build an end-to-end set of applications.

  • .NET-Centric Uno Platform Debuts 'Single Project' for 9 Targets

    "We've reduced the complexity of project files and eliminated the need for explicit NuGet package references, separate project libraries, or 'shared' projects."

  • Creating Reactive Applications in .NET

    In modern applications, data is being retrieved in asynchronous, real-time streams, as traditional pull requests where the clients asks for data from the server are becoming a thing of the past.

  • AI for GitHub Collaboration? Maybe Not So Much

    No doubt GitHub Copilot has been a boon for developers, but AI might not be the best tool for collaboration, according to developers weighing in on a recent social media post from the GitHub team.

  • Visual Studio 2022 Getting VS Code 'Command Palette' Equivalent

    As any Visual Studio Code user knows, the editor's command palette is a powerful tool for getting things done quickly, without having to navigate through menus and dialogs. Now, we learn how an equivalent is coming for Microsoft's flagship Visual Studio IDE, invoked by the same familiar Ctrl+Shift+P keyboard shortcut.

Subscribe on YouTube