Introduction
In this article, I'm going to explain how you can build a world-ready web application and how you can use JavaScript and XSLT with the globalization goal in mind.
This article uses the .NET Framework 1.1.
What is Globalization?
Globalization is the process of developing a program core whose features and code design are not solely based on a single language or locale. Instead, their design is developed for the input, display, and output of a defined set of Unicode-supported language scripts and data related to specific locales.
Globalization in .NET
The .NET Framework has three namespaces to help you develop world-ready applications: System.Threading
, System.Globalization
, and System.Resources
.
System.Threading
includes a very known class called Thread
. The Thread
class has a property called CurrentCulture
that you can use to get/set the current culture of the thread.
The System.Globalization
namespace contains classes that define culture-related information, including the language, the country/region, the calendars in use, the format patterns for dates, currency, and numbers, and the sort order for strings. These classes are useful for writing globalized (internationalized) applications.
The System.Resources
namespace provides classes and interfaces that allow developers to create, store, and manage various culture-specific resources used in an application. One of the most important classes of the System.Resources
namespace is the ResourceManager
class.
Using resources files and the ResourceManager class
Resources files are XML documents that have all the resources for a specific culture. The ResourceManager
class provides convenient access to culture-specific resources at runtime.
Retrieving a value stored in a resource file is as simple as invoking the GetString
method of the ResourceManager
.
protected System.Web.UI.HtmlControls.HtmlAnchor LinkDetalhes;
protected System.Web.UI.WebControls.Label TituloIndex;
private void Page_Load(object sender, System.EventArgs e)
{
ResourceManager rm = new ResourceManager("sample",
Assembly.GetExecutingAssembly());
CultureInfo ci = Thread.CurrentThread.CurrentCulture;
TituloIndex.Text = rm.GetString(TituloIndex.ID, ci);
LinkDetalhes.InnerText = rm.GetString(LinkDetalhes.ID, ci);
}
Globalized JavaScript
Now, it would be great if we could call the GetString
method in our JavaScript code. Since, we can't do that, we have to somehow inject the resource file contents into the HTML using hidden inputs. Then, it would be possible to get the values stored in those hidden inputs by calling document.getElementById
.
Injecting the resource file content into the HTML
The first thing we have to do is to get the resource file contents. The ResourceManager
has a method called GetResourceSet
that obtains a ResourceSet
that represents the resources localized for the specified culture.
Then, we must find the form control of our page and start creating hidden inputs with the ID and the value of the resources.
protected void AddResourceSetToHtml()
{
HtmlForm theForm = null;
for(int i=0;i!=this.Page.Controls.Count;++i)
{
theForm = Page.Controls[i] as HtmlForm;
if(theForm!=null)
break;
}
if(theForm==null)
return;
ResourceSet rs = rm.GetResourceSet(ci, true, true);
IDictionaryEnumerator de = rs.GetEnumerator();
while(de.MoveNext())
{
HtmlInputHidden ih = new HtmlInputHidden();
string key = de.Key as String;
string val = de.Value as String;
if(key!=null && val!=null)
{
ih.ID = "res"+key;
ih.Value = val;
theForm.Controls.Add(ih);
}
}
rs.Close();
}
Since the IDs of my controls is equal to the IDs of the resources stored in the resource file, when I'm creating hidden inputs, I have to add something to the ID. If I don't do that, the result would be two controls with the same ID. If the ID stored in the resource file isn't the same as the ID of the control, it wouldn't be necessary.
The globalized JavaScript code would look like this:
<script language="javascript" type="text/javascript">
var btnAlert;
function load()
{
btnAlert = document.getElementById("btnAlert");
btnAlert.value = document.getElementById("resBtnAlertTitulo").value;
}
function btnAlertClick()
{
alert(document.getElementById("resBtnAlertMsg").value);
}
</script>
Globalized XSLTs
To achieve a globalized XSL transform, we follow the same approach as we did to achieve a globalized JavaScript code. We must inject the XML of the resource file into the input XML of the XSLT.
The XML of a resource file has the following format:
The RSS header has some information about the resource type. The element we're interested in is the data
element. The data
element represents an entry in the resource file. Just like an entry in a Dictionary, you'll find a pair: name and value. The name is an attribute and the value is an element.
Let's look at a sample XSLT that uses this approach:
<xsl:template match="/">
<table border="1">
<tr>
<th colspan="2">Globalization + XSL</th>
</tr>
<xsl:apply-templates select="root/data"/>
</table>
</xsl:template>
<xsl:template match="data">
<tr>
<td><xsl:value-of select="@name"/></td>
<td><xsl:value-of select="value"/></td>
</tr>
</xsl:template>
Conclusion
In this article, I've shown a possible way to achieve globalized JavaScript and XSLT code. The basic idea to achieve this is injecting the XML of the resource file for the specified culture into the HTML so the JavaScript code could reference it, or into the input XML of the XSLT.
As always, comments/sugestions are welcome!
Thank you.