Gibt es eine Möglichkeit, die Kultur für eine gesamte Anwendung festzulegen? Alle aktuellen Threads und neuen Threads?

177

Gibt es eine Möglichkeit, die Kultur für eine gesamte Anwendung festzulegen? Alle aktuellen Threads und neuen Threads?

Wir haben den Namen der Kultur in einer Datenbank gespeichert, und wenn unsere Anwendung startet, tun wir dies

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

Aber dies geht natürlich "verloren", wenn wir etwas in einem neuen Thread tun wollen. Gibt es eine Möglichkeit, dies CurrentCultureund CurrentUICulturefür die gesamte Anwendung einzustellen? Damit neue Threads auch diese Kultur bekommen? Oder wird ein Ereignis ausgelöst, wenn ein neuer Thread erstellt wird, an den ich mich anschließen kann?

Svish
quelle
4
Wenn Sie Ressourcen verwenden, können Sie diese manuell erzwingen, indem Sie: Resource1.Culture = new System.Globalization.CultureInfo ("fr"); Auf diese Weise wird jedes Mal, wenn Sie eine Zeichenfolge abrufen möchten, diese lokalisiert und zurückgegeben
Reza S

Antworten:

196

In .NET 4.5 können Sie die CultureInfo.DefaultThreadCurrentCultureEigenschaft verwenden, um die Kultur einer AppDomain zu ändern.

Für Versionen vor 4.5 müssen Sie Reflection verwenden, um die Kultur einer AppDomain zu manipulieren. Es gibt ein privates statisches Feld in CultureInfo( m_userDefaultCulturein .NET 2.0 mscorlib, s_userDefaultCulturein .NET 4.0 mscorlib), das steuert, was CurrentCulturezurückgegeben wird, wenn ein Thread diese Eigenschaft nicht für sich selbst festgelegt hat.

Dies ändert das native Thread-Gebietsschema nicht und es ist wahrscheinlich keine gute Idee, Code zu versenden, der die Kultur auf diese Weise ändert. Es kann jedoch zum Testen nützlich sein.

Austin
quelle
9
Seien Sie vorsichtig mit dieser Einstellung in ASP.NET-Anwendungen. Durch Festlegen der Kultur in der AppDomain wird die Kultur für alle Benutzer festgelegt. Daher ist es für englische Benutzer nicht gut, die Website beispielsweise auf Deutsch zu sehen.
Dimitar Tsonev
2
Ich habe eine ASP.NET-Anwendung geerbt, die nur funktioniert, wenn sich alle Kulturen in den USA befinden. Dies ist ein Szenario, in dem diese Einstellung perfekt für die Zeit ist, bis dieser Fehler behoben ist
Daniel Hilgarth
37

Das wird oft gefragt. Grundsätzlich gibt es keine, nicht für .NET 4.0. Sie müssen dies manuell zu Beginn jedes neuen Threads (oder jeder neuen ThreadPoolFunktion) tun . Sie könnten vielleicht den Kulturnamen (oder nur das Kulturobjekt) in einem statischen Feld speichern, um zu vermeiden, dass Sie die Datenbank treffen müssen, aber das war es auch schon.

