Introduction
This article shows a simple solution for localization of static files such as HTML, XML, JavaScript, or CSS, using the standard ASP.NET global resources. I was looking for a technique that will allow me to use the <%$ Resources:Resfile, KeyName %>
syntax in all kinds of files. I also wanted all the resources to be concentrated into a single file in order to avoid duplicate entries and to simplify the translation process.
Required Knowledge
I assume that the readers are familiar with:
- ASP.NET global resources
- ASP.NET caching
- .NET HTTP Handlers
- Regular Expressions
How it Works
The idea is simple - static files that need to be localized will be served by a special HTTP Handler. The handler will read the static files and replace all resource keys by their values as specified in your .resource file. The parsed files will be stored in the ASP.NET cache and updated every time you change them.
Consider the following HTML code:
<html dir="<%$ Resources:Resource, direction %>">
<body>
<h1><%$ Resources:Resource, title %></h1>
</body>
</html>
In this example, the HTTP Handler will replace the direction
and title
resources by their values from the Resource.resources file.
At this point, I suggest downloading the enclosed sources and examining the code in LocalizationManager\LocalizationHandler.cs.
The Code
All the important code is located in the ProcessRequest
method, and the workflow is very simple:
- Check whether the requested file already exists in the cache.
- If not, read the file (HTML, JS, CSS, XML etc.)
- Create the
ResourceManager
for the required resource file if it isn't created yet. - Replace all resource keys by their values.
- Store the result in the cache depending on the input file.
- Return the result.
public void ProcessRequest(HttpContext context)
{
if (m_appPath == null)
m_appPath = context.Server.MapPath(".");
string filePath = context.Request.Url.LocalPath;
string fileId = filePath + "." + Thread.CurrentThread.CurrentCulture.Name;
string buffer = (string)context.Cache.Get(fileId);
HttpResponse response = context.Response;
response.ContentType = GetContentType(filePath);
if (buffer == null)
{
string fullPath = context.Server.MapPath(filePath);
buffer = ReadFile(fullPath);
buffer = ParseBuffer(buffer, context);
CacheDependency dependency = new CacheDependency(fullPath);
context.Cache.Insert(fileId, buffer, dependency);
}
response.Write(buffer);
}
Configuration
You will need to configure your web application as follows:
Step 1 - Configure IIS
In the IIS console, open the properties of your web application and click on the Configure button. Under Mappings, add a new one that maps your static files (e.g., ".html", ".js", ".css" etc.) to the ASP.NET ISAPI engine (usually c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll).
Note: On Windows XP, you will probably notice this very annoying bug - in order to enable the OK button, you will need to enter the file extension with a preceding dot (like this: ".js") and click on the Executable edit box to expand the path (eliminating the ellipsis).
Step 2 - Configure the HTTP Handler
In your web.config file, add your HTTP handler:
<system.web>
<httpHandlers>
<add verb="*" path="*.js"
type="LocalizationManager.LocalizationHandler, LocalizationManager"/>
<add verb="*" path="*.htm"
type="LocalizationManager.LocalizationHandler, LocalizationManager"/>
<add verb="*" path="*.css"
type="LocalizationManager.LocalizationHandler, LocalizationManager"/>
</httpHandlers>
...
Step 3 - Configure Globalization
Add the <globalization culture="auto" />
tag to your web.config file. This will ensure a correct value of Thread.CurrentThread.CurrentCulture
in all requests, including requests to static files. Otherwise, it will always be the default (e.g., en-US).
Step 4 - Copy the Handler
Make sure that LocalizationHandler.dll file is located under the Bin directory of your application.
That's it, now everything should work.
Further Development
There are several improvements I planned to do in the near future including automatic invalidation of all cached files when the resource file is changed. I will be more than happy to know if there are any other improvements that you would like to see in this tiny project.
Anton Bar has over 15 years of experience in software development, and over 10 years experience in building high-performance distributed software systems.
Anton is a long time contributor to MOSIX, a free distributed operating system based on Linux.
During the early 90’s, Anton founded start-up developing software for the optimization of networking over satellite lines, later acquired by ViaSat, Inc. Anton also served as CTO for CDIS, an enterprise content management company.
In the past years, Anton spoke and was well received at several conferences in US, Russia and Kazakhstan.
Anton holds a Masters degree in computer science from the Hebrew University of Jerusalem, Israel.