Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Globally overrride MonthNames for all instances of a specific culture

So, i have this problem where Microsoft actually got the month names wrong for the Greenlandic culture (kl-GL). I also know that i can pass my own array of string to the DateTimeFormatInfo.MonthNames Property, but it seems like the values i specify is only used in the scope of that one CultureInfo instance. Is there a way to tell .Net that every time i have an instance of the kl-GL culture these specific monthnames should be used?

I know that you can create user specific cultures, but i don't have access to some legacy code to actually change the code to use a my own userspecified culture.

like image 656
Pauli Østerø Avatar asked Dec 17 '10 19:12

Pauli Østerø


3 Answers

Why do you need more than one or two CultureInfo object? You can change the threading culture (System.Threading.Thread.CurrentThread.CurrentCulture) or the threading UI culture (System.Threading.Thread.CurrentThread.CurrentUICulture) to the values you need. Then you can use current culture or refer to the objects in CurrentThread if you need an explicit reference.

like image 176
Dirk Brockhaus Avatar answered Oct 23 '22 22:10

Dirk Brockhaus


Here you go

    public static void RenameMonthNames(string cultureName, string[] newNames)
    {
        RenameMonthNames(cultureName, newNames, false);
        RenameMonthNames(cultureName, newNames, true);
    }


    public static void RenameMonthNames(string cultureName, string[] newNames, bool custom)
    {
        var nonPublicAndInstance = BindingFlags.NonPublic | BindingFlags.Instance;

        var culture = new CultureInfo(cultureName, custom);

        int calendarId = (int)typeof (System.Globalization.Calendar).GetProperty("ID", nonPublicAndInstance).GetValue(culture.Calendar, new object[0]);

        object cultureData = culture.GetType().GetField("m_cultureData", nonPublicAndInstance).GetValue(culture);

        cultureData.GetType().GetField("bUseOverrides", nonPublicAndInstance).SetValue(cultureData, false); // Magic hack!!!

        object calendarData = cultureData.GetType().GetMethod("GetCalendar", nonPublicAndInstance).Invoke(cultureData, new object[] { calendarId });

        calendarData.GetType().GetField("saMonthNames", nonPublicAndInstance).SetValue(calendarData, newNames);
        calendarData.GetType().GetField("saLeapYearMonthNames", nonPublicAndInstance).SetValue(calendarData, newNames);
        calendarData.GetType().GetField("saMonthGenitiveNames", nonPublicAndInstance).SetValue(calendarData, newNames);
    }

    public  void TestCultureInfoHack()
    {
        RenameMonthNames("da-DK", new string[]
                                      {
                                          "jan1", "feb2", "mar3", "apr", "may", "jun",
                                          "jul", "aug", "sep", "okt", "nov", "dec12", string.Empty
                                      });

        var today = DateTime.Now.ToLongDateString();
        Thread.CurrentThread.CurrentCulture = new CultureInfo("kl-gl", false);
        Response.Write(DateTime.Now.ToLongDateString());

        Response.Write("<br /> "); 

        Thread.CurrentThread.CurrentCulture = new CultureInfo("kl-GL");
        Response.Write(DateTime.Now.ToLongDateString());
        Response.Write("<br /> "); 
    }

NOTE: only for .NET 4.0

like image 34
Dmitry Dzygin Avatar answered Oct 24 '22 00:10

Dmitry Dzygin


Replacing a specific culture.

var cultureBuilder = new CultureAndRegionInfoBuilder(
               "kl-GL", CultureAndRegionModifiers.Replacement);

cultureBuilder.LoadDataFromCultureInfo(new CultureInfo("kl-GL"));

cultureBuilder.GregorianDateTimeFormat.MonthNames = new []
                       {
                            "jan", "feb", "mar", "apr", "may", "jun",
                            "jul", "aug", "sep", "okt", "nov", "dec",
                            string.Empty    // needs to be here!!!
                       };

cultureBuilder.Register();

Don't execute this! It will overwrite your culture settings. Adjust as you need it.

Creating a new specific culture.

    static void Main(string[] args)
    {
        try
        {
           var builder = new CultureAndRegionInfoBuilder(
                "kl-GL-custom",
                CultureAndRegionModifiers.None);

            // bind the properties
            builder.LoadDataFromCultureInfo(new CultureInfo("kl-GL"));
            builder.LoadDataFromRegionInfo(new RegionInfo("kl-GL"));

            // make custom changes to the culture
            builder.GregorianDateTimeFormat.MonthNames = new []
                {
                    "jan", "feb", "mar", "apr", "may", "jun",
                    "jul", "aug", "sep", "okt", "nov", "dec",
                    string.Empty    // needs to be here!!!
                };

            // one time operation! needs admin rights!
            builder.Register();
        }
        catch
        {
        }

        Thread.CurrentThread.CurrentCulture = 
            Thread.CurrentThread.CurrentUICulture = 
                new CultureInfo("kl-GL-custom");

        Console.WriteLine(DateTime.Today.ToString("MMMM"));

    }

Using the new culture in ASP.NET is as trivial as adding this to your web.config:

<globalization culture="kl-GL-custom" uiCulture="kl-GL-custom"/>

or do this

    protected override void InitializeCulture()
    {
        Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = new CultureInfo("kl-GL-custom");

        base.InitializeCulture();
    }
like image 1
Steven K. Avatar answered Oct 23 '22 23:10

Steven K.