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

Posted

技术标签:

【中文标题】是否可以在 ASP.NET MVC 中本地化 URL/路由?【英文标题】:Is it possible to localize a URL / routing in ASP.NET MVC? 【发布时间】:2010-10-14 17:22:01 【问题描述】:

我正在与一个希望我们的 Web 应用程序中的 URL 使用法语的客户合作。我是一名英语开发人员,我们也有英语客户。这是一个有趣的问题,但我认为 ASP.NET MVC 框架不支持它。

这是场景。路线……

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

也会支持

法文网址 www.***.com/problème/poser

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

也需要支持

法文网址http://clientB.product.com/AreaNameFrench/ControllerNameFrench/ActionNameFrench/params

所以在 MVC 中,我的 Area、Controller 和 Actions 都需要有英文和法文的翻译。

如果我将所有控制器、视图和操作名称硬编码为法语,显然可维护性将是一个巨大的问题。有没有办法在不这样做的情况下本地化浏览器中显示的路线?请记住,应用程序中有许多不同的路线。几个区域,每个区域都有几个控制器,每个区域都有很多动作?

谢谢, 贾斯汀

编辑 感谢@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,它将找到并呈现正确的视图。但是我有以下问题。

地区名称无法翻译 本地化区域意味着 Controller.View() 方法无法找到视图。 即使我已经在请求上下文中替换了区域名称,但 ViewEngineCollection.Find() 方法似乎并没有找到它。在我的 Controller 类中执行“return View()”的任何地方都无法找到其操作的默认视图。如果我不本地化该区域,那么其他步骤将起作用。

RedirectToAction 或 Html.ActionLink 任何时候应用程序调用 RedirectToAction 或者如果我使用 html.ActionLink 帮助器或类似的 Urls 生成的是英文的。看起来我将不得不在多个位置的某个地方添加逻辑,以将英语 URL 转换为法语(或其他语言)。

【问题讨论】:

【参考方案1】:

以下博客包含这个确切问题的完整解决方案。它实际上是一个非常优雅的解决方案,我强烈推荐。

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

注意要使其适用于 AREA,我必须将以下扩展方法添加到他的“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 Forums987654322@上提出的相同问题被定向到博客

【讨论】:

不错的发现。它本质上是相同的概念,除了封装在路由中,而不是在控制器实例化逻辑中。我同意,它可能更优雅一些,似乎更适合解决方案。 我知道这是一篇旧帖子,但你们刚刚拯救了我的皮肤。很好的答案!【参考方案2】:

MVC 框架几乎支持您能想到的任何路由方案,但不一定支持默认路由类。

我遇到的大多数本地化解决方案都涉及使用相同的 Controller 和 Action 方法名称,但在路由中指定一个文化参数,该参数指示呈现哪个视图的翻译版本。例如,

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 的语言。

【讨论】:

非常有趣。我正在调查它。感谢您的启动。 不客气,祝你好运。如果我的回答有帮助,别忘了点赞:) 好吧,我被困在 Request.Header 上。我正在研究它,但如果您能告诉我如何配置“ex-MX”部分以解释为请求标头,那将有所帮助。我找不到示例博客文章。我原以为它会成为 Global.asax.cs 文件中 RouteTable 的一部分,但没有成功。 对不起,我想我可能把你弄糊涂了。那篇博客文章与我在前三段中描述的方法不同。博客文章展示了如何根据用户的浏览器文化设置选择控制器。我描述的第一种方法与使用自定义控制器工厂不同。在第一种方法中,您将使用类似 culture/area/controller/action 的路线,并根据“culture”标记简单地选择您的视图。但在这种情况下,你所有的 URL 都是英文的。 好的,所以“接受语言”来自浏览器语言。我已经按照您的建议解决了语言问题。在这一点上,我取得了一定的成功:) 我还有 2 个问题。我将更新问题以描述它们。请稍后再回来查看。

以上是关于是否可以在 ASP.NET MVC 中本地化 URL/路由?的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC Route详解

Rosetta 喜欢 ASP.NET MVC Web 应用程序的本地化?

是否可以在 Visual Studio 2013 中使用 asp.net mvc 6?

是否可以在 ASP.NET MVC 的脚本块中引用 ViewData?

是否可以在不同的 AppDomain 中运行 ASP.NET MVC 路由?

是否可以使用 maproute 在 asp.net mvc 中路由多个参数