83 votes

Définir la culture dans une application ASP.Net MVC

Quel est le meilleur endroit pour définir la culture/la culture UI dans une application ASP.net MVC ?

Actuellement, j'ai une classe CultureController qui ressemble à ceci :

public class CultureController : Controller
    {
        public ActionResult SetSpanishCulture()
        {
            HttpContext.Session["culture"] = "es-ES";
            return RedirectToAction("Index", "Home");
        }

        public ActionResult SetFrenchCulture()
        {
            HttpContext.Session["culture"] = "fr-FR";
            return RedirectToAction("Index", "Home");
        }
    }

et un hyperlien pour chaque langue sur la page d'accueil avec un lien tel que celui-ci :

<li><%= Html.ActionLink("French", "SetFrenchCulture", "Culture")%></li>
<li><%= Html.ActionLink("Spanish", "SetSpanishCulture", "Culture")%></li>

ce qui fonctionne bien, mais je pense qu'il y a un moyen plus approprié de le faire.

Je lis la Culture en utilisant l'ActionFilter suivant http://www.iansuttle.com/blog/post/ASPNET-MVC-Action-Filter-for-Localized-Sites.aspx . Je suis un peu un noob MVC donc je ne suis pas sûr que j'ai réglé cela au bon endroit. Je ne veux pas le faire au niveau du web.config, cela doit être basé sur le choix de l'utilisateur. Je ne veux pas non plus vérifier leurs en-têtes http pour obtenir la culture à partir des paramètres de leur navigateur.

Editar:

Pour être clair, je n'essaie pas de décider s'il faut utiliser la session ou non. Ce point me convient parfaitement. Ce que j'essaie de déterminer, c'est s'il est préférable de faire cela dans un contrôleur de culture qui a une méthode d'action pour chaque culture à définir, ou s'il y a un meilleur endroit dans le pipeline MVC pour faire cela ?

108voto

jao Points 5590

J'utilise ceci méthode de localisation et ajouté un paramètre de route qui définit la culture et la langue chaque fois qu'un utilisateur visite example.com/xx-xx/

Exemple :

routes.MapRoute("DefaultLocalized",
            "{language}-{culture}/{controller}/{action}/{id}",
            new
            {
                controller = "Home",
                action = "Index",
                id = "",
                language = "nl",
                culture = "NL"
            });

J'ai un filtre qui s'occupe du réglage de la culture et de la langue :

using System.Globalization;
using System.Threading;
using System.Web.Mvc;

public class InternationalizationAttribute : ActionFilterAttribute {

    public override void OnActionExecuting(ActionExecutingContext filterContext) {

        string language = (string)filterContext.RouteData.Values["language"] ?? "nl";
        string culture = (string)filterContext.RouteData.Values["culture"] ?? "NL";

        Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(string.Format("{0}-{1}", language, culture));
        Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(string.Format("{0}-{1}", language, culture));

    }
}

Pour activer l'attribut d'internationalisation, il suffit de l'ajouter à votre classe :

[Internationalization]
public class HomeController : Controller {
...

Maintenant, chaque fois qu'un visiteur va sur http://example.com/de-DE/Home/Index le site allemand est affiché.

J'espère que ces réponses vous mettront sur la bonne voie.

J'ai aussi fait un petit projet d'exemple MVC 5 que vous pouvez trouver aquí

Il suffit d'aller sur http://{yourhost}:{port}/en-us/home/index pour voir la date actuelle en anglais (US), ou de la changer en http://{yourhost}:{port}/de-de/home/index pour l'allemand, etc.

38voto

marapet Points 19796

Je sais qu'il s'agit d'une vieille question, mais si vous voulez vraiment que cela fonctionne avec votre ModelBinder (en ce qui concerne le DefaultModelBinder.ResourceClassKey = "MyResource"; ainsi que les ressources indiquées dans les annotations de données des classes du modèle de vue), le contrôleur ou encore une classe ActionFilter il est trop tard pour mettre en place une culture.

La culture doit être mise en place Application_AcquireRequestState par exemple :

protected void Application_AcquireRequestState(object sender, EventArgs e)
    {
        // For example a cookie, but better extract it from the url
        string cookie = HttpContext.Current.Request.Cookies["culture"].Value;

        Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(culture);
        Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(culture);
    }

EDIT

En fait, il existe un meilleur moyen d'utiliser un gestionnaire d'itinéraire personnalisé qui définit la culture en fonction de l'url, parfaitement décrite par Alex Adamyan sur son blog .

Tout ce qu'il y a à faire, c'est de remplacer l'option GetHttpHandler et définir la culture à cet endroit.

24voto

Jace Rhea Points 3186

Je le ferais dans l'événement Initialize du contrôleur comme ceci...

