V .NET rozlišujeme lokalizaci a globalizaci:
- Lokalizace – Zobrazování textů v aplikaci v některém z jazyků (language), do kterého je aplikace přeložena. V .NET nám nastavený jazyk vrací vlastnost System.Globalization.CultureInfo.CurrentUICulture.
- Globalizace – Nastavení formátování čísel, data, času apod. podle zvyklostí daného národa (region) - kultury. V .NET nám nastavený jazyk vrací vlastnost System.Globalization.CultureInfo.CurrentCulture.
Tyto vlastnosti můžeme podle potřeby a scénáře buď přebírat z nastavení Windows nebo je nechat přímo v aplikaci zvolit uživatelem. Konkrétně v ASP.NET aplikacích můžeme celkem snadno dosáhnout toho, aby bylo toto nastavení převzato z preferencí prohlížeče, nastavením globalization ve web.config souboru:
<globalization requestEncoding="utf-8" responseEncoding="utf-8" culture="auto" uiCulture="auto" />
Pokud se pohybujeme v oblasti JavaScriptu a jQuery, existují sice některé řešení globalizace (jako například jQuery Globalization Plugin). Zdá se ale, že se zde tento model lokalizace vs. globalizace úplně vytrácí a neřeší se.
Pří zavádění jQuery UI DatePicker kontrolu do ASP.NET aplikace jsem si místo toho připravil vlastní jednoduchou třídu, která se stará o jeho inicializaci tak, aby respektovala .NET nastavení jak lokalizace CurrentUICulture tak i globalizace CurrentCulture.
Začneme HTML kódem DatePicker kontrolu. Do ASP.NET stránky umístíme klasický TextBox, kterému přidáme class datepicker (*):
<asp:TextBox ID="txtDatePicker" runat="server" CssClass="datepicker" />
Podle této třídy bude javascript (jQuery) hledat všechny kontroly, na které zavolá inicializační metodu datepicker z jQuery UI. Tento script bude právě záviset na nastavení lokalizace a globalizace, a proto ho budeme vytvářet C# třídou. Třídu jsem nazval JQueryHelper. Aby tento kód vracející script šel jednoduše (a čistě) vložit do ASP.NET Web forms stránky, umístíme ho do statické metody InitDatePicker vracející typ HtmlString (je to jakási obdoba helpers tříd v ASP.NET MVC).
using System;
namespace System.Web
{
/// <summary>
/// HTML jQuery helper
/// </summary>
public static class JQueryHelper
{
/// <summary>
/// Convert a .NET date format to jQuery
/// </summary>
public static string ConvertDateFormatToJQuery(string format)
{
// Date used in this comment : 5th - Nov - 2009 (Thursday)
//
// .NET JQueryUI Output Comment
// --------------------------------------------------------------
// d d 5 day of month(No leading zero)
// dd dd 05 day of month(two digit)
// ddd D Thu day short name
// dddd DD Thursday day long name
// M m 11 month of year(No leading zero)
// MM mm 11 month of year(two digit)
// MMM M Nov month name short
// MMMM MM November month name long.
// yy y 09 Year(two digit)
// yyyy yy 2009 Year(four digit)
string currentFormat = format;
//Convert the date
currentFormat = currentFormat.Replace("dddd", "DD");
currentFormat = currentFormat.Replace("ddd", "D");
//Convert month
if (currentFormat.Contains("MMMM"))
{
currentFormat = currentFormat.Replace("MMMM", "MM");
}
else if (currentFormat.Contains("MMM"))
{
currentFormat = currentFormat.Replace("MMM", "M");
}
else if (currentFormat.Contains("MM"))
{
currentFormat = currentFormat.Replace("MM", "mm");
}
else
{
currentFormat = currentFormat.Replace("M", "m");
}
//Convert year
currentFormat = currentFormat.Contains("yyyy") ? currentFormat.Replace("yyyy", "yy") : currentFormat.Replace("yy", "y");
return currentFormat;
}
/// <summary>
/// Returns script to init jQuery DatePicker with localization
/// </summary>
public static IHtmlString InitDatePicker()
{
//Using CSS class 'datepicker' to identify DatePicker controls
string dateformat = ConvertDateFormatToJQuery(System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern);
string html = @"<script type=""text/javascript"">
jQuery(function ($) {
if ($.isFunction($('.datepicker').datepicker)) {
$('.datepicker').datepicker({
showOtherMonths: true,
selectOtherMonths: true,
dateFormat: '" + dateformat + @"'
});
$.datepicker.setDefaults($.datepicker.regional['']); //Restore the default for Localization Fallback
$.datepicker.setDefaults($.datepicker.regional['" + System.Globalization.CultureInfo.CurrentUICulture.TwoLetterISOLanguageName + @"']);
}
});
</script>";
return new HtmlString(html);
}
}
}
Ve scriptu ve volání inicializace metodou datepicker nastavuji patřičný dateformat. Ten je získán pomocnou C# metodou ConvertDateFormatToJQuery odvozený právě z CurrentCulture (konkrétně CurrentCulture.DateTimeFormat.ShortDatePattern). Dále se pomoci setDefaults nastavují lokalizační hodnoty DataPicker kontrolu pomoci hodnot pole regional. Nejprve se nastaví výchozí lokalizace (pro fallback) a poté teprve ten požadovaný podle CurrentUICulture TwoLetterISOLanguageName.
Všimněte si ještě, že třída je umístěna přímo v namespace System.Web, to nám umožní snadné volání přímo na aspx stránce (typicky master page), které může vypadat například takto:
<!DOCTYPE html>
<html lang="cs">
<head runat="server">
...
<webopt:BundleReference runat="server" Path="~/Content/themes/base/css" />
</head>
<body>
<form id="form" runat="server">
<asp:ScriptManager runat="server" AjaxFrameworkMode="Enabled" EnableCdn="true">
<Scripts>
...
<asp:ScriptReference Name="jquery" />
<asp:ScriptReference Name="jquery.ui.combined" />
</Scripts>
</asp:ScriptManager>
<%: Scripts.Render("~/bundles/AppJs") %>
<%: JQueryHelper.InitDatePicker() %>
...
</form>
</body>
</html>
Ve stránce také nesmíme zapomenout inicializovat jQuery UI a CSS pro jeho theme (já zde používám Bundling & minification, o kterém jsme si něco pověděli například zde a zde).
Aby nám uvedené řešení fungovalo, chybí nám poslední část skládačky. Tou je sada lokalizačních scriptů pro DataPicker. Takový script například pro češtinu vypadá takto:
/* Czech initialisation for the jQuery UI date picker plugin. */
jQuery(function($){
$.datepicker.regional['cs'] = {
closeText: 'Zavřít',
prevText: 'Předchozí',
nextText: 'Další',
currentText: 'Dnes',
monthNames: ['Leden', 'Únor', 'Březen', 'Duben', 'Květen', 'Červen', 'Červenec', 'Srpen', 'Září', 'Říjen', 'Listopad', 'Prosinec'],
monthNamesShort: ['Led', 'Úno', 'Bře', 'Dub', 'Kvě', 'Čer', 'Čvc', 'Srp', 'Zář', 'Říj', 'Lis', 'Pro'],
dayNames: ['Neděle', 'Pondělí', 'Úterý', 'Středa', 'Čtvrtek', 'Pátek', 'Sobota'],
dayNamesShort: ['Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So', ],
dayNamesMin: ['Ne', 'Po', 'Út', 'St', 'Čt', 'Pá', 'So'],
weekHeader: 'Týd',
dateFormat: 'dd.mm.yy',
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: ''};
$.datepicker.setDefaults($.datepicker.regional['cs']);
});
Zde je vidět inicializace hodnoty datepicker.regional['cs'] pole regional, kterou pro daný jazyk právě nastavujeme. Tyto lokalizační scripty jsou při stažení jQuery UI k dispozici v podadresáři development-bundle\ui\i18n, a to buď samostatně (jmenují se jquery.ui.datepicker-xx.js), nebo jako jeden spojený script (jquery-ui-i18n.js). Druhou možností je tento script stáhnout a nainstalovat pomoci NuGet balíčku PM> Install-Package jQuery.UI.i18n.
Já jsem potřebné lokalizační scripty umístil do adresáře Scripts\Cultures a zahrnul do bundlu aplikačních scriptů:
bundles.Add(new ScriptBundle("~/bundles/AppJs").Include(
"~/Scripts/App/*.js",
"~/Scripts/Cultures/*.js"));
Tím je DatePicker kontrol funkční, ještě můžeme v CSS stylu upravit velikost prvku a font kalendáře:
.datepicker {
width: 95px !important;
}
.ui-datepicker {
font-size: 0.8em !important;
}
(*) Druhou variantou než použit CSS class datepicker na rozlišení kontrolů pro DatePicker je použít nový HTML5 input typ date (nebo datetime) (více zde nebo zde): <input type="date" >
Poté provést kontrolu, zda není DatePicker podporován nativně (pomoci Modernizr) a prvek vyhledat selektorem podle typu date:
//Setup datepickers if we don't support it natively!
if (!Modernizr.inputtypes.date) {
if ($.isFunction($("input[type='date']").datepicker)) {
$("input[type='date']").datepicker(...);
...
}
}
V dnešní době jsou ale tyto HTML5 typy snad kromě emailu stále většinou browserů nepodporované. Podporuje je co vím pouze Chrome a Opera, ani IE11 je stále nepodporuje (přijde vám také jako mě, že IE 11 vůbec nic nového nepřináší ). S ohledem na tuto skutečnost dávám radši přednost zachování větší kompatibility a používám zatím variantu s CSS třídou datepicker.