6

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
            );
1
  • You can try the awesome AttributeRouting project that I just found! You can get it through NuGet. Commented Mar 11, 2012 at 17:08

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

3 Comments

I just used your sample project, added a Contact action to HomeController and then did a Html.RenderAction("Contact") on About.aspx. Also added new new RouteValueTranslation(cultureEN, "Contact", "Contact") (for the other cultures as well)
Thanks! So I'll think about messing my code with this solution ;-) Too bad, your approach to localizing routes was the cleanest solution I ever found...
@maartenba: Great solution. I just updated your answer with the corresponding Razor syntax. I'm also using your MVC SiteMap provider: mvcsitemap.codeplex.com You helped a lot with these implementations... Thanks!
0

In your view(Razor syntax, VB):

@Html.Action("Index", "Home", New With {.childAction = True})

Then in TranslatedRoute.cs GetVirtualPath as the first statement:

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

This way is much lighter and only for a desired action.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.