Monday, November 14, 2011

Use ASP.NET Resource strings from within javascript files

It seems to be a common issue.

ASP.NET allows you to use resource files (*.resx) to localize content of pages (or views, if we are in context of ASP.NET MVC). All what you need is to put resource files under ~/App_GlobalResources folder and use either resource expression or  HttpContext.GetGlobalResourceObject() API to get a proper string. It is well documented on MSDN. The only issue - this API is not accessible within static resources such JavaScript files.


There are several solution already described by different people: Martin Normark's solution is generating static JavaScript resource files on post-build, Mads Kristensen suggest to localize text in JavaScript files by string replacing, and finally Rick Strahl introduce a localization handler to serve ASP.NET resources to JavaScript.

The last solution looks most elegant for me. Since I am working only with global resources I just simplified his solution and ended up with my own:

    public class JavaScriptResourceHandler : IHttpHandler
    {
 
        public void ProcessRequest(HttpContext context)
        {
            var requestedCulture = new CultureInfo(context.Request.QueryString["locale"]);
            var classKey = context.Request.QueryString["classKey"];
 
            var dictionary = ReadResources(classKey, requestedCulture);
 
            var javaScriptSerializer = new JavaScriptSerializer();
            var script =
                @"
if (typeof(Resources) == ""undefined"") Resources = {};
Resources." + classKey + " = " +
                javaScriptSerializer.Serialize(dictionary) + ";";
            
            context.Response.ContentType = "application/javascript";
 
            context.Response.Expires = 43200; // 30 days
            context.Response.Cache.SetLastModified(DateTime.UtcNow);
 
            context.Response.Write(script);
        }
 
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
 
        private static Dictionary<object ,object> ReadResources(string classKey,
                                                           CultureInfo requestedCulture )
        {
            var resourceManager = new ResourceManager("Resources." + classKey,
                                                Assembly.Load("App_GlobalResources"));
            using (var resourceSet = 
                resourceManager.GetResourceSet(CultureInfo.InvariantCulture, truetrue))
            {
 
                return resourceSet
                    .Cast<DictionaryEntry>()
                    .ToDictionary(x => x.Key,
                         x => resourceManager.GetObject((string)x.Key, requestedCulture));
            }
 
        }
    }
 

The demo project running this code might be found at Googe Code: http://code.google.com/p/izlabs/source/browse/#svn%2Ftrunk%2FJavaScriptResourceHandler

2 comments: