ASP.NET MVC I18n – Teil 9: Fremde Controls

27. Februar 2014

Die meisten Web-Anwendungen nutzen komplexere Controls für Listendarstellungen, Menüs, etc.. Und in aller Regel müssen auch diese Controls bei der Lokalisierung berücksichtigt werden. Glücklicherweise sind mittlerweile die meisten Controls dazu zumindest grundsätzlich in der Lage; zumindest kommerzielle Anbieter können es sich kaum leisten, diese Anforderung zu ignorieren, siehe z.B. Telerik.

Andererseits (und nicht unerwartet) hat natürlich jede Bibliothek ihren eigenen Ansatz für Globalisierung…

Hinweis: Dieser Beitrag ist Teil einer Serie, die Übersicht findet sich hier.

 

Um ein besseres Gefühl für die Lokalisierung solcher Controls zu bekommen schauen wir uns das jQuery UI DatePicker Control an – das kanonische Beispiel für zusätzliche Controls.

Den DatePicker zu nutzen ist vergleichsweise einfach: Ein typisches MVC-Projekt enthält bereits die notwendigen Dateien, Bundles sind ebenfalls definiert und müssen nur noch in der _layout.cshtml ergänzt werden. Ein kleines Initialisierungsskript (datepicker.initialize.js) baut uns Textboxen in DatePicker um:

   1: $(document).ready(function () {

   2:     $("input[type='date']").datepicker();

   3: });

Dieses Script muss in die Views aufgenommen werden, was man am einfachsten bewerkstelligt, indem man es in das Bundle aufnimmt, das auch für den DatePicker zuständig ist:

   1: var bundle = bundles.GetBundleFor("~/bundles/jqueryui"); 

   2: bundle.Include("~/Scripts/datepicker.initialize.js"); 

Und das Resultat ist wie erwartet…

Lokalisierung-9-app1

… mit amerikanischer Lokalisierung.

 

Lokalisierung

Um den DatePicker auch für deutsches Format fit zu machen, braucht man entsprechende Lokalisierungsdateien. Entweder bekommt man die alle in einer Datei über das nuget Paket jQuery.UI.i18n, oder man holt sich gezielt die Lokalisierungen, die man benötigt von github.

Auch diese Script-Dateien lädt man am einfachsten, indem man sie in das Bundle aufnimmt:

   1: var bundle = bundles.GetBundleFor("~/bundles/jqueryui");

   2: bundle.Include(

   3:     "~/Scripts/jquery-ui-i18n.js",          // option 1: from nuget package 

   4:     //"~/Scripts/jquery.ui.datepicker-*",   // option 2: single localization files

   5:     "~/Scripts/datepicker.initialize.js");

Diese Script-Dateien stellen nicht nur die Lokalisierungen bereit, sie schalten auch auf die jeweilige Lokalisierung um. Wer also das nuget Paket verwendet hat, dem wird das chinesisch (zh-TW) vorkommen:

Lokalisierung-9-app2

Wer einzelne Dateien aus github geladen hat, der könnte das noch lösen, indem er gezielt nur die benötigte Lokalisierung lädt. Man kann sich aber auch von den Dateien lösen und das ganze in dem bereits vorhandenen Initialisierungsskript ergänzen:

   1: $(document).ready(function () {

   2:  

   3:     var lang = $(„html“).attr(„lang“); 

   4:     $.datepicker.setDefaults($.datepicker.regional[lang]); 

   5:  

   6:     $("input[type='date']").datepicker();

   7: });

Über das lang Attribut haben wird das auch für Globalize getan, das müsste also funktionieren, richtig?

Leider falsch. Für den DatePicker gibt es normalerweise Lokalisierungen für die Sprache (also de oder en), für die Region aber nur dann, wenn diese von der Sprache abweicht. Z.b. gibt es eine Lokalisierung für en-GB aber eben nicht für en-US und auch nicht für de-DE, weil dort en und de ausreichend sind.

Dazu kommt die “kleine Unschönheit”, dass der DatePicker kein Fallback auf die Sprache macht. Wenn man also eine Region setzt, die er nicht kennt, insbesondere de-DE, dann nimmt er nicht etwa de, sondern ignoriert den Aufruf und es bleibt bei der zuletzt geladenen Lokalisierung – also wieder chinesisch.

Dieses Verhalten wird leider nicht gesondert in der Doku erwähnt und gerne auch mal falsch gemacht.

Die Lösung ist eine Abbildung der von der Anwendung unterstützten Regionen auf die vom DatePicker unterstützten Lokalisierungen. Das könnte man auf dem Server tun, indem man einfach die passende Lokalisierungsdatei sucht (samt Berücksichtigung des Fallbacks) und das Resultat in einem zusätzlichen Attribut im HTML neben lang (etwa langDatePicker) bereitstellt.

Für lediglich zwei Regionen kann man das aber auch einfach im Script manuell machen:

   1: $(document).ready(function () { 

   2:     var lang = $("html").attr("lang"); 

   3:      

   4:     if (lang == "de-DE") 

   5:         $.datepicker.setDefaults($.datepicker.regional["de"]); 

   6:     else 

   7:         $.datepicker.setDefaults($.datepicker.regional[""]); // en-US is default 

   8:      

   9:     $("input[type='date']").datepicker(); 

  10: }); 

Und – endlich – zeigt sich der Kalender in korrekt lokalisiertem Gewand, d.h. übersetzte Texte, erster Tag der Woche, etc.:  

Lokalisierung-9-app3

 

Wertung

Es ist möglich den DatePicker vollständig in allen Aspekten zu lokalisieren – das ist schon mal die gute Nachricht. Es fällt aber auch auf, das es im Vergleich mit der Lokalisierung der Validierung einige Unterschiede gibt:

  • Während das nuget Paket für Lokalisierungen von Globalize einzelne Lokalisierungsdateien liefert, bekommt man beim Pendant für den DatePicker alle Lokalisierungen in einer Datei. (Das ist grundsätzlich erstmal nicht verwunderlich, da beide von unabhängigen Entwicklern, nicht dem jeweiligen Projekt, bereitgestellt werden.) Wenn man gezielt nur die benötigte Lokalisierung laden will, wird das dadurch natürlich erschwert.
  • Die Lokalisierungsdateien von Globalize registrieren die benötigte Information, aber sie wechseln die Region nicht. Die Pendants vom DatePicker hingegen tun das.
  • Globalize unterstützt einen Fallback auf die neutrale Kultur (Sprache), wenn die Region nicht verfügbar ist. Der DatePicker hingegen ignoriert den Aufruf.

Wenn man jetzt noch bedenkt, dass diese subtilen Unterschiede bei zwei Paketen aus dem jQuery-Umfeld auftreten, dann kann man sich ausmalen, was bei Bibliotheken von anderen Herstellern passiert. Hat man davon eine Handvoll im Projekt, kann das ein ziemliches Durcheinander werden.