Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this a good approach for temporarily changing the current thread's culture?

Tags:

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?

like image 714
Jesse Taber Avatar asked Apr 26 '11 15:04

Jesse Taber


People also ask

How do you change the current UI culture?

NET Framework 4.6, you can change the current UI culture by assigning a CultureInfo object that represents the new culture to the CultureInfo. CurrentUICulture property. The current UI culture can be set to either a specific culture (such as en-US or de-DE) or to a neutral culture (such as en or de).

How do I change the current culture in C#?

CurrentCulture = New CultureInfo("th-TH", False) Console. WriteLine("CurrentCulture is now {0}.", CultureInfo.CurrentCulture.Name) ' Display the name of the current UI culture. Console. WriteLine("CurrentUICulture is {0}.", CultureInfo.CurrentUICulture.Name) ' Change the current UI culture to ja-JP.

What is difference between CurrentCulture and CurrentUICulture?

CurrentCulture is the . NET representation of the default user locale of the system. This controls default number and date formatting and the like. CurrentUICulture refers to the default user interface language, a setting introduced in Windows 2000.


1 Answers

I like the using approach. I'd also create an extension method to make things read better:

var customerCulture = new CultureInfo(currentCustomer.Locale);   using (customerCulture.AsCurrent()) {   invoiceService.CreateInvoice(currentCustomer.CustomerId); } 

Something like this:

public static class CultureInfoExtensions {   public static IDisposable AsCurrent(this CultureInfo culture) {     return new CultureRunner(culture);   } } 

CultureRunner example:

public class CultureRunner : IDisposable {     readonly CultureInfo originalCulture;     readonly CultureInfo originalUICulture;      public CultureRunner(CultureInfo culture)     {         if (culture == null)             throw new ArgumentNullException(nameof(culture));          originalCulture = Thread.CurrentThread.CurrentCulture;         originalUICulture = Thread.CurrentThread.CurrentUICulture;          Thread.CurrentThread.CurrentCulture = culture;         Thread.CurrentThread.CurrentUICulture = culture;     }      public void Dispose()     {         Thread.CurrentThread.CurrentCulture = originalCulture;         Thread.CurrentThread.CurrentUICulture = originalUICulture;     } } 

Or, if it's always your customer object who sets the culture, another extension method would raise the abstraction even further:

using (currentCustomer.CultureContext()) {   invoiceService.CreateInvoice(currentCustomer.CustomerId); } 
like image 151
Jordão Avatar answered Oct 05 '22 03:10

Jordão