Есть ли способ установить культуру для всего приложения? Все текущие потоки и новые потоки?


есть ли способ установки культуры для всего приложения? Все текущие потоки и новые потоки?

у нас есть имя культуры, хранящейся в базе данных, и когда наше приложение запускается, мы делаем

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

но, конечно, это "теряется", когда мы хотим сделать что-то в новом потоке. Есть ли способ установить это CurrentCulture и CurrentUICulture для всего приложения? Так что новые потоки также получают эту культуру? Или это какое-то событие уволили всякий раз, когда создается новый поток, к которому я могу подключиться?

9 156

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:

  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. во-вторых: в 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
        }
    }
}