One of the things you may occasionally have to do while using JavaScript is show dialogs and react to your users inputs. These could be in the form of alert boxes that are built into the language, growls, loading panels or even just a message added to an element. (Side note: The jQuery BlockUI plugin seems very promising).
The discerning user would realize that a website that targets a global audience has to be able to localize, globalize and internationalize to their language and a good starting place is to look at Scott Hanselman’s post on this very topic.
Globalization, Internationalization and Localization in ASP.NET MVC 3, JavaScript and jQuery – Part 1
One hacky way to get localized strings in JavaScript when they are in separate files is to have a localized file with all the localized text in it. Then based on the users language preference, load up the appropriate file and use the strings from there. But what if the strings come from a database and you need to generate this at runtime to be able to handle change without deployment again. Well here is how you can do it.
Read the article on JavaScriptView by elegantcode for more details. However, to summarize here are their steps:
- Create a controller method that return the view as a JavaScriptFileResult preferably in your home controller.
- Create a view that contains the localized strings in an array. I used a helper method to get the contents from the database dynamically. You may wish to add this to your home controllers view folder as well.
- Add a script block in the shared layout’s header to the URL for the JavaScript file.
All well and good. The file will now come down with the rest of the content as a JavaScript file and you can use the array of localized strings in your other JavaScript code.
BUT! The one problem you may notice is that the JavaScript source file is retrieved every time a request is made to the server. Thus you will need to cache it. To do so, we just need to add the OutputCacheAttribute onto the controller method that returns the JavaScript file.
[OutputCache(Location = System.Web.UI.OutputCacheLocation.ServerAndClient, Duration = 900, VaryByParam = "none")]
The only problem here is that the VaryByParam is set to none. That’s because we don’t have any parameters being passed into the method. This is a problem because two different requests can come in for varying locales and now the second one may get the cached value of the first one. Therefore, we need to pass in the locale as a parameter and then VaryByParam on that field. This will ensure that every locale has the file cached and changes made can go out without requiring a deployment of files to the server.
The script block in the _Layouts.cshtml file.
<script src="@Url.Content("~/Home/JsConstants?lcid=" + System.Threading.Thread.CurrentThread.CurrentCulture.LCID)" type="text/javascript"></script>
But of course, who wants to keep sending these Id’s over all the time for all our script files. So, the easiest way to do this would be to create an identifier that can be used to check language automatically. And then we can write, “lang” in the VaryByParam attribute option and remove the lcid parameter from JsConstants.
[OutputCache(Location = System.Web.UI.OutputCacheLocation.ServerAndClient, Duration = 900, VaryByParam = "lang")]
The code to make this work is as follows. [Sorry but I’m not quite sure where I found this gem from]
public override string GetVaryByCustomString(HttpContext context, string value) { if (value.Equals("lang")) { return Thread.CurrentThread.CurrentUICulture.Name; } return base.GetVaryByCustomString(context,value); }
As you can see from the image above, the first request for the JsConstants file containing the JavaScript returned 918bytes of data. Whereas, the subsequent call returned 0 bytes. The raw message returned reads as follows:
HTTP/1.1 304 Not Modified
Cache-Control: private, max-age=863
Expires: Sat, 03 Sep 2011 22:57:26 GMT
Last-Modified: Sat, 03 Sep 2011 22:42:26 GMT
Vary: *
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Sat, 03 Sep 2011 22:43:03 GMT
This indicates that we are able to cache the contents of the JavaScript file that was being generated dynamically and it will be refreshed after the Duration we set (900).
Happy Coding.