Marc Gravell
quelle
1
irgendwie nervig ... scheint, als hättest du recht, hehe. Also machen wir das jetzt (und haben die Kultur als statische Klasse), aber wir haben immer noch ein Problem mit einigen Threads, über die wir keine Kontrolle haben. Wie das Verarbeiten von Threads im Microsoft Report Viewer. Ich habe eine Lösung gefunden. Vielen Dank für die Info :)
Svish
8
Das ist wirklich ärgerlich :( Es wäre schön, wenn es eine Möglichkeit gäbe, die aktuelle (UI) Kultur automatisch für Ihre Anwendung
festzulegen
1
Es ist so lange her, dass ich jetzt damit gearbeitet habe, also erinnere ich mich nicht genau, was wir getan haben. Aber ich denke, es könnte sein, dass wir anstelle von Datumsangaben in dem an den Berichts-Viewer gesendeten Datensatz das Datum zuerst in eine Zeichenfolge formatiert haben, wobei wir die in der Anwendung festgelegte Kultur verwendet haben. Dann war es nicht mehr wirklich wichtig, dass die Berichts-Rendering-Threads die falsche Kultur verwendeten. Wir haben das Problem also nicht mit den Threads umgangen, die die falsche Kultur verwendet haben. Wir haben gerade das Problem
umgangen,
2
In unserer App habe ich versucht, die Threads zu "erfassen" (indem ich eine bestimmte Methode von bestimmten Stellen aus aufrief) und sie zur späteren Verwendung in einer Sammlung zu speichern (in diesem Fall zum Festlegen der Kultur), was zu weit zu funktionieren scheint.
Herr TA
1
Könnten Sie das kulturinfo-Objekt nicht in einer Sitzung speichern und (wenn Sie Masterseiten verwenden) in Ihrem Masterpage-Code dahinter nachsehen und den aktuellen Thread festlegen?
user609926
20

Wenn Sie Ressourcen verwenden, können Sie diese manuell erzwingen, indem Sie:

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

Im Ressourcenmanager gibt es einen automatisch generierten Code, der wie folgt lautet:

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

Jedes Mal, wenn Sie auf Ihre individuelle Zeichenfolge in dieser Ressource verweisen, wird die Kultur (Thread oder Prozess) mit der angegebenen Ressourcenkultur überschrieben.

Sie können entweder die Sprache wie in "fr", "de" usw. angeben oder den Sprachcode wie in 0x0409 für en-US oder 0x0410 für it-IT eingeben. Eine vollständige Liste der Sprachcodes finden Sie unter: Sprachkennungen und Gebietsschemas

Reza S.
quelle
Es kann "ungezwungen" sein, indem es auf Null gesetzt wird:Resource1.Culture = Null;
Habakuk
8

Für .net 4.5 und höher sollten Sie verwenden

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

Eigentlich Sie können die Standard - Thread Kultur und UI - Kultur gesetzt, sondern nur mit Rahmen 4.5+

Ich habe diesen statischen Konstruktor eingefügt

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

und setzen Sie einen Haltepunkt in die Convert-Methode eines ValueConverter, um zu sehen, was am anderen Ende angekommen ist. CultureInfo.CurrentUICulture war nicht mehr en-US und wurde stattdessen en-AU mit meinem kleinen Hack, um die regionalen Einstellungen für ShortTimePattern zu berücksichtigen.

Hurra, alles ist gut in der Welt! Oder nicht. Der an die Convert-Methode übergebene Kulturparameter ist weiterhin en-US. Ähm, WTF?! Aber es ist ein Anfang. Zumindest so

  • Sie können die UI-Kultur einmal korrigieren, wenn Ihre App geladen wird
  • es ist immer zugänglich von CultureInfo.CurrentUICulture
  • string.Format("{0}", DateTime.Now) verwendet Ihre benutzerdefinierten regionalen Einstellungen

Wenn Sie Version 4.5 des Frameworks nicht verwenden können, geben Sie das Festlegen von CurrentUICulture als statische Eigenschaft von CultureInfo auf und legen Sie es als statische Eigenschaft einer Ihrer eigenen Klassen fest. Dadurch wird das Standardverhalten von string.Format nicht behoben oder StringFormat funktioniert ordnungsgemäß in Bindungen. Gehen Sie dann durch den logischen Baum Ihrer App, um alle Bindungen in Ihrer App neu zu erstellen und ihre Konverterkultur festzulegen.

Peter Wone
quelle
1
Die Antwort von Austin lieferte bereits die Erkenntnis, dass CultureInfo.DefaultThreadCurrentCulture so eingestellt werden kann, dass die Kultur der AppDomain geändert wird. CultureInfo.DefaultThreadCurrentUICulture ist für CurrentUICulture wie CultureInfo.DefaultThreadCurrentCulture für CurrentCulture. Es gibt wirklich keinen Grund, den Wert direkt aus der Registrierung in Ihrem Code abzurufen. Wenn Sie die CurrentCulture in eine bestimmte Kultur ändern möchten, aber die Benutzerüberschreibungen beibehalten möchten, müssen Sie nur den Wert aus den DateTimeFormat-Dateien der CurrentCulture abrufen, bevor Sie sie überschreiben.
Eric MSFT
1
Ich werde es überprüfen müssen, aber ich erinnere mich anscheinend daran, dass ich es ohne Erfolg versucht habe, was dazu führte, dass ich es aus der Registrierung holte. Glaubst du wirklich, ich würde mir ohne Grund all diese Mühe machen? Der Registrierungszugriff ist eine riesige PITA in dieser schönen neuen Welt der Benutzerkontensteuerung.
Peter Wone
4

Für ASP.NET5, dh ASPNETCORE, können Sie Folgendes tun 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")
    }
});

