Introduction
As we all know, when we run a .NET application, it will use the culture installed in the machine. But sometimes, we want to run our application in a specific culture. In the beginning, I thought it would be very simple, by setting the CurrentCulture
and CurrentUICulture
of the application's thread to the culture we want to use. But, if there is more than one thread running in our application, we will have a problem: the culture of the other threads would still be the installed culture of the machine. Theoretically, we can set the CurrentCulture
and CurrentUICulture
properties of a thread when we start it. But, actually, in some cases, we cannot know exactly when a thread is created or started if it is in a ThreadPool
or is created by the Invoke/BeginInvoke
method of a Control
or a Delegate
.
Background
You should have some knowledge about CultureInfo
. For more details, please go to http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo%28VS.80%29.aspx.
Using the Code
In my demo application, I resolved these problems by creating a class named CultureManager
. It has a static property, CurrentCulture
, which stores the value of the current culture used by the application.
private static CultureInfo _currentCulture = CultureInfo.InvariantCulture;
public static CultureInfo CurrentCulture
{
get { return _currentCulture; }
set
{
if (value == null || value.Equals(_currentCulture))
return;
_currentCulture = value;
}
}
Now, assume we store the name of the culture we want to use in the application's configuration file (to understand more about the CultureInfo
class and its name, please visit http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo%28VS.80%29.aspx). In the CultureManager
class, we have a method to create the specific culture:
public static void LoadApplicationCulture()
{
string cultureName = string.Empty;
try
{
cultureName = ConfigurationSettings.AppSettings["cultureName"];
}
catch
{
cultureName = string.Empty;
}
if (string.IsNullOrEmpty(cultureName))
cultureName = string.Empty;
CurrentCulture = new CultureInfo(cultureName);
}
This method will be called in the Main()
method of the application:
[STAThread]
static void Main()
{
CultureManager.LoadApplicationCulture();
Now, we have the specific culture, and we need to apply this culture for all the threads in our application. To do this, I created a method in the CultureManager
class:
public static void SetThreadCulture(System.Threading.Thread thread)
{
if (!thread.CurrentUICulture.Equals(_currentCulture))
{
thread.CurrentCulture = _currentCulture;
thread.CurrentUICulture = _currentCulture;
}
}
public static void SetCurrentThreadCulture()
{
SetThreadCulture(System.Threading.Thread.CurrentThread);
}
Using this method, we can set the current culture for any thread. For example, to apply a culture for the main thread of the application, we put a call (bold text) in the Main()
method:
[STAThread]
static void Main()
{
CultureManager.LoadApplicationCulture();
CultureManager.SetCurrentThreadCulture();
Of course, we can use this method for other threads we create using the new
keyword. Here is an example:
Thread t = new Thread(new ThreadStart(ShowDialogInNewThread));
CultureManager.SetThreadCulture(t);
t.Start();
Because we always need the call to the SetThreadCulture
method after creating a new thread, I simplify it by adding some CreateThread
methods to create threads in the class. There are four CreateThread
methods, corresponding to the four versions of the constructor of the Thread
object.
#region CreateThread methods
public static Thread CreateThread(ParameterizedThreadStart start)
{
Thread t = new Thread(start);
SetThreadCulture(t);
return t;
}
public static Thread CreateThread(ThreadStart start)
{
Thread t = new Thread(start);
SetThreadCulture(t);
return t;
}
public static Thread CreateThread(ParameterizedThreadStart start,
int maxStackSize)
{
Thread t = new Thread(start, maxStackSize);
SetThreadCulture(t);
return t;
}
public static Thread CreateThread(ThreadStart start, int maxStackSize)
{
Thread t = new Thread(start, maxStackSize);
SetThreadCulture(t);
return t;
}
#endregion
So now, to create a new thread, we simply use one of the four methods:
Thread t = CultureManager.CreateThread(
new ThreadStart(ShowDialogInNewThread));
t.Start();
Next, we have to look for a way to set the culture for the threads created by Invoke/BeginInvoke
methods of a Control
or a Delegate
. This is not very easy because we don't know when this kind of threads are created and started. In case the invoker is a Control
, the problem can be resolved because the created thread will use the culture of that control. But with a Delegate
we create manually, we have to add a call to set the culture of the thread at the beginning of the method represented by that delegate. An example is (the call is in bold text):
private delegate void ShowDialogDelegate();
private void ShowDialog_Callback(IAsyncResult result) { }
private void btnDelegate_Click(object sender, EventArgs e)
{
ShowDialogDelegate showDialogDelegate = ShowDialogByDelegate;
AsyncCallback callback = new AsyncCallback(ShowDialog_Callback);
showDialogDelegate.BeginInvoke(callback, null);
}
private void ShowDialogByDelegate()
{
CultureManager.SetCurrentThreadCulture();
ProgressDialog dlg = new ProgressDialog();
dlg.ShowDialog();
}
In my demo application, the culture is Italian. There are some important notes here:
- The culture name must in the format "-"; for instance, "it-IT" instead of "it", because it helps you to avoid errors like: "Culture 'it' is a neutral culture. It cannot be used in formatting and parsing and therefore cannot be set as the thread's current culture." (See http://msdn.microsoft.com/en-us/library/system.threading.thread.currentculture.aspx for more details).
- To allow a form or control to be localized, you can set their
Localizable
property to true
.
Points of Interest
I also have some code that allows .NET applications to change culture "on the fly", but I still have some issues with it. I will post a new article about it later.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.