Есть ли способ установить культуру для всего приложения? Все текущие темы и новые темы? - PullRequest
168 голосов
/ 22 января 2009

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

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

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

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

Ответы [ 9 ]

185 голосов
/ 24 сентября 2011

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

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

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

36 голосов
/ 22 января 2009

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

17 голосов
/ 08 ноября 2011

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

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" и т. Д. Или указать код языка как 0x0409 для en-US или 0x0410 для it-IT. Полный список кодов языков см. По адресу: Идентификаторы языков и локали

7 голосов
/ 13 декабря 2016

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

var culture = new CultureInfo("en-US");
        CultureInfo.DefaultThreadCurrentCulture = culture;
        CultureInfo.DefaultThreadCurrentUICulture = culture;
5 голосов
/ 17 января 2013

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

Ура, в мире все хорошо! Или нет. Параметр культуры, переданный методу Convert, равен still en-US. Хм, WTF ?! Но это начало. По крайней мере, так

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

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

3 голосов
/ 16 августа 2017

Этот ответ немного расширяет отличный ответ @ 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
        }
    }
}
3 голосов
/ 07 марта 2016

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

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

3 голосов
/ 20 января 2015

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

Вот решение для 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();
}
...