Asp.net mvc asp.net mvc多语言URL/路由

Asp.net mvc asp.net mvc多语言URL/路由,asp.net-mvc,asp.net-mvc-routing,Asp.net Mvc,Asp.net Mvc Routing,这是一个关于asp.net mvc多语言URL/路由和SEO最佳实践/优点的两部分问题 问题第1部分) 我被要求创建一个新的ASP.NET MVC网站,该网站将支持至少(最初)两种语言(英语和法语),也许在未来,三种语言 至于本地化应用程序(标签、jQuery错误等),使用资源文件应该没问题,我已经找到了很多这样的例子……但我关心的问题更多的是URL 就搜索引擎优化而言,这两种时尚之间的推荐方法是什么 Fashion 1 (no culture folder) www.mydomain.co

这是一个关于asp.net mvc多语言URL/路由和SEO最佳实践/优点的两部分问题

问题第1部分)

我被要求创建一个新的ASP.NET MVC网站,该网站将支持至少(最初)两种语言(英语和法语),也许在未来,三种语言

至于本地化应用程序(标签、jQuery错误等),使用资源文件应该没问题,我已经找到了很多这样的例子……但我关心的问题更多的是URL

就搜索引擎优化而言,这两种时尚之间的推荐方法是什么

Fashion 1 (no culture folder)  
www.mydomain.com/create-account 
www.mydomain.com/creer-un-compte

Fashion 2 (with built in culture folder)
www.mydomain.com/create-account 
www.mydomain.com/fr/creer-un-compte <--notice the “fr” folder 
Fashion 1(无区域性文件夹)
www.mydomain.com/create-account
www.mydomain.com/creer-un-compte
时尚2(内置文化文件夹)
www.mydomain.com/create-account

www.mydomain.com/fr/creer-un-compte您可以创建具有以下本地化逻辑的基本控制器:

 public abstract class LocalizedController : Controller
 {
     protected override void ExecuteCore()
     {
         HttpCookie cookie;
         string lang = GetCurrentCulture();
         Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang, false);

         // set the lang value into route data
         RouteData.Values["lang"] = lang;

         // save the location into cookie
         cookie = new HttpCookie("DPClick.CurrentUICulture",
             Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName)
             {
                 Expires = DateTime.Now.AddYears(1)
             };

         HttpContext.Response.SetCookie(cookie);  
         base.ExecuteCore();
     }

     private  string  GetCurrentCulture()
     {
         string lang;

         // set the culture from the route data (url)

         if (RouteData.Values["lang"] != null &&
            !string.IsNullOrWhiteSpace(RouteData.Values["lang"].ToString()))
         {
             lang = RouteData.Values["lang"].ToString();
             if (Localization.Locales.TryGetValue(lang, out lang))
             {
                 return lang;
             }
         }
         // load the culture info from the cookie
         HttpCookie cookie = HttpContext.Request.Cookies["DPClick.CurrentUICulture"];
         if (cookie != null)
         {
             // set the culture by the cookie content
             lang = cookie.Value;
             if (Localization.Locales.TryGetValue(lang, out lang))
             {
                 return lang;
             }

         }
         // set the culture by the location if not speicified
         lang = HttpContext.Request.UserLanguages[0];
         if (Localization.Locales.TryGetValue(lang, out lang))
         {
             return lang;
         }
         //English is default
         return Localization.Locales.FirstOrDefault().Value;

     }

 }
            routes.MapRoute(
            "Localization", // Route name
            "{lang}/{controller}/{action}/{id}", // URL with parameters
            new {controller = "Default", action = "Index", id = UrlParameter.Optional}, // Parameter defaults
            new {lang = @"\w{2,3}(-\w{4})?(-\w{2,3})?"}
            );
