I work on a fairly large ASP .NET Web Forms application that is currently used primarily in the United States. We are in the process of rolling it out to other parts of the world, which of course means we are currently working on localizing all areas of the application. Generally speaking our approach has been to set the current thread's CurrentCulture and CurrentUICulture properties at the beginning of each request to support the proper formatting and resource extraction based on the current user's locale.
In some cases, however, we have a need to run a certain bit of a code using a culture other than the culture of the current user. For example, 'User A' lives in Germany but works for a company that does business with other companies in France. When 'User A' wants to create an invoice (PDF) for one of those French companies, we want that invoice generation code to run with the 'fr-FR' culture rather than the 'de-DE' culture.
I've considered a couple ways of doing this easily and am wondering if I'm going about this correctly. My main concerns are around performance and thread safety.
One approach involves a static method designed to run a given task with a provided culture. Something like this:
public static void RunWithCulture(CultureInfo culture, Action task)
{
if (culture == null)
throw new ArgumentNullException("culture");
var originalCulture = new
{
Culture = Thread.CurrentThread.CurrentCulture,
UICulture = Thread.CurrentThread.CurrentUICulture
};
try
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
task();
}
finally
{
Thread.CurrentThread.CurrentCulture = originalCulture.Culture;
Thread.CurrentThread.CurrentUICulture = originalCulture.UICulture;
}
}
This method could then be invoked like this:
var customerCulture = new CultureInfo(currentCustomer.Locale);
CultureRunner.RunWithCulture(customerCulture, () => invoiceService.CreateInvoice(currentCustomer.CustomerId));
I've also considered creating a class that implements IDisposable that would be responsible for setting the thread culture in it's ctor and then returning the original cultures back in the Dispose method, so you could call it like this:
var customerCulture = new CultureInfo(currentCustomer.Locale);
using(new CultureRunner(currentCustomer.Locale))
{
invoiceService.CreateInvoice(currentCustomer.CustomerId);
}
Am I going about this all wrong? Which, if any of these approaches is preferable?