Home Articles

有没有办法为整个应用程序设置文化?所有当前线程和新线程?

Asked
Viewed 1449 times
157

Is there a way of setting culture for a whole application? All current threads and new threads?

我们将文化的名称存储在数据库中,当我们的应用程序启动时,我们就会这样做

CultureInfo ci = new CultureInfo(theCultureString);
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;

但是,当然,当我们想在新线程中做某事时,这会得到"lost" . 有没有办法为整个应用程序设置 CurrentCultureCurrentUICulture ?那么新线程也会获得这种文化?或者,只要创建了一个我可以连接的新线程,就会触发某个事件?

9 Answers

  • 179

    实际上,您可以设置默认的线程文化和UI文化,但仅限于Framework 4.5

    我放入了这个静态构造函数

    static MainWindow()
    {
      CultureInfo culture = CultureInfo
        .CreateSpecificCulture(CultureInfo.CurrentCulture.Name);
      var dtf = culture.DateTimeFormat;
      dtf.ShortTimePattern = (string)Microsoft.Win32.Registry.GetValue(
        "HKEY_CURRENT_USER\\Control Panel\\International", "sShortTime", "hh:mm tt");
      CultureInfo.DefaultThreadCurrentUICulture = culture;
    }
    

    并在ValueConverter的Convert方法中放置一个断点,以查看到达另一端的内容 . CultureInfo.CurrentUICulture不再是en-US而是变成en-AU完成了我的小黑客,使其尊重ShortTimePattern的区域设置 .

    华友世纪,一切都很好!或不 . 传递给Convert方法的culture参数仍然是en-US . 呃,WTF?!但这是一个开始 . 至少这样

    • 您可以在应用加载时修复UI文化

    • 始终可以从 CultureInfo.CurrentUICulture 访问

    • string.Format("{0}", DateTime.Now) 将使用您自定义的区域设置

    如果你不能使用框架的4.5版,那么就放弃将CurrentUICulture设置为CultureInfo的静态属性,并将其设置为你自己的一个类的静态属性 . 这不会修复string.Format的默认行为或使StringFormat在绑定中正常工作,然后遍历应用程序的逻辑树以重新创建应用程序中的所有绑定并设置其转换器文化 .

  • 34

    对于ASP.NET5,即ASPNETCORE,您可以在 configure 中执行以下操作:

    app.UseRequestLocalization(new RequestLocalizationOptions
    {
        DefaultRequestCulture = new RequestCulture(new CultureInfo("en-gb")),
        SupportedCultures = new List<CultureInfo>
        {
            new CultureInfo("en-gb")
        },
                SupportedUICultures = new List<CultureInfo>
        {
            new CultureInfo("en-gb")
        }
    });
    

    这是一个提供更多信息的series of blog posts .

  • 17

    这问得很多 . 基本上,没有,不适用于.NET 4.0 . 您必须在每个新线程(或 ThreadPool 函数)的开头手动执行此操作 . 您可以将文化名称(或文化对象)存储在静态字段中,以节省必须访问数据库,但这就是它 .

  • 5

    这是c#MVC的解决方案:

    • 首先:创建一个自定义属性并覆盖如下方法:
    public class CultureAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            // Retreive culture from GET
            string currentCulture = filterContext.HttpContext.Request.QueryString["culture"];
    
            // Also, you can retreive culture from Cookie like this :
            //string currentCulture = filterContext.HttpContext.Request.Cookies["cookie"].Value;
    
            // Set culture
            Thread.CurrentThread.CurrentCulture = new CultureInfo(currentCulture);
            Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(currentCulture);
        }
    }
    
    • 第二:在App_Start中,找到FilterConfig.cs,添加此属性 . (这适用于整个应用程序)
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            // Add custom attribute here
            filters.Add(new CultureAttribute());
        }
    }
    

    而已 !

    如果要为每个控制器/操作定义文化而不是整个应用程序,可以使用以下属性:

    [Culture]
    public class StudentsController : Controller
    {
    }
    

    要么:

    [Culture]
    public ActionResult Index()
    {
        return View();
    }
    
  • 4

    在.NET 4.5中,您可以使用CultureInfo.DefaultThreadCurrentCulture属性来更改AppDomain的文化 .

    对于4.5之前的版本,您必须使用反射来操纵AppDomain的文化 . 在 CultureInfo 上有一个私有静态字段(.NET 2.0 mscorlib中为 m_userDefaultCulture ,.NET 4.0 mscorlib中为 s_userDefaultCulture ),如果线程未在其自身上设置该属性,则控制 CurrentCulture 返回的内容 .

    这不会更改本机线程区域设置,并且发布以这种方式更改文化的代码可能不是一个好主意 . 但它可能对测试很有用 .

  • 3

    如果您正在使用资源,可以通过以下方式手动强制它:

    Resource1.Culture = new System.Globalization.CultureInfo("fr");
    

    在资源管理器中,有一个自动生成的代码如下:

    /// <summary>
    ///   Overrides the current thread's CurrentUICulture property for all
    ///   resource lookups using this strongly typed resource class.
    /// </summary>
    [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
    internal static global::System.Globalization.CultureInfo Culture {
        get {
            return resourceCulture;
        }
        set {
            resourceCulture = value;
        }
    }
    

    现在,每次在此资源中引用单个字符串时,它都会使用指定的resourceCulture覆盖文化(线程或进程) .

    您可以指定"fr","de"等语言,也可以将语言代码设置为en-US的0x0409或it-IT的0x0410 . 有关语言代码的完整列表,请参阅:Language Identifiers and Locales

  • 3

    对于.net 4.5及更高版本,您应该使用

    var culture = new CultureInfo("en-US");
            CultureInfo.DefaultThreadCurrentCulture = culture;
            CultureInfo.DefaultThreadCurrentUICulture = culture;
    
  • 2

    DefaultThreadCurrentCulture和DefaultThreadCurrentUICulture也存在于Framework 4.0中,但它们是私有的 . 使用Reflection您可以轻松设置它们 . 它会影响未明确设置CurrentCulture的所有thred(也运行线程) .

    Public Sub SetDefaultThreadCurrentCulture(paCulture As CultureInfo)
        Thread.CurrentThread.CurrentCulture.GetType().GetProperty("DefaultThreadCurrentCulture").SetValue(Thread.CurrentThread.CurrentCulture, paCulture, Nothing)
        Thread.CurrentThread.CurrentCulture.GetType().GetProperty("DefaultThreadCurrentUICulture").SetValue(Thread.CurrentThread.CurrentCulture, paCulture, Nothing)
    End Sub
    
  • 2

    对于@ rastating的好答案,这个答案有点扩展 . 您可以对所有版本的.NET使用以下代码,而无需担心:

    public static void SetDefaultCulture(CultureInfo culture)
        {
            Type type = typeof (CultureInfo);
            try
            {
                // Class "ReflectionContext" exists from .NET 4.5 onwards.
                if (Type.GetType("System.Reflection.ReflectionContext", false) != null)
                {
                    type.GetProperty("DefaultThreadCurrentCulture")
                        .SetValue(System.Threading.Thread.CurrentThread.CurrentCulture,
                            culture, null);
    
                    type.GetProperty("DefaultThreadCurrentUICulture")
                        .SetValue(System.Threading.Thread.CurrentThread.CurrentCulture,
                            culture, null);
                }
                else //.NET 4 and lower
                {
                    type.InvokeMember("s_userDefaultCulture",
                        BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static,
                        null,
                        culture,
                        new object[] {culture});
    
                    type.InvokeMember("s_userDefaultUICulture",
                        BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static,
                        null,
                        culture,
                        new object[] {culture});
    
                    type.InvokeMember("m_userDefaultCulture",
                        BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static,
                        null,
                        culture,
                        new object[] {culture});
    
                    type.InvokeMember("m_userDefaultUICulture",
                        BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Static,
                        null,
                        culture,
                        new object[] {culture});
                }
            }
            catch
            {
                // ignored
            }
        }
    }
    

Related