【问题标题】:How to route a multiple language URL with a MVC如何使用 MVC 路由多语言 URL
【发布时间】:2011-01-09 21:56:06
【问题描述】:

我需要现有控制器的多语言 URL 路由。让我解释一下:

我有一个名为“产品”的控制器和一个名为“软件”的视图;因此,默认情况下,如果用户输入“http://example.com/en/Product/Software”,则获取正确的内容(http://example.com/Product/Software 中确实存在),

但是,如果另一个用户(法国用户)键入“http://example.com/fr/Produits/logiciels”,则必须越过控制器并显示正确的内容(相同的http://example.com/Product/Software,但使用法语文本)。

注意:我使用“{language}/{controller}/{action}/{id}”设置路由表

任何其他无效 URL 都必须显示 404 页面。

有可能吗?

【问题讨论】:

  • 实际上,如果您关心搜索引擎排名,这不是一个好主意。您可以始终重定向到英文页面,或者为同一实体的所有实例使用标准规范 URL。

标签: c# asp.net-mvc model-view-controller routing url-rewriting


【解决方案1】:

我强烈推荐以下方法在 MVC 5(和

你基本上需要实现三件事:

  • 多语言感知路由来处理传入的 URL(如果您使用 MVC5 或更高版本,您也可以使用 基于属性的路由,但我仍然更喜欢使用处理此问题的全局规则)。
  • 一个 LocalizationAttribute 来处理这些类型的多语言请求。
  • 在您的应用程序中生成这些 URL 的辅助方法Html.ActionLink 和/或 Url.Action 扩展方法)。

有关更多详细信息和代码示例,请参阅 this answer

有关此主题的更多信息和更多示例,您还可以阅读您还可以阅读我在此主题上写的this blog post

