ASP.NET Локализация MVC 3 — Url.Content

#asp.net-mvc-3 #localization

#asp.net-mvc-3 #локализация

Вопрос:

У меня есть ASP.NET Сайт MVC 3, использующий пользовательский маршрут для указания языка в URL, вот так:

 routes.MapRoute("Default", "{culture}/{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", culture = "en", id = UrlParameter.Optional });
  

Затем мой базовый контроллер соответствующим образом устанавливает текущую культуру потока в своем событии OnActionExecuting следующим образом:

 protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
    var culture = filterContext.RouteData.Values["culture"] ?? "en";
    var cultureInfo = CultureInfo.GetCultureInfo((string)culture);
    Thread.CurrentThread.CurrentCulture = cultureInfo;
    Thread.CurrentThread.CurrentUICulture = cultureInfo;
    base.OnActionExecuting(filterContext);
}
  

Везде, где, на мой взгляд, мне нужна строка, зависящая от локали, я ссылаюсь на ресурс соответствующим образом:

 <img src="@Url.Content(Resources.Paths.ChallengeLogo)" alt="@Resources.Strings.AltChallengeLogo" class="logo" />
  

Однако для изображений URL (src=»…») будет соответствовать соглашению «~/Content/Culture/Images/Whatever.jpg «, и я бы предпочел не поддерживать вручную файл ресурсов для каждого расположения изображения. Короче говоря, то, что я бы предпочел сделать, это:

 <img src="@Url.Content("Images/ChallengeLogo.png")" alt="@Resources.Strings.AltChallengeLogo" class="logo" />
  

В этом сценарии метод Url.Content применил бы соглашение о пути и преобразовал значение атрибута src в, например:

 /Content/en-US/Images/ChallengeLogo.png
/Content/en-GB/Images/ChallengeLogo.png
/Content/de/Images/ChallengeLogo.png
etc...
  

Мне не нужно специально использовать Url.Content. Я более чем готов создать метод расширения для этой цели, но я даже не уверен, что использую наилучший подход. Каков здесь стандартный подход?

Редактировать: в итоге я создал помощника. Помощник имеет дополнительное преимущество проверки того, что путь к текущему языку действительно существует, или возврата к родительскому языку / языку по умолчанию, если это необходимо. Приведенный ниже код:

 private static CultureInfo _defaultCulture = CultureInfo.GetCultureInfo("en");

public static string Localized(this UrlHelper url, string pathTemplate)
{
    var server = url.RequestContext.HttpContext.Server;
    var culture = Thread.CurrentThread.CurrentUICulture;
    var localizedPath = string.Format(pathTemplate, culture.Name);
    var physicalPath = server.MapPath(localizedPath);

    while (!File.Exists(physicalPath) amp;amp; culture.Parent != null)
    {
        culture = culture.Parent;
        localizedPath = string.Format(pathTemplate, culture.Name);
        physicalPath = server.MapPath(localizedPath);
    }

    if (!File.Exists(physicalPath))
        localizedPath = string.Format(pathTemplate, _defaultCulture.Name);

    return url.Content(localizedPath);
}
  

На мой взгляд, я могу использовать этот помощник следующим образом:

 <div class="toolbox">

    <a href="#" class="button register">
        <img src="@Url.Localized("~/Content/Localized/{0}/Images/Button_Register.png")" 
             alt="@Resources.Strings.AltRegisterButton" /></a>

    <a href="#" class="button login">
        <img src="@Url.Localized("~/Content/Localized/{0}/Images/Button_Login.png")" 
             alt="@Resources.Strings.AltLoginButton" /></a>

</div>
  

Ответ №1:

Я думаю, что ваше предложение — первое, что тоже пришло мне в голову. Вы можете легко решить эту проблему, создав свой собственный html-помощник, который создает локализованный URL. Смотрите http://develoq.net/2011/how-to-create-custom-html-helpers-for-asp-net-mvc-3-and-razor-view-engine/ в качестве примера для создания пользовательского помощника html.

Комментарии:

1. В итоге я создал помощник, как вы предложили, но я собираюсь воздержаться от предоставления вам ответа, потому что я хотел бы посмотреть, есть ли у кого-нибудь еще какие-либо интересные альтернативы.

2. Если все ваши локализованные изображения всегда будут находиться в одной и той же структуре папок, вы могли бы исключить первую часть URL-адреса, например @Url.Localized(«Images /Button_Register.png»)» и добавить его в вспомогательный класс. Это сделает его короче и удобнее для чтения.

3. Я действительно в конечном итоге сделал именно это. Спасибо!

Ответ №2:

Ну, на самом деле я этого не делал, но я наткнулся на этот пост, когда искал кого-то, кто действительно это сделал.

Я подумал, что вы могли бы расширить StaticFileHandler, чтобы сначала искать некоторую «локализованную» версию статического файла, прежде чем обслуживать фактический файл.

Что-то вроде, при обслуживании http://yoursite.com/Content/images/logo.jpg

  1. Исказьте запрошенный URL и посмотрите, есть ли /Content/images/es-ES/logo.jpg существует?
  2. Если существует, то отправьте файл
  3. Если не существует, то либо выполните откат к языку по умолчанию, либо попробуйте найти нейтральный язык, прежде чем использовать язык по умолчанию.

** все это может быть связано с тем фактом, что /Content/images/logo.jpg ДОЛЖНО существовать, поскольку именно таким образом StaticFileHandler будет запущен в первую очередь.

Если я в конечном итоге это сделаю, я напишу сообщение в блоге и поделюсь ссылкой здесь.

ОБНОВЛЕНИЕ: Реализовал это, как я упоминал, хотя в итоге это был пользовательский HttpHandler вместо расширения StaticFileHandler: http://www.prosoftnearshore.com/2011/10/localizing-files-jpg-css-js-etc-in-asp-net

Комментарии:

1. Интересный подход. При этом отпадает необходимость определять резервный язык — по умолчанию используется исходное местоположение — и вам не нужно учитывать язык просмотра. Мне это нравится!

2. Ссылка не работает, и я, похоже, не могу найти ее, выполнив поиск. Есть шанс, что ваш пост все еще в Сети?

3. @NightOwl888 только что обновил сообщение с помощью URL. Извините за задержку.