是否有为整个应用程序设置区域性的方法? 所有当前线程和新线程?

是否有为整个应用程序设置区域性的方法? 所有当前线程和新线程?

我们有存储在数据库中的区域性的名称,当我们的应用程序启动时,我们会这样做

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

但是,当然,当我们想要在一个新的线程中做一些事情的时候,这会“丢失”。有没有办法为整个应用程序设置 CurrentCultureCurrentUICulture?所以新的线程也得到了这种文化?还是每次创建新线程时触发的某个事件,我可以挂接到这个事件?

179662 次浏览

人们经常问这个问题。基本上,没有,没有。NET 4.0.必须在每个新线程(或 ThreadPool函数)开始时手动执行。您也许可以将区域性名称(或仅仅是区域性对象)存储在一个静态字段中,以避免访问数据库,但仅此而已。

在.NET 4.5中,可以使用 CultureInfo.DefaultThreadCurrentCulture属性更改 AppDomain 的区域性。

对于4.5之前的版本,必须使用反射来操作 AppDomain 的区域性。CultureInfo上有一个私有静态字段(m_userDefaultCulture in。NET 2.0 mscolib,s_userDefaultCulture in.NET 4.0 mscolib) ,如果线程没有在自身上设置该属性,则控制 CurrentCulture返回的内容。

这不会改变本机线程区域设置,而且以这种方式发布改变区域性的代码可能不是一个好主意。不过,它可能对测试有用。

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

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;
}
}

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

您可以将语言指定为“ fr”、“ de”等,也可以将语言代码设置为 en-US 的0x0409或 it-IT 的0x0410。有关语言代码的完整列表,请参阅: 语言标识符和语言环境

实际上,您可以使用 可以设置默认的线程区域性和 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 方法的区域性参数是 还是 en-US。呃卧槽? !但这是个开始。至少这样

  • 当你的应用程序加载时,你可以修复一次用户界面文化
  • 它总是可以从 CultureInfo.CurrentUICulture
  • string.Format("{0}", DateTime.Now)将使用您自定义的区域设置

如果您不能使用该框架的4.5版本,那么就放弃将 CurrentUICulture 设置为 CultureInfo 的静态属性,而将其设置为您自己类的静态属性。这不会修复字符串的默认行为。格式化或使 StringFormat 在绑定中正常工作,然后遍历应用程序的逻辑树,重新创建应用程序中的所有绑定,并设置它们的转换器区域性。

DefaultThreadCurrentCultureDefaultThreadCurrentUICulture也出现在 Framework4.0中,但它们是私有的。使用反射可以很容易地设置它们。这将影响所有未显式设置 CurrentCulture的线程(也运行线程)。

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

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

下面是一系列提供更多信息的博客文章:

下面是 c # MVC 的解决方案:

  1. 首先: 创建一个自定义属性和覆盖方法,如下所示:

    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);
    }
    }
    
  2. Second : In App_Start, find FilterConfig.cs, add this attribute. (this works for WHOLE application)

    public class FilterConfig
    {
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
    // Add custom attribute here
    filters.Add(new CultureAttribute());
    }
    }
    

That's it !

If you want to define culture for each controller/action in stead of whole application, you can use this attribute like this:

[Culture]
public class StudentsController : Controller
{
}

或者:

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

对于.NET 4.5或更高版本,您应该使用:

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

这个答案对于@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
}
}
}

为所有线程和窗口设置 CultureInfo 的工作解决方案。

  1. 打开 App.xaml文件并添加一个新的“ Startup”属性来为应用程序分配启动事件处理程序:
<Application ........
Startup="Application_Startup"
>
  1. 打开 App.xaml.cs文件并将此代码添加到创建的启动处理程序(本例中为 Application _ Startup)。类应用程序将看起来像这样:
    public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
CultureInfo cultureInfo = CultureInfo.GetCultureInfo("en-US");
System.Globalization.CultureInfo.DefaultThreadCurrentCulture = cultureInfo;
System.Globalization.CultureInfo.DefaultThreadCurrentUICulture = cultureInfo;
Thread.CurrentThread.CurrentCulture = cultureInfo;
Thread.CurrentThread.CurrentUICulture = cultureInfo;
}
}