Existe-t-il un moyen de définir la culture pour toute une application? Tous les threads actuels et les nouveaux threads?

StackOverflow https://stackoverflow.com/questions/468791

  •  19-08-2019
  •  | 
  •  

Question

Existe-t-il un moyen de définir la culture pour toute une application? Tous les threads actuels et nouveaux?

Nous avons le nom de la culture stockée dans une base de données, et lorsque notre application démarre, nous faisons

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

Mais, bien sûr, cela "se perd". quand nous voulons faire quelque chose dans un nouveau fil. Existe-t-il un moyen de définir CurrentCulture et CurrentUICulture pour l'ensemble de l'application? Pour que les nouveaux fils acquièrent aussi cette culture? Ou est-ce un événement déclenché chaque fois qu'un nouveau fil est créé auquel je peux me connecter?

Était-ce utile?

La solution

Dans .NET 4.5, vous pouvez utiliser le < code> CultureInfo.DefaultThreadCurrentCulture pour changer la culture d'un AppDomain.

Pour les versions antérieures à la version 4.5, vous devez utiliser la réflexion pour manipuler la culture d'un AppDomain. Il existe un champ statique privé sur CultureInfo ( m_userDefaultCulture dans .NET 2.0 mscorlib, s_userDefaultCulture dans .NET 4.0 mscorlib) qui contrôle quoi . CurrentCulture est renvoyé si un thread n'a pas défini cette propriété sur elle-même.

Cela ne modifie pas les paramètres régionaux du thread natif et ce n'est probablement pas une bonne idée d'envoyer du code qui modifie la culture de cette manière. Cela peut être utile pour tester cependant.

Autres conseils

Cela se pose souvent. En gros, non, pas pour .NET 4.0. Vous devez le faire manuellement au début de chaque nouveau thread (ou de la fonction ThreadPool ). Vous pourriez peut-être stocker le nom de la culture (ou simplement l'objet de la culture) dans un champ statique pour éviter de devoir toucher la base de données, mais c'est à peu près tout.

Si vous utilisez des ressources, vous pouvez le forcer manuellement par:

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

Dans le gestionnaire de ressources, il existe un code généré automatiquement, comme suit:

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

Chaque fois que vous faites référence à votre chaîne individuelle au sein de cette ressource, elle remplace la culture (thread ou processus) par le resourceCulture spécifié.

Vous pouvez spécifier la langue comme dans "fr", "de". etc. ou mettez le code de langue comme dans 0x0409 pour en-US ou 0x0410 pour it-IT. Pour obtenir la liste complète des codes de langue, consultez la page suivante: Identificateurs de langue et paramètres régionaux .

Pour .net 4.5 et supérieur, vous devez utiliser

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

En fait, vous pouvez définir la culture de thread et la culture d'interface utilisateur par défaut, mais uniquement avec Framework 4.5 +

.

Je mets dans ce constructeur statique

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

et mettez un point d'arrêt dans la méthode de conversion d'un ValueConverter pour voir ce qui est arrivé à l'autre bout. CultureInfo.CurrentUICulture a cessé d'être en-US et est devenu en-AU complet avec mon petit bidouillage pour lui faire respecter les paramètres régionaux de ShortTimePattern.

Hourra, tout va bien dans le monde! Ou pas. Le paramètre culture transmis à la méthode Convert est still en-US. Euh, WTF?! Mais c'est un début. Au moins de cette façon

  • vous pouvez réparer la culture de l'interface utilisateur une fois lorsque votre application est chargée
  • il est toujours accessible à partir de CultureInfo.CurrentUICulture
  • string.Format (" {0} " ;, DateTime.Now) utilisera vos paramètres régionaux personnalisés

Si vous ne pouvez pas utiliser la version 4.5 du framework, renoncez à définir CurrentUICulture en tant que propriété statique de CultureInfo et définissez-la en tant que propriété statique de l'une de vos propres classes. Cela ne résoudra pas le comportement par défaut de string.Format ou ne permettra pas à StringFormat de fonctionner correctement dans les liaisons, puis parcourra l'arborescence logique de votre application pour recréer toutes les liaisons dans votre application et définir leur culture de conversion.

Pour ASP.NET5, c’est-à-dire ASPNETCORE, vous pouvez effectuer les opérations suivantes dans configurer :

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

Voici une série de billets de blog qui donne davantage d'informations.

Cette réponse est un peu plus expansive pour la réponse géniale de @ rastating. Vous pouvez utiliser le code suivant pour toutes les versions de .NET sans soucis:

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

DefaultThreadCurrentCulture et DefaultThreadCurrentUICulture sont également présents dans Framework 4.0, mais ils sont privés. En utilisant la réflexion, vous pouvez facilement les définir. Cela affectera tous les threads où CurrentCulture n'est pas explicitement défini (les threads en cours d'exécution également).

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

Voici la solution pour c # MVC:

  1. Tout d'abord: créez un attribut personnalisé et substituez la méthode suivante:

    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. Deuxièmement: dans App_Start, recherchez FilterConfig.cs, ajoutez cet attribut. (cela fonctionne pour toute l'application)

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

C'est tout!

Si vous souhaitez définir une culture pour chaque contrôleur / action au lieu d'une application entière, vous pouvez utiliser cet attribut comme suit:

[Culture]
public class StudentsController : Controller
{
}

Ou:

[Culture]
public ActionResult Index()
{
    return View();
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top