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

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

这是场景。路线……

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

也会支持

法文网址
www.stackoverflow.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 转换为法语(或其他语言)。

【问题讨论】:

    标签: asp.net-mvc url localization asp.net-mvc-routing


    【解决方案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 个问题。我将更新问题以描述它们。请稍后再回来查看。
    猜你喜欢
    • 2011-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-23
    • 1970-01-01
    • 1970-01-01
    • 2010-11-22
    相关资源
    最近更新 更多