Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Localized views with Razor

I was trying to be witty and use a VirtualPathProvider to find localized views. It takes the requested view path and modifies it when checking after the file. It returns a localized virtual file if found:

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
}

The problem is that I get the following exception:

The VirtualPathProvider returned a VirtualFile object with VirtualPath set to '/Views/Shared/_Layout.sv.cshtml' instead of the expected '/Views/Shared/_Layout.cshtml'.

Sure, I could fake the file path, but that would produce problems with caching and different localizations. Right?

Anyone got a better way to be able to create localized views? I do not want to use the same view but with resource strings instead. Such views are so horrible that they almost makes me cry because they are so hard to read.

If you still haven't understood what I'm looking for:

/Views/User/Details.sv.cshtml

Hejsan @Model.FirstName

Detta är en lite rolig text på svenska.

/Views/User/Details.en.cshtml

Hello @Model.FirstName

This is a test on english.

Controller

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

I want to be able to switch views (to a localized one using CurrentCulture) without having to do anything manually at each request.

like image 599
jgauffin Avatar asked Dec 02 '25 21:12

jgauffin


1 Answers

Here is my implementation. It could be made more generic, but it fulfills all my requirements.

I looks for the most specialized view first and tries without a language specfication last.

View finding process:

  1. Details.sv-fi.cshtml
  2. Details.sv.cshtml
  3. Details.en.cshtml
  4. Details.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;
        }



    }

Note that the caching is disabled using this approach and you may need to create your own cache (to get the correct language)

like image 62
jgauffin Avatar answered Dec 04 '25 11:12

jgauffin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!