是否可以在ASP.NET MVC中本地化URL /路由?

问题描述:

我正在和一位希望我们的Web应用程序中的URL使用法语的客户端合作。我是英语开发人员,我们也有英语客户。这是一个有趣的问题,但我不认为它是ASP.NET MVC框架支持的东西。是否可以在ASP.NET MVC中本地化URL /路由?

这里是场景。路线...

具体的例子
英文网址
www.*.com/questions/ask

还将支持

法国URL
www.*.com/problème/poser

通用示例
英文网址
http://clientA.product.com/AreaNameEnglish/ControllerNameEnglish/ActionNameEnglish/params

还需要支持

法国URL
http://clientB.product.com/AreaNameFrench/ControllerNameFrench/ActionNameFrench/params

所以在MVC我区,控制器和操作都需要有英语和法语翻译。

如果我要将所有控制器,视图和操作名称硬编码到法语,显然可维护性将是一个巨大的问题。无论如何本地化没有这样做的浏览器中呈现的路线?请记住,应用程序中有很多不同的路线。几个区域每个都有少量控制器,每个控制器都有很多操作?

感谢,
贾斯汀

编辑
由于这里@womp是我想出那么远,虽然在最后,我把我张贴的答案的方法。

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<string, string> controllerMapper = new Dictionary<string, string>() 
     { 
      {"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<string, string> areaMapper = new Dictionary<string, string>() 
     { 
      {"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<string, string> actionMapper = new Dictionary<string, string>() 
     { 
      {"frenchAction1", "englishAction1"}, 
      {"frenchAction2", "englishAction2"} 
     }; 

     this.ReplaceRouteValue(requestContext, "action", actionMapper); 
    } 

    private string ReplaceRouteValue(RequestContext requestContext, string paramName, Dictionary<string, string> translationLookup) 
    { 
     if (requestContext.RouteData.Values[paramName] == null) 
     { 
      return null; 
     } 

     string srcRouteValue = requestContext.RouteData.Values[paramName] as string; 
     if (srcRouteValue != null && translationLookup.ContainsKey(srcRouteValue)) 
     { 
      requestContext.RouteData.Values[paramName] = translationLookup[srcRouteValue]; 
     } 

     return requestContext.RouteData.Values[paramName] as string; 
    } 
} 

体面的开始。如果我本地化了Url中的ControllerName和ActionName,它将查找并呈现适当的View。不过,我有以下问题。

区域名称不能转换
本地化区域系指Controller.View()方法无法找到的意见。 尽管我已经在请求上下文中替换了区域名称,但ViewEngineCollection.Find()方法似乎没有提取它。在执行“返回View()”的Controller类中的任何位置都无法找到其操作的默认视图。如果我没有将区域本地化,那么其他步骤就可以工作。

RedirectToAction或Html.ActionLink
每当应用程序调用RedirectToAction或者如果我使用的Html.ActionLink辅助或类似的东西的URL生成是英文的。看起来我必须在多个地方添加逻辑,以将英文网址转换为法文(或其他语言)。

以下博客包含完整的解决方案,确切的问题。其实我非常推荐一个非常优雅的解决方案。

https://blog.maartenballiauw.be/post/2010/01/26/translating-routes-(aspnet-mvc-and-webforms).html

注意得到它的地区工作,我不得不在下面的扩展方法添加到自己的“TranslatedRouteCollectionExtensions.cs”类:

public static Route MapTranslatedRoute(this AreaRegistrationContext areaContext, string name, string url, object defaults, object routeValueTranslationProviders, bool setDetectedCulture) 
    { 
     TranslatedRoute route = new TranslatedRoute(
      url, 
      new RouteValueDictionary(defaults), 
      new RouteValueDictionary(routeValueTranslationProviders), 
      setDetectedCulture, 
      new MvcRouteHandler()); 

     route.DataTokens["area"] = areaContext.AreaName; 

     // disabling the namespace lookup fallback mechanism keeps this areas from accidentally picking up 
     // controllers belonging to other areas 
     bool useNamespaceFallback = (areaContext.Namespaces == null || areaContext.Namespaces.Count == 0); 
     route.DataTokens["UseNamespaceFallback"] = useNamespaceFallback; 

     areaContext.Routes.Add(route); 

     return route; 
    } 

然而,即使这种翻译的路线通过AREA可以读取和解释生成的路线总是包含英文AREA名称,但本地化其他所有内容。

我是通过询问关于ASP.NET MVC Forums

+0

很好找。它基本上是相同的概念,除了封装在路由中,而不是在控制器实例化逻辑中。我同意,它可能更优雅一些,它似乎是解决方案的更合适的领域。 – womp 2010-10-15 02:40:57

+0

我知道这是一个旧帖子,但你们只是救了我的皮肤。很好的答案! – 2014-10-14 18:12:51

MVC框架几乎支持您可以想到的任何路由场景,但不一定使用默认路由类。

我跑过的大多数本地化解决方案都涉及到使用相同的Controller和Action方法名称,但在路径中指定了文化参数,该参数规定了View的哪个翻译版本。例如,

http://clientA.product.com/AreaName/Controller/Action //en-US 
http://clientB.product.com/es-MX/AreaName/Controller/Action // spanish 

如果你真的必须转变的URL的,虽然,我看不出有其他的选择,然后在某处保持的映射表。如果我正确理解你的问题,你需要能够将“问题”(控制器)和“询问”(行动)的所有不同语言翻译映射到相同的控制器/操作方法组合。

但是,一旦您在某处(资源文件?)构建了此表,您可以轻松覆盖该框架正在使用的DefaultControllerFactory,并实现自己的逻辑以确定要实例化的控制器。因此,不要仅仅将URL中的{controller}令牌作为简单字符串比较进行匹配,您可以实现逻辑以根据映射表检查它以选择正确的控制器。

有关创建自定义控制器工厂的演练,check this great blog post。它实际上也是一个本地化示例,但它基于用户的文化设置,而不是URL的语言。

+0

非常有趣的同样的问题引导到一个博客。我正在研究它。感谢您的启动。 – Justin 2010-10-14 18:01:33

+0

不客气,祝你好运。如果我的答案有帮助,不要忘记注册:) – womp 2010-10-14 18:23:50

+0

那么我卡在Request.Header上。我正在研究它,但如果您可以告诉我如何配置“ex-MX”部分以解释为请求标头,这将有所帮助。我找不到它的示例博客文章。我本来以为它是Global.asax.cs文件中的RouteTable的一部分,但没有去。 – Justin 2010-10-14 19:38:41