    protected override void Initialize(System.Web.Routing.RequestContext requestContext)
    {
        base.Initialize(requestContext);

        const string culture = "en-US";
        CultureInfo ci = CultureInfo.GetCultureInfo(culture);

        Thread.CurrentThread.CurrentCulture = ci;
        Thread.CurrentThread.CurrentUICulture = ci;
    }

7voto

NerdFury Points 9935

Comme il s'agit d'un paramètre qui est stocké par utilisateur, la session est un endroit approprié pour stocker l'information.

Je modifierais votre contrôleur pour qu'il prenne la chaîne de culture comme paramètre, plutôt que d'avoir une méthode d'action différente pour chaque culture potentielle. L'ajout d'un lien vers la page est facile, et vous ne devriez pas avoir besoin d'écrire le même code à chaque fois qu'une nouvelle culture est requise.

public class CultureController : Controller    
{
        public ActionResult SetCulture(string culture)
        {
            HttpContext.Session["culture"] = culture
            return RedirectToAction("Index", "Home");
        }        
}

<li><%= Html.ActionLink("French", "SetCulture", new {controller = "Culture", culture = "fr-FR"})%></li>
<li><%= Html.ActionLink("Spanish", "SetCulture", new {controller = "Culture", culture = "es-ES"})%></li>

4voto

Andy Points 81

Si vous utilisez des sous-domaines, par exemple "pt.mydomain.com" pour définir le portugais par exemple, l'utilisation de Application_AcquireRequestState ne fonctionnera pas, car elle n'est pas appelée lors des demandes de cache ultérieures.

Pour résoudre ce problème, je suggère une implémentation comme celle-ci :

  1. Ajoutez le paramètre VaryByCustom au OutPutCache comme suit :

    [OutputCache(Duration = 10000, VaryByCustom = "lang")]
    public ActionResult Contact()
    {
        return View("Contact");
    }
  2. Dans global.asax.cs, récupérez la culture de l'hôte en utilisant un appel de fonction :

    protected void Application_AcquireRequestState(object sender, EventArgs e)
    {
        System.Threading.Thread.CurrentThread.CurrentUICulture = GetCultureFromHost();
    }
  3. Ajoutez la fonction GetCultureFromHost à global.asax.cs :

    private CultureInfo GetCultureFromHost()
    {
        CultureInfo ci = new CultureInfo("en-US"); // en-US
        string host = Request.Url.Host.ToLower();
        if (host.Equals("mydomain.com"))
        {
            ci = new CultureInfo("en-US");
        }
        else if (host.StartsWith("pt."))
        {
            ci = new CultureInfo("pt");
        }
        else if (host.StartsWith("de."))
        {
            ci = new CultureInfo("de");
        }
        else if (host.StartsWith("da."))
        {
            ci = new CultureInfo("da");
        }
    
        return ci;
    }
  4. Et enfin, remplacez la fonction GetVaryByCustomString(...) pour utiliser également cette fonction :

    public override string GetVaryByCustomString(HttpContext context, string value)
    {
        if (value.ToLower() == "lang")
        {
            CultureInfo ci = GetCultureFromHost();
            return ci.Name;
        }
        return base.GetVaryByCustomString(context, value);
    }

La fonction Application_AcquireRequestState est appelée sur les appels non mis en cache, ce qui permet au contenu d'être généré et mis en cache. GetVaryByCustomString est appelée lors des appels en cache pour vérifier si le contenu est disponible dans le cache. Dans ce cas, nous examinons à nouveau la valeur du domaine hôte entrant, au lieu de nous fier uniquement aux informations de culture actuelles, qui pourraient avoir changé pour la nouvelle demande (car nous utilisons des sous-domaines).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X