在ASP.NET MVC中本地化/翻译路由

18
有没有人知道ASP.NET MVC中本地化路由的好方法?我想实现这样的效果,让这两个URL指向同一个操作/资源: 此外,应该有可能根据当前文化(或默认文化,如果没有可用的翻译)生成路由。或者,如果我能够指定只有一种文化,那么上面的这两个链接中只有一个能够工作也是可行的。
我尝试了Maarten Balliauw的非常好的方法,但他的解决方案不幸地不能与Html.RenderAction(...)一起使用。
当然,我可以为所有翻译添加路由,例如:
routes.MapRoute(
    "Products_Categories",
    "Produkte/Kategorien",
    new { controller = "Products", action = "Categories" }
);

但这将导致大量的路由,并且非常不灵活。欢迎任何更好的解决方案 :-) 越灵活越好。

6个回答

2

这确实可以简化路由管理,+1。然而,正如你所说,它并没有解决真正的问题。 - davehauser
我已经更新了链接,从wayback存档中获取最新版本。 - Beno

2
你可以尝试一下我刚发现的很棒的 AttributeRouting 项目!你可以通过 NuGet 获取它。

1

您可以在https://github.com/boudinov/mvc-5-routing-localization找到一个简单的解决方案,既适用于属性路由,也适用于传统路由。

您可以使用/de前缀来实现此功能,这是首选模式。您需要在资源文件中将“Products”和“Categories”翻译成德语:

如果你不想使用语言前缀来回答原始问题,你可以像这样获取答案:


0

我认为这不应该是一个问题。必须选择一种文化(由用户或系统选择),以确定路线的语言。始终只使用一组路线。 - davehauser
1
即使这并不是一个问题,但在URL中包含文化信息是谷歌推荐的最佳实践之一,以便他们可以识别页面的文化背景。这是三种推荐方法之一 - 其他两种是http://en.example.org/Products/Categories或http://example.co.us/Products/Categories - 当然后者可能成本高昂且难以实现。 - NightOwl888

0

0
尝试使用自定义路由。这比此处提供的替代方案更灵活。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Routing;
using System.Web;
using System.Web.Mvc;

public class ProductRoute : RouteBase
{

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        RouteData result = null;

        string virutalPath = httpContext.Request.Url.AbsolutePath.Substring(1).ToLowerInvariant();

        // Call the database here to retrieve the productId based off of the virtualPath
        var productId = Product.GetProductIdFromVirtualPath(virutalPath);
        if (productId != Guid.Empty)
        {
            result = new RouteData(this, new MvcRouteHandler());
            result.Values["controller"] = "Product";
            result.Values["action"] = "Details";
            result.Values["id"] = productId;
        }

        return result;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        VirtualPathData result = null;
        string controller = Convert.ToString(values["controller"]);
        string action = Convert.ToString(values["action"]);

        if (controller == "Product")
        {
            string path = string.Empty;
            if (action == "Details")
            {
                Guid productId = (Guid)values["id"];

                // Call the database here to get the Virtual Path
                var virtualPath = Product.GetVirtualPathFromProductId(productId);
            }

            if (!String.IsNullOrEmpty(virtualPath))
            {
                result = new VirtualPathData(this, virtualPath);
            }
        }


        return result;
    }

}

您可以通过将其直接添加到Global.asax中的路由表中来使用该路由,如下所示:

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            "home", // Route name
            "", // URL with parameters
            new { controller = "Home", action = "Index" } // Parameter defaults
        );


        // Add your custom route like so
        routes.Add(new ProductRoute());


        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );

    }

然后在您的本地化产品表上,只需有一个包含要查找路径的字段(不带前导斜杠)。当然,您没有提及如何存储数据,因此您需要自己想出来。

此外,您需要通过解析virtualPath来处理本地化。根据Google的说法,它应该存在。您应该根据传递的标头处理初始Culture,并重定向(302)到所选Culture的URL。然后用户应该能够切换语言,在这种情况下,您可以将其放入cookie中以便记住其偏好设置。但是,搜索引擎应该能够从URL中识别Culture而无需传递任何标头。

这将通过GetVirtualPath()方法处理@Html.RenderAction()的情况,如果需要,您可以更改逻辑。我建议您添加缓存,因为这将使每个请求都直接打到数据库中。路由表在应用程序启动时填充,但每个路由都会在每个请求上执行。

还有一件事 - 要处理“路由不匹配”场景,只需返回null,路由器就会继续移动到下一个配置的路由。这样可以配置尽可能多的自定义路由而不混淆逻辑。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接