asp.net многоязычные ссылки / маршрутизация mvc
Это вопрос из двух частей, касающийся многоязычных URL / маршрутизации asp.net mvc и лучших практик / преимуществ SEO…
Вопрос часть 1)
Меня просят создать новый веб-сайт ASP.NET MVC, который будет поддерживать минимум (сначала) двух языков (английский и французский), возможно, в будущем, 3 языка…
Что касается локализации приложения (метки, ошибки jQuery и т. Д.), То все должно быть хорошо с использованием файлов ресурсов, и я нашел много примеров по этому поводу... но моя проблема / вопрос больше касаются URL-адресов.
С точки зрения SEO, каков рекомендуемый подход между этими двумя модами?
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
Есть ли известная проблема / штраф при использовании одного над другим?
Или это так мало, что становится неактуальным!
Вопрос часть 2)
Для достижения Fashion 2 я уже нашел статью здесь: ASP.NET MVC - Маршрут локализации
Но мне было бы любопытно узнать, как добиться моды 1.
У кого-нибудь есть ссылки?
Кроме того, насколько я знаю, переписывание URL-адресов - это не то, что мне нужно, поскольку я не хочу "перенаправлять" пользователей… Я просто хочу, чтобы URL-адреса отображались на соответствующем языке без необходимости показывать культуру в URL
Заранее спасибо за любую помощь в этом!
3 ответа
Вы можете создать базовый контроллер с логикой локализации, как показано ниже:
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;
}
}
Вышеуказанный контроллер удовлетворяет моду 2 вашего вопроса, если вы хотите игнорировать папку культур, просто не назначайте язык в RouteDate. Для достижения моды 2 вы должны добавить маршрутизацию для культуры, как показано ниже:
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})?"}
);
Чтобы достичь желаемого, вам нужно реализовать три вещи:
Многоязычный маршрут для обработки входящих 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
по умолчанию), например:
- Пример кода для мультиязычного расширения Html.ActionLink
- Пример кода для мультиязычного расширения Url.Action
(оба написаны на C#)
Вы также можете избежать шаблона метода расширения и записать их как MultiLanguageActionLink
/ MultiLanguageAction
вместо.
Для получения дополнительной информации и дополнительных образцов по этой теме вы также можете прочитать этот пост в моем блоге.
AttributeRouting может решить Fashion 1: