如何使用 MVC 路由多语言 URL

Posted

技术标签:

【中文标题】如何使用 MVC 路由多语言 URL【英文标题】:How to route a multiple language URL with a MVC 【发布时间】: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。 【参考方案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 请检查此链接***.com/questions/725220/… Fred 回答

以上是关于如何使用 MVC 路由多语言 URL的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET MVC 多语言实现——URL路由

在mvc4中多语言建站的实例

使用 ASP.NET MVC 的多语言网站

在 Zend 中使用多语言路由器

URI 路由不起作用(多语言)

如何制作多语言链接文本li菜单和下拉列表?