Есть ли способ установить культуру для всего приложения? Все текущие потоки и новые потоки?
есть ли способ установки культуры для всего приложения? Все текущие потоки и новые потоки?
у нас есть имя культуры, хранящейся в базе данных, и когда наше приложение запускается, мы делаем
CultureInfo ci = new CultureInfo(theCultureString);
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = ci;
но, конечно, это "теряется", когда мы хотим сделать что-то в новом потоке. Есть ли способ установить это CurrentCulture
и CurrentUICulture
для всего приложения? Так что новые потоки также получают эту культуру? Или это какое-то событие уволили всякий раз, когда создается новый поток, к которому я могу подключиться?
9 ответов:
в .NET 4.5, вы можете использовать
CultureInfo.DefaultThreadCurrentCulture
свойство для изменения языка и региональных параметров домена приложения.для версий до 4.5 вы должны использовать отражение для управления культурой домена приложения. Существует частное статическое поле на
CultureInfo
(m_userDefaultCulture
в .NET 2.0 mscorlib,s_userDefaultCulture
в .NET 4.0 mscorlib), который контролирует то, чтоCurrentCulture
возвращает, если поток не установил это свойство на себя.это не изменяет локаль собственного потока, и это вероятно, не очень хорошая идея отправлять код, который изменяет культуру таким образом. Это может быть полезно для тестирования.
об этом много спрашивают. В принципе, нет, не для .NET 4.0. Вы должны сделать это вручную в начале каждого нового потока (или ). Возможно, вы могли бы сохранить имя культуры (или просто объект культуры) в статическом поле, чтобы сохранить необходимость попадания в БД, но это все.
Если вы используете ресурсы, вы можете вручную заставить его:
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; } }
можно указать язык как в "фр", "де" и т. д. или поместите код языка как в 0x0409 для en-US или 0x0410 для it-IT. Для полный список кодов языков см. по ссылке: язык и районов
для .net 4.5 и выше, вы должны использовать
var culture = new CultureInfo("en-US"); CultureInfo.DefaultThreadCurrentCulture = culture; CultureInfo.DefaultThreadCurrentUICulture = culture;
на самом деле вы можете установите культуру потока по умолчанию и культуру пользовательского интерфейса, но только с 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, чтобы увидеть, что прибыло на другом конце. CultureInfo.CurrentUICulture перестал быть en-US и стал вместо этого en-AU в комплекте с моим маленьким взломом, чтобы заставить его уважать региональные настройки для ShortTimePattern.
ура, все в порядке весь мир! Или нет. Параметр culture, передаваемый методу Convert, равен еще en-US. ЭМ, WTF?! Но это только начало. По крайней мере, так
- вы можете исправить культуру пользовательского интерфейса один раз, когда ваше приложение загружается
- он всегда доступен из
CultureInfo.CurrentUICulture
string.Format("{0}", DateTime.Now)
будет использовать ваши индивидуальные региональные настройкиЕсли вы не можете использовать версию 4.5 фреймворка, то откажитесь от установки CurrentUICulture в качестве статического свойства CultureInfo и установить его как статическое свойство одного из ваших собственных классов. Это не исправит поведение строки по умолчанию.Отформатируйте или заставьте StringFormat работать правильно в привязках, а затем пройдите по логическому дереву вашего приложения, чтобы воссоздать все привязки в вашем приложении и установить их язык и региональные параметры конвертера.
для 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") } });
здесь серия сообщений в блоге это дает больше информации.
DefaultThreadCurrentCulture и DefaultThreadCurrentUICulture также присутствуют в Framework 4.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
вот решение для 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(); }
этот ответ является немного расширением для отличного ответа @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 } } }