Lokalisierung mit Cultures
Um ein .Net Webprojekt zu lokalisieren, wurden bis anhin bei uns sämtliche Elemente in separaten Strings übersetzt gehalten und zur Laufzeit mittels Select/Case (abhängig von der ausgewählten Sprache) ausgelesen und den Objekten zugeordnet. Ein Relikt aus alten Projekten..
Dass dies auch eleganter geht, zeigt das folgende Beispiel. Nachdem eine .aspx Seite aufgebaut wurde (inkl. Code-behind File), kann in Visual Studio 2005 unter „Tools“ der Punkt „Generate Local Resource“ ausgewählt werden. Es wird automatisch im Projekt ein Ordner App_LocalResources angelegt mit dem Namen der Webform und dem Zusatz .apsx.resx. In dem File finden sich sämtliche verwendeten Elemente der .aspx Seite wieder, zu jedem Element existiert ein String mit dem angezeigten Text. Die Liste kann manuell beliebig erweitert werden, falls neue Buttons oder was auch immer zur Seite hinzugefügt werden. Nun kann das .resx File kopiert und umbenannt werden, beispielsweise „Default.aspx.de-CH.resx“ oder „Default.aspx.en-US.resx“. Der Filenamen enthält nun bereits die Sprachspezifikation. Die einzelnen Strings in den Files können bequem übersetzt werden, Visual Studio stellt dafür einen kleinen Editor zur Verfügung.
Zur Laufzeit kann nun innerhalb der Webform „CurrentCulture“ und „CurrentUICulture“ gesetzt werden, aufgrund dieser Auswahl wird das entsprechende .resx File eingelesen und die Strings automatisch auf die Objekte gemappt. Natürlich können die Strings aber auch manuell ausgelesen werden. Hier ein Codesample:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Threading;
using System.Globalization;
public partial class _Default : System.Web.UI.Page
{
// Methode um manuell ein ResouceObject auszulesen
public string G(string sKey)
{
return GetLocalResourceObject(sKey).ToString(); ;
}
// Init
protected override void InitializeCulture()
{
base.InitializeCulture();
string selectedLanguage = "de-CH";//""en-US";
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(selectedLanguage);
Thread.CurrentThread.CurrentUICulture = new CultureInfo(selectedLanguage);
}
// Einem ASP Button einen String manuell zuweisen
protected void Page_Load(object sender, EventArgs e)
{
Button1.Text = G("Button1Resource1.Text");
}
}
Parameter an Telerik DockableObject Form mit Reflection übergeben
Eine kleine Knacknuss hat sich bei der Verwendung der Telerik Docking Zones (DZ) rsp. Dockable Objects (DO) ergeben. Folgende Situation: drei DZ liegen nebeneinander, alle werden dynamisch mit DO gefüllt. Als ContentTemplate wird für jedes DO ein eigenes Control definiert, welches nach dem Aufklappen des DO eine umfangreiche Editmaske zur Verfügung stellt. Soweit so gut, bloss muss dem Control innerhalb des DO ein Parameter übergeben werden, damit dort die ID des DO zur Verfügung steht. Alles klar?
Der erste Versuch nur über ein Property war nicht von Erfolg gekrönt. Die Lösung heisst: Reflection! Hier ein Vorschlag, wie die Create Methode aussehen könnte:
Function CreateDockableObject(ByVal _Id As Integer, ByVal _Text As String) As RadDockableObject
'create new dockable object
Dim dObj As New RadDockableObject
dObj.ID = _Id
dObj.Text = _Text
dObj.DockingMode = RadDockingModeFlags.AlwaysDock
dObj.Expanded = False
dObj.Width = "250"
'load a user control as a template
Dim myUC As UserControl
myUC = CType(LoadControl("Controls/ModulEdit.ascx"), UserControl)
Dim ucType As Type = myUC.GetType()
'pass a parameter to the user control
Dim ucProperty As Reflection.PropertyInfo = ucType.GetProperty("mId")
ucProperty.SetValue(myUC, _Id, Nothing)
'add user control to dockable object template
dObj.ContentTemplate = myUC
Return dObj
End Function
Natürlich muss im Control ein entsprechendes Property (hier „mId“) vorhanden sein. Ist dies der Fall, funktioniert alles bestens!
Arbeiten mit Verzeichnissen in vb.net
Zu internen Zwecken musste ich ein kleines Tool schreiben, welches diverse Verzeichnisse abgleicht und ein paar Fileoperationen ausführt. Dafür gibt’s in .net eine praktische Lösung! Mit dem folgenden Code kann für jede Datei in einem Verzeichnis eine Aktion ausgeführt werden.
Imports System.IO Imports System.Data Partial Public Class _Default Inherits System.Web.UI.Page Dim SourcePath As String = "C:\Test\TestSource" Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load Dim di As New DirectoryInfo(SourcePath) For Each fi As FileInfo In di.GetFiles Dim mySourceFilename As String = fi.Name 'do something Next End Sub
Fortune Cookie Codes mit .net
Für einen Kunden sollten wir einen Glückscode-Generator schreiben. Die Anforderungen waren relativ simpel: Codes im Format xxxx-xxxx-xxxx, natürlich absolut unique Codes, performant auch bei der Erzeugung von mehreren 100′000 Codes im Zusammenspiel mit einer MS SQL Datenbank.Zur Erzeugung der Codes verwendeten wir die .net GUID (globally unique identifier) Funktion, die diese Arbeit recht hübsch erledigt. In einer For-Next Schlaufe werden die Codes generiert, transformiert und in eine Datatable geschrieben. Die Funktion DeleteDuplicates erstellt einen DataView, sortiert diesen nach Codes und arbeitet sich top-down. Sind zwei aufeinanderfolgende Codes identisch, wird der aktuelle gelöscht. Fertig ist die Geschichte, das Ganze wird in diesem Beispiel in ein XML File gespeichert.Werden die Codes in eine SQL Db gespeichert, kann die Einzigartigkeit zusätzlich überprüft werden mit einer DISTINCT Abfrage.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click ‘number of codes to generate Dim EndCount As Integer = 5000 ‘create the datatable and add a row objDT = New System.Data.DataTable(”CodeTable”) objDT.Columns.Add(”Code”, GetType(String)) ‘create random id, transform code Dim count As Integer For count = 0 To EndCount - 1 ‘edit the string Dim myCode As String = Guid.NewGuid.ToString ‘add some separators and cut the string down on 15 chars (3 x 4chars + 3x 1 separator) myCode = UCase(myCode.Replace(”-”, “”)) myCode = myCode.Insert(4, “-”) myCode = myCode.Insert(9, “-”) myCode = myCode.Substring(0, 14) ‘add to datatable objDR = objDT.NewRow objDR(”Code”) = myCode.ToString objDT.Rows.Add(objDR) Next ’start the sub DeleteDuplicates(objDT) ‘Serialize the datatable object into a xml file objDT.WriteXml(”final_codes.xml”) objDT.WriteXmlSchema(”final_scheme.xslt”) ‘output the number of generated codes lblNumRows.Text = objDT.Rows.Count & ” Codes generiert” End Sub ‘Selects duplicate entries and removes them Public Sub DeleteDuplicates(ByVal dt As DataTable) Dim myDataView As New DataView(dt) myDataView.Sort = “Code” For x As Integer = 0 To myDataView.Count - 2 Dim myDataRowView As DataRowView = myDataView.Item(x) Dim myDataRowViewNext As DataRowView = myDataView.Item(x + 1) If myDataRowView.Item(”Code”).ToString = myDataRowViewNext.Item(”Code”).ToString Then myDataRowView.Delete() End If Next End Sub End Class