ASP.NET 2.0 offers 'out-of-the-box' localization. It uses resource-files (xml). It is possible to use a database instead (see the article of Michèle Leroux Bustamante, mentioned below the blog). A few days earlier I looked a bit to adapters so I got the crazy idea to add those two pieces together. My prime-directive was:
Make code localized with as less changes in the (existing) source as possible. UPLOADTEMPLATE
We start with a simple page with two controls: a dropdownlist with the languages and a label.
The languages are Nederlands, English and Deutsch. The text we want to show on the label is a simple 'Hello'.
So really nothing special. Since we don't want to change a lot of code I choose not to create my own label-control, but instead use an adapter to 'overwrite' the standard functionality.
To do this I create a browserfile:
Code:<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.WebControls.Label"
adapterType="Arcencus.LabelAdapter" />
</controlAdapters>
</browser>
<browser id="W3C_Validator" parentID="default">
<identification>
<userAgent match="^W3C_Validator" />
</identification>
<capabilities>
<capability name="browser" value="W3C Validator" />
<capability name="ecmaScriptVersion" value="1.2" />
<capability name="javascript" value="true" />
<capability name="supportsCss" value="true" />
<capability name="supportsCallback" value="true" />
<capability name="tables" value="true" />
<capability name="tagWriter" value="System.Web.UI.HtmlTextWriter" />
<capability name="w3cdomversion" value="1.0" />
</capabilities>
</browser>
</browsers>
In the browserfile we state when using the control 'System.Web.UI.WebControls.Label' we want to use the adapter 'Arcencus.LabelAdapter'.
Next step is to create the adapter. For this we need to create a file in the App_Code map, a 'generic' adapter which inherits from System.Web.UI.Adapters.ControlAdapter. This is our LabelAdapter. Since we don't have to worry about databinding (it's a label) the only thing to do is overriding the render-method. We use one extra function to retreive the actual text to show from a database.
The whole code for the adapter is:
Code:Imports System
Imports System.Data
Imports System.Configuration
Imports System.IO
Imports System.Web
Imports System.Web.Security
Imports System.Web.UI
Imports System.Web.UI.WebControls
Namespace Arcencus
Public Class LabelAdapter
Inherits System.Web.UI.Adapters.ControlAdapter
Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
If TypeOf Control Is Label Then
Dim lb As Label = CType(Control, Label)
If (Not String.IsNullOrEmpty(lb.Text)) Then
Dim term As String = GetTerm(lb.Text, HttpContext.Current.Session("Culture"))
If String.IsNullOrEmpty(term) Then
MyBase.Render(writer)
Else
writer.Write(term)
End If
End If
Else
MyBase.Render(writer)
End If
End Sub
Private Function GetTerm(ByVal Text As String, ByVal Culture As String) As String
Dim sconn As New SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings("GlobalizationConnectionString").ConnectionString)
Dim scomm As New SqlClient.SqlCommand("SELECT TOP 1 Text FROM Terms WHERE Value = @Value AND Culture = @Culture", sconn)
With scomm.Parameters
.AddWithValue("@Value", Text)
.AddWithValue("@Culture", Culture)
End With
Dim _result As String
sconn.Open()
_result = scomm.ExecuteScalar
sconn.Close()
Return _result
End Function
End Class
End Namespace
First we check if the control is really a label. Then we check if the text-property of the label is filled. If so, we retreive the translation, based on this text and the culture (see below). If it isn't found, we simply render the original text. If found, we write the translation. If the control wasn't a label, call the original render-method.
So without changing the aspx it is now localizable
Ok, the culture. In this sample I let the user choose, so no Culture or UICulture settings are used (which obviously is also possible).
When the dropdownlist is used I simply change a session-variable, that's all. And with load off the dropdownlist I also set the session-variable (for init-phase).
The code:
Code:Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles DropDownList1.SelectedIndexChanged, DropDownList1.Load
Session("Culture") = DropDownList1.SelectedValue
End Sub
End Class
Ofcourse there are many ways to enhance this code. The use of the original text as key to find a translation is at least doubtfull but hey, it's just a prototype 
Have fun with this code and don't forget to update me when you use and enhance the code!
Ferry
P.S. The VS.NET 2005 code is attached to this post. In the solution you will also find a SQL-script to create the used db + data.Bijlagen:
Globalization.rar 5 KB