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

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

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

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

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

Ответ 1

В .NET 4.5 вы можете использовать свойство CultureInfo.DefaultThreadCurrentCulture, чтобы изменить культуру AppDomain.

Для версий до 4.5 вы должны использовать отражение, чтобы манипулировать культурой AppDomain. Существует личное статическое поле в CultureInfo (m_userDefaultCulture в .NET 2.0 mscorlib, s_userDefaultCulture в .NET 4.0 mscorlib), которое контролирует, что возвращает CurrentCulture, если поток не установил это свойство сам по себе.

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

Ответ 2

Об этом много спрашивают. В принципе, нет, а не для .NET 4.0. Вы должны сделать это вручную в начале каждого нового потока (или ThreadPool). Возможно, вы сохранили название культуры (или только объект культуры) в статическом поле, чтобы сохранить возможность попадания в БД, но об этом.

Ответ 3

Если вы используете ресурсы, вы можете вручную заставить их:

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

В диспетчере ресурсов есть автоматически сгенерированный код, который выглядит следующим образом:

/// <summary>
///   Overrides the current thread 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;
    }
}

Теперь каждый раз, когда вы ссылаетесь на свою отдельную строку в этом ресурсе, она переопределяет культуру (поток или процесс) с указанным ресурсом. Культура.

Вы можете указать язык как в "fr", "de" и т.д. или поместить код языка как в 0x0409 для en-US или 0x0410 для него - IT. Полный список кодов языков можно найти по адресу: Идентификаторы языков и локали

Ответ 4

Для .net 4.5 и выше вы должны использовать

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

Ответ 5

На самом деле вы можете установить культуру потока по умолчанию и культуру пользовательского интерфейса, но только с 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;
}

и положите точку останова в методе Convert ValueConverter, чтобы узнать, что произошло на другом конце. CultureInfo.CurrentUICulture перестал быть en-US и стал вместо en-AU дополнен моим маленьким взломом, чтобы он учитывал региональные настройки для ShortTimePattern.

Ура, все в мире! Или нет. Параметр Culture, переданный методу Convert, по-прежнему находится в состоянии en-US. Erm, WTF?! Но это начало. По крайней мере, таким образом

  • вы можете исправить культуру пользовательского интерфейса один раз, когда ваше приложение загружает
  • он всегда доступен из CultureInfo.CurrentUICulture
  • string.Format("{0}", DateTime.Now) будет использовать ваши настроенные региональные настройки.

Если вы не можете использовать версию 4.5 фреймворка, то откажитесь от установки CurrentUICulture как статического свойства CultureInfo и установите его как статическое свойство одного из ваших собственных классов. Это не будет исправлять поведение по умолчанию string.Format или заставить StringFormat корректно работать в привязках, а затем ходить в логическое дерево приложения, чтобы воссоздать все привязки в вашем приложении и установить их культуру конвертера.

Ответ 6

Для 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")
    }
});

Здесь серия сообщений в блоге, в которой содержится дополнительная информация.

Ответ 7

DefaultThreadCurrentCulture и DefaultThreadCurrentUICulture также присутствуют в Framework 4.0, но они являются частными. Используя Reflection, вы можете легко установить их. Это влияет на все threds, где 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

Ответ 8

Вот решение для С# 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, добавьте этот атрибут. (это работает для приложения WHOLE)

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

Ответ 9

Этот ответ немного расширился для @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
        }
    }
}