title: Is it possible to localize a URL / routing in ASP.NET MVC?
body: <p>I'm working with a client that wants the URLs in our web application to be in French.  I'm an English developer and we also have English clients.  This is an interesting problem but I don't think its something the ASP.NET MVC Framework would support.</p>
  
  <p>Here's the scenario.  The route...</p>
  
  <p><strong>Specific EXAMPLE</strong><br>
  English URL<br>
  www.stackoverflow.com/questions/ask</p>
  
  <p>would also support</p>
  
  <p>French URL<br>
  www.stackoverflow.com/problème/poser</p>
  
  <p><strong>Generic EXAMPLE</strong><br>
  English URL<br>
  <a href="http://clientA.product.com/AreaNameEnglish/ControllerNameEnglish/ActionNameEnglish/params">http://clientA.product.com/AreaNameEnglish/ControllerNameEnglish/ActionNameEnglish/params</a></p>
  
  <p>also needs to support</p>
  
  <p>French URL<br>
  <a href="http://clientB.product.com/AreaNameFrench/ControllerNameFrench/ActionNameFrench/params">http://clientB.product.com/AreaNameFrench/ControllerNameFrench/ActionNameFrench/params</a></p>
  
  <p>So in MVC my Area, Controller and Actions all need to have both English and French translations.</p>
  
  <p>Obviously maintainability would be a HUGE issue if I were to go and hardcode all my Controllers, Views and Action names to French.  Is there anyway to localize the route that is presented in the browser without doing this?  Keeping in mind there are lots of different routes in the application.  A couple Areas each with a handful of Controller each with many Actions?</p>
  
  <p>Thanks, <br>
  Justin</p>
  
  <p><strong>EDIT</strong><br>
  Thanks to @womp here is what I've come up with so far...  Although in the end I took the approach which I posted as an answer.</p>
  
  <pre><code>public class LocalizedControllerFactory : DefaultControllerFactory
  {
      public override IController CreateController(RequestContext requestContext, string controllerName)
      {
          if (string.IsNullOrEmpty(controllerName))
              throw new ArgumentNullException("controllerName");
  
          if (CultureInfo.CurrentCulture.TwoLetterISOLanguageName == "fr")
          {
              controllerName = this.ReplaceControllerName(requestContext, controllerName);
              this.ReplaceActionName(requestContext);
              this.ReplaceAreaName(requestContext);
          }
  
          return base.CreateController(requestContext, controllerName);
      }
  
      private string ReplaceControllerName(RequestContext requestContext, string controllerName)
      {
          // would use the language above to pick the propery controllerMapper.  For now just have french
          Dictionary&lt;string, string&gt; controllerMapper = new Dictionary&lt;string, string&gt;()
          {
              {"frenchControllerA", "englishControllerA"},
              {"frenchControllerB", "englishControllerB"}
          };
  
          return this.ReplaceRouteValue(requestContext, "controller", controllerMapper);
      }
  
      private void ReplaceAreaName(RequestContext requestContext)
      {
          // would use the language above to pick the propery areaMapper.  For now just have french
          Dictionary&lt;string, string&gt; areaMapper = new Dictionary&lt;string, string&gt;()
          {
              {"frenchAreaX", "englishAreaX"},
              {"frenchAreaY", "englishAreaY"}
          };
  
          this.ReplaceRouteValue(requestContext, "area", areaMapper);
      }
  
      private void ReplaceActionName(RequestContext requestContext)
      {
          // would use the language above to pick the propery actionMapper.  For now just have french
          Dictionary&lt;string, string&gt; actionMapper = new Dictionary&lt;string, string&gt;()
          {
              {"frenchAction1", "englishAction1"},
              {"frenchAction2", "englishAction2"}
          };
  
          this.ReplaceRouteValue(requestContext, "action", actionMapper);
      }
  
      private string ReplaceRouteValue(RequestContext requestContext, string paramName, Dictionary&lt;string, string&gt; translationLookup)
      {
          if (requestContext.RouteData.Values[paramName] == null)
          {
              return null;
          }
  
          string srcRouteValue = requestContext.RouteData.Values[paramName] as string;
          if (srcRouteValue != null &amp;&amp; translationLookup.ContainsKey(srcRouteValue))
          {
              requestContext.RouteData.Values[paramName] = translationLookup[srcRouteValue];
          }
  
          return requestContext.RouteData.Values[paramName] as string;
      }
  }
  </code></pre>
  
  <p>A decent start.  If I localize just the ControllerName and ActionName in the Url it will find and render the proper View.  However I have the following problems.</p>
  
  <p><strong>Area Name can't be translated</strong><br>
  Localizing the Area means the Controller.View() method fails to find Views.
  Even though I've replaced the Area name in the request context the ViewEngineCollection.Find() method doesn't seem to pick it up.  Anywhere in my Controller class that does "return View()" fails to find the default view for its action.  If I don't localize the Area then the other steps work.</p>
  
  <p><strong>RedirectToAction or Html.ActionLink</strong><br>
  Anytime the application calls RedirectToAction or if I use an Html.ActionLink helper or something similiar the Urls generate are the English ones.  It looks like I'm going to have to add logic somewhere possibly in multiple spots to convert an English Url to the French (or other language) one.</p>