Search code examples
javascriptc#asp.net-mvc-4globalization

Double ToString keeping "en-US" format


Sounds simples - And I know it is... but i'm having issues with it and don't know why exactly..

I have a web application globalized (multilanguages). When I click to change the language, this is my action:

public ActionResult ChangeCulture(string lang)
{
    Thread.CurrentThread.CurrentCulture = new CultureInfo(lang);
    Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;

    var languageCookie = new HttpCookie("_language") { Value = lang, Expires = DateTime.UtcNow.AddYears(1) };

    Response.Cookies.Remove("_language");
    Response.SetCookie(languageCookie);

    return Redirect(Request.UrlReferrer.PathAndQuery);
}

And I have a page to display some char (I'm using chart.js) and I need to bind a List<double> to a javascript array.

So this list looks like:

var list = new List<double> {144, 0, 540.23};

And I need a simples array in javascript:

var arr = [144, 0, 540.23];

Here is how I'm doing (razor):

var arr = [@string.Join(",", Model.ListWithDoubles.Select(x => Convert.ToString(x, new CultureInfo("en-US"))))]

The problem is:

When I'm using english language its works pretty. The others langues gives me integer numbers instead...

var arr = [144, 0, 540.23]; //en-US
var arr = [144, 0, 54023]; //pt-BR 
var arr = [144, 0, 54023]; //it
var arr = [144, 0, 54023]; //es

Questions

  1. Why?
  2. How to fix?

Solution

  • Because in some other non en-US cultures the , and . have the exact opposite meaning and usage. If you are not displaying this data, only for chart purposes, then use CultureInfo.InvariantCulture when converting the double to string representation for the HTML. You should only convert to a culture specific string at the point you want to actually visually display that data value to the user.

    var arr = [@string.Join(",", Model.ListWithDoubles.Select(x => Convert.ToString(x, CultureInfo.InvariantCulture)))]
    

    The default format specifier for double is G so it will create output with only a decimal separator. As you want the raw number (not formatted for display) then this (CultureInfo.InvariantCulture) is what you need to pass, not the culture formatted string representation as that is for display only.


    To illustrate that the code I posted works regardless of the culture of the current thread here is that code. Drop this into a console application and replace the Main method and run it. You will see that this works. Your issue lies elsewhere, not with this code.

    static void Main(string[] args)
    {
        var cultures = new[] {"en-US", "pt-BR", "it", "es"};
        var list = new List<double> {144, 0, 540.23};
    
        Console.WriteLine("Without specifying a culture");
    
        foreach (var culture in cultures.Select(isoCulture => new CultureInfo(isoCulture)))
        {
            System.Threading.Thread.CurrentThread.CurrentCulture = culture;
            System.Threading.Thread.CurrentThread.CurrentUICulture = culture;
    
            Console.WriteLine("Culture: " + culture.Name);
    
            Console.WriteLine("Not defined:                  " + string.Join(",", list.Select(x => Convert.ToString(x))));
            Console.WriteLine("CultureInfo.InvariantCulture: " + string.Join(",", list.Select(x => Convert.ToString(x, CultureInfo.InvariantCulture))));
        }
        Console.ReadLine(); // stops so you can see the results
    }