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

时间:2010-10-14 17:22:02

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

我正在与希望我们的网络应用程序中的网址为法语的客户合作。我是英语开发人员,我们也有英语客户。这是一个有趣的问题,但我不认为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我的区域,控制器和动作都需要有英文和法文翻译。

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

谢谢,
贾斯汀

修改
感谢@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()方法无法找到视图。 即使我已经在请求上下文中替换了Area名称,ViewEngineCollection.Find()方法似乎也没有取出它。我的Controller类中“返回View()”的任何地方都无法找到其操作的默认视图。如果我没有本地化区域,那么其他步骤就可以工作。

RedirectToAction或Html.ActionLink
每当应用程序调用RedirectToAction时,或者如果我使用Html.ActionLink帮助程序或类似的东西,则Urls生成的是英文版。看起来我不得不在某个地方添加逻辑,可能在多个地方将英语网址转换为法语(或其他语言)。

2 个答案:

答案 0 :(得分:14)

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

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 Forums

上提出的同一问题被引导到博客的

答案 1 :(得分:3)

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

我遇到过的大多数本地化解决方案都涉及使用相同的Controller和Action方法名称,但在路由中指定了一个culture参数,用于指示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的语言。