2010-11-22 17 views
3

J'essayais d'être plein d'esprit et j'utilisais un VirtualPathProvider pour trouver des vues localisées. Il prend le chemin d'accès demandé et le modifie lors de la vérification après le fichier. Il retourne un fichier virtuel localisé si trouvé:Vues localisées avec Razor

public pseudoclass MyFileProvider : VirtualPathProvider 
{ 

    bool FileExists(string requestedPath) 
    { 
     if (IsLocalizedView(requestedPath)) 
      return true; 
     return base.FileExists(requestedPath); 
    } 

    bool IsLocalizedView(string requestedPath) 
    { 
     var uri = requestedUri.AddLocaleByMagic("sv"); 
     if (FileExistsInternal(uri)) 
      return true; 
    } 

    //some more stuff to return the actual file 
} 

Le problème est que je reçois l'exception suivante:

Le VirtualPathProvider retourné un objet VirtualFile avec VirtualPath réglé sur «/vues/Shared/_Layout. sv.cshtml 'au lieu de' /Views/Shared/_Layout.cshtml 'attendu.

Bien sûr, je pourrais simuler le chemin du fichier, mais cela causerait des problèmes avec la mise en cache et différentes localisations. Droite?

Quelqu'un at-il une meilleure façon de créer des vues localisées? Je ne veux pas utiliser la même vue mais avec des chaînes de ressources à la place. De telles vues sont si horribles qu'elles me font presque pleurer parce qu'elles sont si difficiles à lire.

Si vous avez toujours pas compris ce que je cherche:

/Views/User/Details.sv.cshtml

Hejsan @Model.FirstName 

Detta är en lite rolig text på svenska. 

/Vues/utilisateur/Details.en.cshtml

Hello @Model.FirstName 

This is a test on english. 

Contrôleur

public ActionResult Details() 
{ 
    return View(new User()); //should automagically use a swedish or english view 
} 

Je veux être en mesure de changer de vue (à une localisée à l'aide CurrentCulture) sans avoir à faire quoi que ce soit manuellement à chaque demande.

+0

pourquoi ne pas simplement la mise en œuvre ASP.NET mondialisation? Je le fais pour tous les pays scandinaves et fonctionne comme un charme. La fin, j'ai une vue avec le texte du dossier 'App_GlobalResources'. – balexandre

+1

Parce qu'il rend les vues illisibles par rapport à une vue par langue. – jgauffin

Répondre

2

Vous pouvez écrire un ViewEngine personnalisé qui renvoie des vues en fonction de CurrentCulture. Un bel exemple de ceci peut être trouvé à Scott Hanselman's blog post, qui retourne des vues mobiles si la demande a été faite par un appareil mobile

+0

Le blog dit que l'implémentation est ** cassée ** :) Mais je pense que ma version fonctionne (bien que rien ne soit mis en cache). Le lien m'a aidé, d'où l'acceptation. – jgauffin

+0

Sa première mise en œuvre a été brisée, lire, plus tard dans le post, il décrit pourquoi et fournit la bonne version. – marcind

5

Voici ma mise en œuvre. Cela pourrait être plus générique, mais cela répond à toutes mes exigences.

Je recherche d'abord la vue la plus spécialisée et essaie sans spécification de langage en dernier.

Voir processus de conclusion:

  1. Details.sv-fi.cshtml
  2. Details.sv.cshtml
  3. Details.en.cshtml
  4. Détails.
  5. cshtml

public class LocalizedRazorViewEngine : RazorViewEngine 
    { 
     public LocalizedRazorViewEngine() 
     { 
      DefaultLanguageCode = "en"; 
     } 
     public string DefaultLanguageCode { get; set; } 

     public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) 
     { 
      var controllerName = (string)controllerContext.RouteData.Values["controller"]; 
      var language = GetLanguage(controllerName, viewName); 
      if (language != "") language = "." + language; 

      var masterPath = string.Format("~/Views/Shared/_Layout{0}.cshtml", language); 
      var uri = string.Format("~/Views/{0}/{1}{2}.cshtml", controllerName, viewName, language); 
      if (VirtualPathProvider.FileExists(uri)) 
       return new ViewEngineResult(CreateView(controllerContext, uri, masterPath), this); 


      return base.FindView(controllerContext, viewName, masterName, useCache); 
     } 

     private string GetLanguage(string controllerName, string actionName) 
     { 
      string format = "~/Views/{0}/{1}.{2}.cshtml"; 
      if (VirtualPathProvider.FileExists(string.Format(format, controllerName, actionName, Thread.CurrentThread.CurrentCulture.Name))) 
       return Thread.CurrentThread.CurrentCulture.Name; 
      if (VirtualPathProvider.FileExists(string.Format(format, controllerName, actionName, Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName))) 
       return Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName; 
      if (VirtualPathProvider.FileExists(string.Format(format, controllerName, actionName, DefaultLanguageCode))) 
       return DefaultLanguageCode; 
      return string.Empty; 
     } 



    } 

Notez que la mise en cache est désactivée à l'aide de cette approche et vous devrez peut-être créer votre propre cache (pour obtenir la bonne langue)

+1

Bon travail avec l'extrait de code. Comment pouvez-vous détecter si View n'utilise pas de mise en page partagée et, par conséquent, ne le fournit pas du tout? –

1

est le plus simple ici que peut être (je suppose) exemple de commutation entre les vues en utilisant la convention suivante:

  1. MyView.cshtml - par défaut
  2. MyView.pl.cshtml - locale polonaise

.. et ainsi de suite

public class LocalizedRazor : RazorViewEngine 
    { 
    public LocalizedRazor() 
     : base() 
    { 
    } 

    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) 
    { 
     var controllerName = (string)controllerContext.RouteData.Values["controller"]; 
     var format = "~/Views/{0}/{1}.{2}.cshtml"; 
     var lang = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName; 
     if (VirtualPathProvider.FileExists(string.Format(format, controllerName, viewName, lang))) 
      return base.FindView(controllerContext, viewName + "." + lang, masterName, useCache); 

     return base.FindView(controllerContext, viewName, masterName, useCache); 
    } 
    } 

et Global.asax:

protected void Application_Start() 
    { 
     ViewEngines.Engines.Clear(); 
     ViewEngines.Engines.Add(new LocalizedRazor()); 
    }