全局覆盖特定区域性的所有实例的月份名称

时间:2010-12-17 19:31:15

标签: .net asp.net cultureinfo

所以,我有这个问题,微软实际上让格陵兰文化(kl-GL)的月名错了。我也知道我可以将自己的字符串数组传递给DateTimeFormatInfo.MonthNames属性,但似乎我指定的值仅用于该一个CultureInfo实例的范围。有没有办法告诉.Net,每当我有一个kl-GL文化的实例时,应该使用这些特定的月份名?

我知道您可以创建特定于用户的文化,但我无法访问某些遗留代码来实际更改代码以使用我自己的用户指定文化。

6 个答案:

答案 0 :(得分:2)

为什么需要一个或两个以上的CultureInfo对象?您可以将线程文化(System.Threading.Thread.CurrentThread.CurrentCulture)或线程UI文化(System.Threading.Thread.CurrentThread.CurrentUICulture)更改为您需要的值。然后,如果需要显式引用,则可以使用当前区域性或引用CurrentThread中的对象。

答案 1 :(得分:1)

取代特定的文化。

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();

不要执行此操作!它将覆盖您的文化设置。根据需要进行调整。

创造新的特定文化。

    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"));

    }

在ASP.NET中使用新文化与将其添加到web.config:

一样简单

< globalization culture =“kl-GL-custom”uiCulture =“kl-GL-custom”/>

或者这样做

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

        base.InitializeCulture();
    }

答案 2 :(得分:1)

你去吧

    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 /> "); 
    }

注意:仅适用于.NET 4.0

答案 3 :(得分:1)

我认为@Dirk的答案是最好的。在this MSDN page上,它解释了如何初始化ASP.NET页面的文化:

  
      
  1. 覆盖页面的InitializeCulture方法。   
        
    1. 在重写方法中,确定将页面设置为的语言和文化。
    2.   
    3. 通过以下方式之一设置UI文化和文化:   
          
      • 将页面的Culture和UICulture属性设置为语言和文化字符串(例如,en-US)。这些属性是页面内部的,只能在页面中使用。
      •   
      • 分别将当前线程的CurrentUICulture和CurrentCulture属性设置为UI文化和区域性。 CurrentUICulture属性采用语言和文化信息字符串。要设置CurrentCulture属性,请创建CultureInfo类的实例并调用其CreateSpecificCulture方法。
      •   
    4.   
  2.   

示例:

public class YourCodeBehind : Page
{
    protected override void InitializeCulture()
    {
        CultureInfo cultureInfo = new CultureInfo("kl-GL");
        cultureInfo.DateTimeFormat.MonthNames = new string[] { ... };
        Thread.CurrentThread.CurrentCulture = cultureInfo;
    }
}

答案 4 :(得分:0)

这完全是一个黑客/暴力答案,但你可以处理Page_PreRender事件,检测文化,然后在这些单词发送到浏览器之前对这些单词进行字符串替换。

我不知道这是什么意思。

答案 5 :(得分:0)

您可能想要研究模拟框架TypeMock Isolator。有了它,你可以覆盖CLR中的许多东西,包括从“新”调用返回的内容。因此,如果您要设置一个“假的”CultureInfo,其中更正的月份名称接近您的程序的入口点,则每次调用new CultureInfo("kl-GL")都会返回您更正的实例。

性能影响不大(TypeMock显然可以通过CLR的分析钩子工作),但值得研究的是,正确性的好处是否超过了性能损失。