Monday, January 28, 2013

JavaScript Localization part 1


Going to do some posts on JavaScript localization in the context of .Net.

So as the web slowly drifts towards SPA style architecture (or even just unobtrusive JavaScript) the issue of JavaScript localization rears its ugly head. In the past people might have had the JavaScript in the page itself and they might have just used the same mechanism as the would normally use to replace strings, the resource ExpressionBuilder in .Net WebForms. But this technique doesn't work when you isolate your JavaScript into js files. The server typically just serves those files directly and doesn't process resource expressions. So what do you do for JavaScript localization?

First, some goals for a JavaScript localization system.
  1. I want all my localization to be in one format. I want to hand localizers one big file and not hand them one file for .Net and one for JavaScript. If there is a localized string it should be from essentially one source. This would allow reuse of resource strings that might otherwise be duplicated in various sources.
  1. It should be very easy for developers. They should touch at most two files and nothing complex should be involved.
  2. I only want to send the needed resources over the wire. This means I don't want to send every language my page could be in or every resource I might have in my system regardless of whether it is used client side.
  3. I want to support formatted strings since grammar may differ between languages.
  4. I don't want to incur any kind of significant processing requirements during normal usage. A request may trigger the creation of some file, but that file should be cached.
  5. It would be nice for this to be easy in terms of configuration and build management.

Okay, because of goals #1 to #3 I want something to run on the server that translates a resource requirement in a JavaScript file into a .Net resource from a resx file. So that brings up two questions:
  1. How will the resources get to the client? Embedded in the JavaScript or as a separate JavaScript file? Will there be a file marked with a language/culture identifier?
  1. When will the processing occur? During the build or dynamically when a request is made?

So my answer to the first question is that I would, in JavaScript, like to do something like Resources.Dotted.Resource.Name. That makes it act like it is accessing a JavaScript "namespace". But this can potentially have a negative performance consequences because you might be descending a long object hierarchy deep inside a loop. So how about Resources["Dotted.Resource.Name"]. Then we can have a JavaScript file that is created automatically that is like the following:

var Resources = {
"Resource.One" : "value";
"Resource.Two" : "another value";
}

This file can be referenced like FileName.en-US.js. This allows a JavaScript request to generally return the same thing every time as opposed to FileName.js sometimes returning English and sometimes Spanish. So the question becomes when will you do processing. Dynamically is more flexible, you just need to manage the caching and regenerating of the file. You just build a handler that will examine if files are modified and will compare file modification times. If it is out of date it will go through all the JavaScript files finding instances of Resources[].

Okay, so another issue is that  your markup code won't contain a hardcoded culture. So this brings up another question. How will you serve a culture specific file? One way is to have your JavaScript figure out culture and make the correct request. Another way is to have a request like FileName.js.axd that will be intercepted by a handler that will figure out the culture and serve the right file. This does mean that FileName.js.axd will return different things violating the principle of a request returning a specified resource, but in this case I think it is okay.

So now we have an approach. On the client will we assume we have loaded a Resources object. This gives us the option of changing what we are doing fairly easily. On the server we create a special handler that will dynamically generate a JavaScript file that has the right resources. It will watch the existing JavaScript files and have an output file that it will serve based on the browser culture.

I will use some work done by Mads Kristensen who has a similar solution posted at  http://madskristensen.net/post/Localize-text-in-JavaScript-files-in-ASPNET.aspx

No comments:

Post a Comment