Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET (MVC) routes internationalization

I was looking for a solution to internationalize/localize routes on an ASP.NET MVC website. I stumbled upon the blog post Translating routes (ASP.NET MVC and Webforms) by Maarten Balliauw. He present a very nice solution, which works great - until there's a Html.RenderAction("...") in the view.

Basically he introduces a TranslatedRoute inheriting from System.Web.Routing.Route, that than does the translation using a Dictionary with the translations on the fly.

Any idea why this behaves differently when calling Html.RenderAction("...")? Also it seems like if the error only occurs, if the action that should be rendered is in the same controller.

And here's the exact error:

"The controller for path '/MyTranslatedControllerName' was not found or does not implement IController."

Update:

Here's my routes configuration (taken from Maarten's sample project, added routes for Contact, which is the partial to be rendered):

    public static void RegisterRoutes(RouteCollection routes)
        {
            CultureInfo cultureEN = CultureInfo.GetCultureInfo("en-US");
            CultureInfo cultureDE = CultureInfo.GetCultureInfo("de-DE");
            CultureInfo cultureFR = CultureInfo.GetCultureInfo("fr-FR");

            DictionaryRouteValueTranslationProvider translationProvider = new DictionaryRouteValueTranslationProvider(
                new List<RouteValueTranslation> {
                    new RouteValueTranslation(cultureEN, "Home", "Home"),
                    new RouteValueTranslation(cultureEN, "About", "About"),
                    new RouteValueTranslation(cultureEN, "Contact", "Contact"),
                    new RouteValueTranslation(cultureDE, "Home", "Home"),
                    new RouteValueTranslation(cultureDE, "About", "About"),
                    new RouteValueTranslation(cultureDE, "Contact", "Kontakt"),
                    new RouteValueTranslation(cultureFR, "Home", "Demarrer"),
                    new RouteValueTranslation(cultureFR, "About", "Infos"),
                    new RouteValueTranslation(cultureFR, "Contact", "Contact")
                }
            );

            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapTranslatedRoute(
                "TranslatedRoute",
                "{controller}/{action}/{id}",
                new { controller = "Home", action = "Index", id = "" },
                new { controller = translationProvider, action = translationProvider },
                true
            );

            routes.MapRoute(
                "Default",                                              // Route name
                "{controller}/{action}/{id}",                           // URL with parameters
                new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
            );
like image 693
davehauser Avatar asked Jun 02 '11 23:06

davehauser


1 Answers

This will depend on your route configuration. Can you share it?

EDIT: It seems the RenderAction method is using "GetVirtualPath" on the route to determine a URL for the MvcHandler. However, that one does not call back into the "GetRouteData" method.

There is a method of detecting this: routeData.DataTokens["ParentActionViewContext"] Problem is it comes to late in the pipeline for the TranslatedRoute to know about this...

In short: I'm affraid this is impossible by the current implementation of ChildActionExtensions.ActionHelper in System.Web.Mvc...

I do have a (dirty, self-disrespecting) workaround (which you can also wrap in a custom RenderAction() method): - In your view, do this:

<%
RouteData.DataTokens.Add("GoingToRenderChildAction",
true); %> <%
Html.RenderAction("Contact", "Home");
%> <%
RouteData.DataTokens["GoingToRenderChildAction"]
= false; %>

Razor syntax:

@{
    ViewContext.RequestContext.RouteData.DataTokens.Add("GoingToRenderChildAction",
                                                         true);
}

@Html.Action("Action", "Controller" )

@{
    ViewContext.RequestContext.RouteData.DataTokens["GoingToRenderChildAction"]=false;
}

In TranslatedRoute.cs GetVirtualPath, add the following as the first statement:

if(requestContext.RouteData.DataTokens.ContainsKey("GoingToRenderChildAction") &&
(bool)requestContext.RouteData.DataTokens["GoingToRenderChildAction"] == true)
{
    return base.GetVirtualPath(requestContext, values);
}

This will work, but may have unwanted side effects.

like image 143
maartenba Avatar answered Oct 13 '22 10:10

maartenba