如果要忽略区域性文件夹,只需不在RouteDate中分配lang,上述控制器就满足了问题的第2种方式。当然,要实现fashion 2,您必须添加文化路线,如下所示:

 public abstract class LocalizedController : Controller
 {
     protected override void ExecuteCore()
     {
         HttpCookie cookie;
         string lang = GetCurrentCulture();
         Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang, false);

         // set the lang value into route data
         RouteData.Values["lang"] = lang;

         // save the location into cookie
         cookie = new HttpCookie("DPClick.CurrentUICulture",
             Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName)
             {
                 Expires = DateTime.Now.AddYears(1)
             };

         HttpContext.Response.SetCookie(cookie);  
         base.ExecuteCore();
     }

     private  string  GetCurrentCulture()
     {
         string lang;

         // set the culture from the route data (url)

         if (RouteData.Values["lang"] != null &&
            !string.IsNullOrWhiteSpace(RouteData.Values["lang"].ToString()))
         {
             lang = RouteData.Values["lang"].ToString();
             if (Localization.Locales.TryGetValue(lang, out lang))
             {
                 return lang;
             }
         }
         // load the culture info from the cookie
         HttpCookie cookie = HttpContext.Request.Cookies["DPClick.CurrentUICulture"];
         if (cookie != null)
         {
             // set the culture by the cookie content
             lang = cookie.Value;
             if (Localization.Locales.TryGetValue(lang, out lang))
             {
                 return lang;
             }

         }
         // set the culture by the location if not speicified
         lang = HttpContext.Request.UserLanguages[0];
         if (Localization.Locales.TryGetValue(lang, out lang))
         {
             return lang;
         }
         //English is default
         return Localization.Locales.FirstOrDefault().Value;

     }

 }
            routes.MapRoute(
            "Localization", // Route name
            "{lang}/{controller}/{action}/{id}", // URL with parameters
            new {controller = "Default", action = "Index", id = UrlParameter.Optional}, // Parameter defaults
            new {lang = @"\w{2,3}(-\w{4})?(-\w{2,3})?"}
            );

属性运算可以解决方式1:


要实现您的目标,您基本上需要实现三件事:

处理传入URL的多语言感知路由

routes.MapRoute(
    name: "DefaultLocalized",
    url: "{lang}/{controller}/{action}/{id}",
    constraints: new { lang = @"(\w{2})|(\w{2}-\w{2})" },   // en or en-US
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
LocalizationAttribute用于处理此类多语言请求:

public class LocalizationAttribute : ActionFilterAttribute
{
    private string _DefaultLanguage = "en";

    public LocalizationAttribute(string defaultLanguage)
    {
        _DefaultLanguage = defaultLanguage;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        string lang = (string)filterContext.RouteData.Values["lang"] ?? _DefaultLanguage;
        if (lang != _DefaultLanguage)
        {
            try
            {
                Thread.CurrentThread.CurrentCulture =
                Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang);
            }
            catch (Exception e)
            {
                throw new NotSupportedException(String.Format("ERROR: Invalid language code '{0}'.", lang));
            }
        }
    }
}
在应用程序中生成这些URL的助手方法:这可以通过多种方式完成,具体取决于应用程序逻辑。例如,如果需要在Razor视图中执行此操作,那么最好编写两个扩展方法,使
Html.ActionLink
Url.Action
接受
CultureInfo
对象作为参数(和/或使用
CultureInfo.CurrentCulture
作为默认值),例如:

(都是用C#写的)

您还可以避免使用扩展方法模式,而是将它们写成
multi-languageActionLink
/
multi-languageAction


有关此主题的更多信息和更多示例,您也可以在我的博客上阅读。

哇,谢谢Feras!这段代码很棒,帮助我了解更多关于路由和本地化的信息。@FerasKayyali嗨,Feras,谢谢分享信息。我正在使用您的代码,但发现VS 2012无法识别本地化。它的名称空间和dll是什么?Thx@Franva这些必须是定制类,遗憾的是它们没有嵌入或解释它们的功能。