Hier ist eine Reihe von Blog-Posts , die weitere Informationen enthalten.

Sean
quelle
1
Ich habe nach einer Möglichkeit gesucht, dies auf einer älteren ASP.NET 2.0-Site zu tun, und es ist frustrierend, wie einfach ich es mit einer anderen Core-Site im Vergleich geschafft habe! Ich bin in einem multinationalen Unternehmen und für interne Websites ist die gesamte Formatierung in den USA, um Datumsverwechslungen zu vermeiden. Diese Legacy-Site ist jedoch für en-US, en-CA und fr-CA eingerichtet. Und auf eine "hack-y" Art und Weise, wenn ich es behebe, explodieren alle ihre Typkonvertierungen in der Datenschicht! (Französische Geldwerte sind "1 234,56 $"
Andrew S
1
@ Sean dein Link ist kaputt. Vielleicht deutet es auf dies , dies und das hin
Fer R
4

Diese Antwort ist eine kleine Erweiterung für die großartige Antwort von @ rastating. Sie können den folgenden Code für alle Versionen von .NET ohne Bedenken verwenden:

    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
        }
    }
}
Polfosol ఠ_ఠ
quelle
4

DefaultThreadCurrentCultureund DefaultThreadCurrentUICulturesind auch in Framework 4.0 vorhanden, aber sie sind privat. Mit Reflection können Sie sie einfach einstellen. Dies betrifft alle Threads, die CurrentCulturenicht explizit festgelegt sind (auch das Ausführen von Threads).

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
HCAxel
quelle
1
Dieser hat für mich gearbeitet. Obwohl Thread.CurrentThread.CurrentCulture = culture verwendet wird; Thread.CurrentThread.CurrentUICulture = Kultur; Welches sieht das gleiche nicht aus. Aus Gründen der Klarheit wird dies in einer WPF-App verwendet, in der die App selbst ihre Kultur geändert hat. Benutzersteuerungen in anderen Projekten verwendeten jedoch die Browserkultur und nicht die vom Benutzer ausgewählte Kultur
chillfire
3

Hier ist die Lösung für c # MVC:

  1. Erstens: Erstellen Sie ein benutzerdefiniertes Attribut und überschreiben Sie die Methode wie folgt:

    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. Zweitens: Suchen Sie in App_Start nach FilterConfig.cs und fügen Sie dieses Attribut hinzu. (Dies funktioniert für die gesamte Anwendung)

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

Das ist es !

Wenn Sie anstelle der gesamten Anwendung eine Kultur für jeden Controller / jede Aktion definieren möchten, können Sie dieses Attribut wie folgt verwenden:

[Culture]
public class StudentsController : Controller
{
}

Oder:

[Culture]
public ActionResult Index()
{
    return View();
}
Meng Xue
quelle
1

Arbeitslösung zum Festlegen von CultureInfo für alle Threads und Fenster.

  1. Öffnen Sie die Datei App.xaml und fügen Sie ein neues Attribut "Startup" hinzu, um den Startereignishandler für die App zuzuweisen:
<Application ........
             Startup="Application_Startup"
>
  1. Öffnen Sie die Datei App.xaml.cs und fügen Sie diesen Code dem erstellten Starthandler hinzu (in diesem Fall Application_Startup). Die Klassen-App sieht folgendermaßen aus:
    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;
        }
    }
Rustam Shafigullin
quelle