Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
В статьях Локализация чисел decimal и Локализация дат в ASP.NET MVC была рассмотрена статическая локализация, когда приложение делается под определенную культуру со всеми ее особенностями (запятая или точка в качестве разделителя, определенный формат даты). Однако если у нас веб-приложение расчитано на несколько языков или культур, такая ситуация может оказаться нежелательной. Например, пользователю из США будет привычнее использовать в качестве разделителя точку и формат даты месяц/день/год, а пользователь из Германии, наоборот, использует формат день/месяц/год и запятую в качестве разделителя. Поэтому рассмотрим, как менять динамически настройки локализации в зависимости от выбранной пользователем культуры.
Сначала создадим в проекте инфраструктуру для переключения языка. Подробно данный момент описан в статье Логика мультиязычного сайта. Фильтр локализации. Для этого определим добавим в файл Global.asax, обработчик события BeginRequest, который будет переключать текущую культуру приложения:
using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; using System.Web; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; namespace LocalApp { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } protected void Application_BeginRequest() { string cultureName = null; // Получаем куки из контекста, которые могут содержать установленную культуру HttpCookie cultureCookie = HttpContext.Current.Request.Cookies["lang"]; if (cultureCookie != null) cultureName = cultureCookie.Value; else cultureName = "ru"; // Список культур List<string> cultures = new List<string>() { "ru", "en", "de" }; if (!cultures.Contains(cultureName)) { cultureName = "ru"; } Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureName); Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(cultureName); } } }
Обработчик Application_BeginRequest вызывается в начале жизненного цикла запроса. В нем который получаем установленную культуру из куков. Затем мы смотрим, есть ли такая культура в списке. Если культуры нет, то используем рускоязычную культуру по умолчанию.
Далее в контроллере создадим метод, который будет сохранять выбранную пользователем культуру в куки
public class HomeController : Controller { public ActionResult ChangeCulture(string lang) { string returnUrl = Request.UrlReferrer.AbsolutePath; List<string> cultures = new List<string>() { "ru", "en"}; if (!cultures.Contains(lang)) { lang = "ru"; } // Сохраняем выбранную культуру в куки HttpCookie cookie = Request.Cookies["lang"]; if (cookie != null) cookie.Value = lang; // если куки уже установлено, то обновляем значение else { cookie = new HttpCookie("lang"); cookie.HttpOnly = false; cookie.Value = lang; cookie.Expires = DateTime.Now.AddYears(1); } Response.Cookies.Add(cookie); return Redirect(returnUrl); } }
В файле _Layout.cshtml определим переключение языка:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title> @Styles.Render("~/Content/css") @Scripts.Render("~/bundles/modernizr") </head> <body> <div> @using (Html.BeginForm("ChangeCulture", "Home")) { <select name="lang"> <option disabled selected>Выберите язык</option> <option value="ru">Русский</option> <option value="en">English</option> </select> <input type="submit" name="submit" value="Изменить"> } </div> @RenderBody() @Scripts.Render("~/bundles/jquery") @RenderSection("scripts", required: false) </body> </html>
С помощью выпадающего списка переключаем культуру. В данном случае опустим локализацию названий полей с помощью ресурсов.
Теперь добавим в проект модель User:
public class User { public int Id { get; set; } [Display(Name = "Имя")] public string Name { get; set; } [DataType(DataType.Date)] [Display(Name = "Дата рождения")] public DateTime Date { get; set; } }
Также добавим в контроллер действие Create, которое будет получать введенные пользователем данные:
public ActionResult Create() { return View(); } [HttpPost] public ActionResult Create(User user) { if (ModelState.IsValid) { return Content(user.Date.ToLongDateString()); } return View(user); }
В post-методе будем получать модель и в случае успешной валидации выводить введенную дату рождения.
Теперь самое главное - определим представление для создания модели, причем нам надо учесть возможность выбора одного из двух форматов дат в соответствии с заданной культурой. Фактически нам надо два набора настроек для виджета datepicker, который позволит установить дату: для русскоязычной и для англоязычной культры. Для упрощения работы вынесем настройки в отдельный файлы javascript.
Добавим в папку Scripts файл datepicker.en.js со следующим содержимым:
$(function () { $("input[type='date']") .datepicker({ dateFormat: 'm/d/yy' }) .get(0).setAttribute("type", "text"); });
Для англоязычной культуры используется формат 'm/d/yy'.
Также добавим в папку Scripts файл datepicker.ru.js:
$(function () { $("input[type='date']") .datepicker({ dateFormat: 'dd/mm/yy' }) .get(0).setAttribute("type", "text"); $.datepicker.regional['ru'] = { prevText: 'Пред', nextText: 'След', monthNames: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'], monthNamesShort: ['Янв', 'Фев', 'Мар', 'Апр', 'Май', 'Июн', 'Июл', 'Авг', 'Сен', 'Окт', 'Ноя', 'Дек'], dayNames: ['воскресенье', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота'], dayNamesShort: ['вск', 'пнд', 'втр', 'срд', 'чтв', 'птн', 'сбт'], dayNamesMin: ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'], weekHeader: 'Не', dateFormat: 'dd/mm/yy', firstDay: 1, isRTL: false, showMonthAfterYear: false, yearSuffix: '' }; $.datepicker.setDefaults($.datepicker.regional['ru']); $.validator.addMethod('date', function (value, element) { var ok = true; try { $.datepicker.parseDate('dd/mm/yy', value); } catch (err) { ok = false; } return ok; }); });
Здесь уже другой формат "dd/mm/yy" плюс куча дополнительный настроек.
И определим представление Create.cshtml:
@model LocalApp.Models.User @{ ViewBag.Title = "Create"; } @using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>Новый пользователь</h4> <hr /> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) <div class="form-group"> @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Date, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Date, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Date, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Create" class="btn btn-default" /> </div> </div> </div> } @section Scripts { @Scripts.Render("~/bundles/jqueryval") <!--подключаем стили jquery-ui--> <link href='@Url.Content("~/Content/themes/base/all.css")' rel="stylesheet" type="text/css" /> <!--подключаем скрипт jquery-ui--> <script src='@Url.Content("~/Scripts/jquery-ui-1.11.4.min.js")' type="text/javascript"></script> @if (System.Threading.Thread.CurrentThread.CurrentCulture.Name == "ru-RU") { <script src='@Url.Content("~/Scripts/datepicker.ru.js")' type="text/javascript"></script> } else { <script src='@Url.Content("~/Scripts/datepicker.en.js")' type="text/javascript"></script> } }
С помощью свойства System.Threading.Thread.CurrentThread.CurrentCulture мы можем получить текущую культуру и в зависимости от ее значения подключить тот или иной скрипт.
Выберем русскоязычную культуру и введем дату:
При получении данных модель будет успешно валидирована в контроллере, и браузер выведет дату в соответствии с культурой:
Теперь изменим культуру на англоязычную и соответветственно используем другой формат даты:
И также валидация модели пройдет успешно :