全局覆盖特定区域性的所有实例的 MonthNames

发布于 2024-10-08 04:00:41 字数 236 浏览 9 评论 0 原文

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

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

双马尾 2024-10-15 04:00:41

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

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.

过期情话 2024-10-15 04:00:41

给你

    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

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

玻璃人 2024-10-15 04:00:41

取代特定的文化。

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 中一样简单:

或者这样做

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

        base.InitializeCulture();
    }

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();
    }
清晨说晚安 2024-10-15 04:00:41

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

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

例子:

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

I think @Dirk's answer is best. On this MSDN page, it explains how to initialize the culture for an ASP.NET page:

  1. Override the InitializeCulture method for the page.
    1. In the overridden method, determine which language and culture to set the page to.
    2. Set the UI culture and culture in one of the following ways:
      • Set the Culture and UICulture properties of the page to the language and culture string (for example, en-US). These properties are internal to the page, and can only be used in a page.
      • Set the CurrentUICulture and CurrentCulture properties of the current thread to the UI culture and culture, respectively. The CurrentUICulture property takes a language and culture information string. To set the CurrentCulture property, you create an instance of the CultureInfo class and call its CreateSpecificCulture method.

Example:

public class YourCodeBehind : Page
{
    protected override void InitializeCulture()
    {
        CultureInfo cultureInfo = new CultureInfo("kl-GL");
        cultureInfo.DateTimeFormat.MonthNames = new string[] { ... };
        Thread.CurrentThread.CurrentCulture = cultureInfo;
    }
}
愚人国度 2024-10-15 04:00:41

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

我不知道这对性能有何影响。

This is completely a hack/brute force answer, but you could handle the Page_PreRender event, detect the culture, and then and do a string replace on those words before they are sent out to the browser.

I have no idea what the performance implication of this is.

就此别过 2024-10-15 04:00:41

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

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

You may want to investigate the mocking framework TypeMock Isolator. With it you can override many things in the CLR, including what gets returned from a "new" invocation. So if you were to set up a "fake" CultureInfo with the corrected month names close to your program's entry point, each call to new CultureInfo("kl-GL") would return your corrected instance.

The performance implications are not great (TypeMock apparently works via the CLR's profiling hooks), but it is worth investigating if the benefits of correctness outweigh a small performance penalty.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文