3

I'm trying to determine the best way to implement localization into one of our web apps. This app is going to have a large number of javascript files, which will need to be localized as well.

Localizing the .net code is straight forward enough. We have a file called WebResources.resx which contains all strings in english (our fall back language). Then we just add additional files with alternative localized information (eg: WebResources.es-mx.resx). Then, bam! .Net pretty much takes care of the rest.

Pretty sweet. But when it comes to javascript, not so fast. Reading on MSDN they recommend:

You create a separate script file for each supported language and culture. In each script file, you include an object in JSON format that contains the localized resources values for that language and culture.

This seems like a maintenance nightmare that I'd like to avoid. Plus I'd like to avoid having to use the asp.net ScriptManager. So I got the bright idea of trying to use the resource files in my .js files. EG foobar.js:

function showGenericError(){
     alert('<% =Resources.WebResources.JsGenericError %>');
}

This unfortunately does not work as the .NET does not seem to do any processing on .js files. So the next idea I got was from the answer on this thread. It recommended having a javascript file which contained all your language strings. This feels like a waist of resources since at run time I only need one language, not all of them.

This leads me to the solution I'm planning on implementing. I plan to have a generic handler that writes out JSON that is localized for the language the current user is in need of. Here is a sample of what the .ashx page will look like:

public void ProcessRequest (HttpContext context) {
        context.Response.ContentType = "application/json";

        StringBuilder json = new StringBuilder();
        using (StringWriter jsonStringWriter = new StringWriter(json))
        {
            using (JsonTextWriter jsonWriter = new JsonTextWriter(jsonStringWriter))
            {
                jsonWriter.WriteStartObject();                

                jsonWriter.WritePropertyName("genericErrorMessage");
                jsonWriter.WriteValue(Resources.WebResources.GenericErrorMessage);

                jsonWriter.WriteEndObject();
            }
        }
        context.Response.Write("var webResources = " + json.ToString());
}

In the head of my pages I will have:

<script type="text/javascript" src="js/webResources.js.ashx"></script>

Then my js file will look like:

function showGenericError(){
     alert(webResources.genericErrorMessage);
}

Almost seems too easy, right? So my question is, does this make sense? Am I missing a "gotcha" somewhere? What are the downsides? Is there a better way to do this?

Community
  • 1
  • 1
roto
  • 677
  • 6
  • 11
  • 1
    Makes sense, though you might want to figure out a way to produce the JavaScript version of each catalog file at **build** time so that browsers can cache the data. The way it is here, the catalog will have to be re-downloaded for each page view. – Pointy Feb 17 '11 at 16:30
  • Looks like in the end you ended up with something very similar to your MSDN article recommended. i.e. one js file containing the json serialized localization of a single language. – CodesInChaos Feb 17 '11 at 16:32
  • CodeInChaos, in a round about way, yes. But I avoid having to use the ScriptManager or having to write logic to determine which JS file to load. The real advantage is that it degrades nicely if a key is missing in one of the language files. – roto Feb 17 '11 at 16:47
  • Using the same javascript url for all languages is a bad idea IMO. This makes caching much harder to do correctly. For example if the user switches the language... – CodesInChaos Feb 17 '11 at 19:23

2 Answers2

0

I posted a similar question a while ago, and this is what I came up with:

Localize javascript messages and validation text

The advantage here is that you can share resources used in regular .net pages.

Your approach looks fine as well.

Community
  • 1
  • 1
ScottE
  • 21,530
  • 18
  • 94
  • 131
0

Here is the way i did it, just in case someone finds it useful.

I didnt want to put any Razor on JS, because of CSP i kept JS files separated from the cshtml.

So I added a element in the Shared cshtml, with the content of an array of arrays, each element of the array is a Key/Value pair with the name and the localized string as returned by Razor>

<meta name="resources" content="[
          ['name1', '@HttpUtility.JavaScriptStringEncode(Resources.name1)'],
          ['name2', '@HttpUtility.JavaScriptStringEncode(name2)']
     ]" />

Then in the js file, i convert this into a dictionary:

let livstrResMap = document.querySelector("meta[name='resources']").getAttribute("content");
livstrResMap = livstrResMap.replace(/'/g, '"')
let lioJSN = JSON.parse(livstrResMap)
let mcvcodResources = new Map(lioJSN);

Finally i use the localized string using the Format helper defined here

alert(mcvcodResources.get('name1'));
D.Firka
  • 59
  • 5