【讨论】:

    【解决方案2】:

    基于 Dan 的帖子,我使用下面的内容来翻译我的控制器和动作名称。

    我创建了一个表来存储值,它可以并且可能应该保存在资源文件中以将所有内容放在一起;但是我使用了一个数据库表,因为它更适合我的公司流程。

    CREATE TABLE [dbo].[RoutingTranslations](
    [RouteId] [int] IDENTITY(1,1) NOT NULL,
    [ControllerName] [nvarchar](50) NOT NULL,
    [ActionName] [nvarchar](50) NOT NULL,
    [ControllerDisplayName] [nvarchar](50) NOT NULL,
    [ActionDisplayName] [nvarchar](50) NOT NULL,
    [LanguageCode] [varchar](10) NOT NULL)
    

    RouteConfig.cs 文件随后更改为:

    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
            //Build up routing table based from the database.  
            //This will stop us from having to create shedloads of these statements each time a new language, controller or action is added
            using (GeneralEntities db = new GeneralEntities())
            {
                List<RoutingTranslation> rt = db.RoutingTranslations.ToList();
                foreach (var r in rt)
                {
                    routes.MapRoute(
                        name: r.LanguageCode + r.ControllerDisplayName + r.ActionDisplayName,
                        url: r.LanguageCode + "/" + r.ControllerDisplayName + "/" + r.ActionDisplayName + "/{id}",
                        defaults: new { culture = r.LanguageCode, controller = r.ControllerName, action = r.ActionName, id = UrlParameter.Optional },
                        constraints: new { culture = r.LanguageCode }
                    );
                }                
            }
    
            //Global catchall
            routes.MapRoute(
                name: "Default",
                url: "{culture}/{controller}/{action}/{id}",
                defaults: new {culture = CultureHelper.GetDefaultCulture(), controller = "Default", action = "Index", id = UrlParameter.Optional }
                //defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
    
        }
    }
    

    默认情况下,这将始终使用英文控制器和操作名称,但允许您通过在表中输入值来提供覆盖。

    (我的国际化代码主要来自这篇精彩的博文。 http://afana.me/post/aspnet-mvc-internationalization-part-2.aspx)

    【讨论】:

    • 这不适用于新添加的路由,因为注册路由仅在启动时执行吗?
    【解决方案3】:

    正如之前所建议的,这确实偏离了网站网址(和路线)使用英文的惯例。

    尽管如此,这是可能的,但为了做到这一点,您可能必须考虑为每种外语的每个操作生成一条路线。因此,对于具有 20 个操作和三种语言(英语、法语和德语)的网站,您将需要 41 条路线(20 条法语、20 条德语和 1 条英语)。我承认,这不是最有效的系统,但它可以按您的意愿工作。

    //You'll only need one of these, which is the default.
    routes.MapRoute(
      "English route",
      "en/{controller}/{action}/{id}"
      new { controller = "Home", action = "Index", language = "en" },
    );
    
    routes.MapRoute(
      "FrenchHome",
      "fr/Demarrer/Index/{id}",
      new { controller = "Home", action = "Index", language = "fr" }
    );
    
    routes.MapRoute(
      "GermanHome",
      "de/Heim/Index/{id}", //'Heim' is, I believe the correct usage of Home in German.
      new { controller = "Home", action = "Index", language = "de" }
    );
    
    //Some more routes...
    
    routes.MapRoute(
      "FrenchSoftware",
      "fr/Produit/Logiciels/{id}",
      new { controller = "Product", action = "Software", language = "fr" }
    );
    
    routes.MapRoute(
      "GermanSoftware",
      "de/Produkt/Software/{id}", //In this instance, Software should be the same in German and English.
      new { controller = "Product", action = "Software", language = "de" }
    );
    
    //And finally, the 404 action.
    routes.MapRoute(
      "Catchall",
      "{language}/{*catchall}",
      new { controller = "Home", action = "PageNotFound", language = "en" },
      new { language = "^(en|fr|de)$" }
    );
    
    //This is for the folks who didn't put a language in their url.
    routes.MapRoute(
      "Catchall",
      "{*catchall}",
      new { controller = "Home", action = "PageNotFound", language = "en" }
    );
    

    在您的操作中,例如产品/软件...

    public ActionResult Software(string language, int id)
    {
      //This would go off to the DAL and get the content in whatever language you want.
      ProductModel model = ProductService.GetSoftware(language, id);
    
      return View(model);
    }
    

    如果有人过来说有更好的方法,我会喜欢它,因为我同意使用外语的 url 不好,并且考虑到互联网它本身正在朝着允许在 url 中使用非罗马字符的方向发展,我们越早寻找解决方案越好。

    不仅如此,我知道骄傲的法国人不喜欢看到他们的网站网址包含英语。 :)

    【讨论】:

    • (有人提出了更好的方法...)不关心传递给操作方法的内容怎么办?相反,像往常一样路由它。但是在你的基础控制器上有一个 OnActionExecuting() 的重载,它会根据路由相应地设置 CultureUI(例如,它会查看 filterContext 中的 Request.Url)。或者更强类型的版本是创建您自己的继承自 Route 的 LangaugeRoute() 类。在其上添加一个新属性 LanguageCode,并在您的答案中将其设置在您的 MapRoute 中。然后,您可以在 OnActionExecuting() 中将其强制类型化。
    • 我喜欢这个,但检查当前文化有其风险,主要与您可能实际上没有网站版本的可能性有关。例如,土耳其语在文化方面有很多问题(谷歌土耳其语-i 问题)。在任何情况下,您都必须在某处创建一堆 if/else 或大小写语句来处理您拥有的翻译,以便在不正确时默认为另一个。
    • 另外,这是 Maarten Balliauw 就该主题撰写的一篇出色的博客文章。 blog.maartenballiauw.be/post/2010/01/26/…
    • @DanAtkinson 感谢您的回答。这对我帮助很大。但是现在如何创建 ActionLink 并维护所选语言的正确路径?例如,如果我将选择语言德语,然后有一个 @Html.ActionLink("HomeLink", "Index", "Home") 我希望收到 href="de/Heim/Index" 但是我会收到 href= “en/Home/Index”...或者如果“FrenchSoftware”路线排在第一位,我将收到 href="fr/Produit/Logiciel"。我应该怎么做才能收到所选语言的正确 href?
    • @John 看看这篇文章 - afana.me/post/aspnet-mvc-internationalization-part-2.aspx。使用Request.UserLanguage 应该会引导您朝着正确的方向前进。
    【解决方案4】:

    你应该有类似“http://mysite.com/en/Product/Software”的英文网址和“http://mysite.com/fr/Product/Software”的法文网址,这很有意义。

    对两者使用相同的视图。

    编码愉快。

    【讨论】:

    • 这意味着不友好的 URL,因为世界上并不是每个人都会说英语
    • 默认你应该使用英文 erikkallen
    • @erikkallen:那么 OP 是否应该旨在提供所有可能语言的 URL? URL 应该标识一个资源,并尽可能描述该资源的性质。这确实意味着应该有多个 URL 来满足多种语言的需求。呈现资源的语言很重要。赞成。
    • 非常感谢您的快速响应,mysite.com/en/Product/Software 对我来说没问题,但是怎么办???如何找到正确的控制器并查看并设置它???注意:我使用“{language}/{controller}/{action}/{id}”作为路由
    • Hamid 请检查此链接stackoverflow.com/questions/725220/… Fred 回答
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-12-11
    • 2011-10-08
    • 2020-03-09
    • 2012-11-25
    • 2011-06-19
    • 2019-12-09
    • 2020-03-04
    相关资源
    最近更新 更多