Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Accessing Localized values in ASP.NET markup and JavaScript


:P
On this page:

I’m finally to the point where I can start using my localization provider code to actually localize a few applications and pages <s>. Took a while to get everything working correctly and get the live resource editing hooked up and little kinks worked out.

 

So the first task is to actually localize (or rather make localization ready) the various admin forms and helpers for the Localization provider.

 

The first thing I ran into is that by far the hardest part of the localization process is not the UI control assignments, but any text assignments in code. Yech. This is made even worse by the fact that the entire admin interface is driven mostly through AJAX code so a lot of strings are embedded on the client side in script code.

 

So, ASP.NET Pages make it pretty easy to get localized ‘objects’ back using Control.GetLocalResourceObject() and Control.GetGlobalResourceObject(). These two functions allow you to get a provider specific resource without having to muck with resource managers. Behind the scenes ASP.NET has hooked up the appropriate ResourceProvider and is asking it to return to you the appropriate ResourceKey.

 

In code this is pretty straight forward. Anywhere in Page code you can do:

 

string Value = this.GetGlobalResourceObject("westwindglobalization","NoReourcesFound") as string;

 

You can also get this stuff into the markup using classic ASP style expressions:

 

<%= GetGlobalResourceObject("westwindglobalization","NoReourcesFound") %>

 

I know some folks shutter at using <%= %> expressions, but if you have literal text in certain places you can’t easily get around using these expressions. For example in script code where it gets kinda ugly:

 

<script type="text/javascript">

alert('<%= GetGlobalResourceObject("westwindglobalization","Loading") %>');

 

Or for the more politically correct:

 

<script type="text/javascript">

alert('<asp:Localize runat="server">My Text</asp:Localize>');

 

The advantage of the latter is that you can assign a meta:resourcekey to the ASP.NET 2.0 Localize control:

 

alert('<asp:Localize runat="server" id="locSomeText" meta:resourcekey="LoaderString">Some Text</asp:Localize>');

 

Well, it’s supposed to work, but unfortunately I can’t get the resource key to work either inside of script or just in the middle of the page proper. VS.NET generated a Resource key but for some reason the Implicit key is never fired at runtime <shrug>.

 

In any case typically I prefer to have explicit resource strings stored in global resources where they can hopefully be reused more frequently.

 

But there’s another problem with the syntax of both entries above: Both will fail if the string returned includes a single quote as the output is generated as a literal string as well as any escaped characters that can potentially be misinterpreted by the client script parser if the literal is placed inside of JavaScript code.

 

Sooo… to make things a little easier in client code (both markup and script) I think it’s probably a good idea to create a few helper functions with shorter names and simpler syntax.

 

#region Localization Helper Functions

 

/// <summary>

/// Global Resource Help Function for easier syntax

/// </summary>

/// <param name="ResourceKey"></param>

/// <param name="ResourceSet"></param>

/// <returns></returns>

public string Res(string ResourceKey, string ResourceSet)

{

    string Value = this.GetGlobalResourceObject(ResourceSet, ResourceKey) as string;

    if (Value == null)

        return ResourceKey;

 

    return Value;

}

/// <summary>

/// Global Resource Helper function for easier access.

/// Defaults resource set and requires only the ResourceId

/// </summary>

/// <param name="ResourceKey"></param>

/// <returns></returns>

public string Res(string ResourceKey)

{

    return Res(ResourceKey, "westwindglobalization");

}

 

/// <summary>

/// Creates a client side compatible string including the quote characters.

/// This simplifies adding values to client script with code like this:

///

/// &lt;%= ResC("ResourceID") %&gt;

/// </summary>

/// <param name="ResourceKey"></param>

/// <returns></returns>

public string ResC(string ResourceKey)

{

    string Value = Res(ResourceKey, "westwindglobalization");

    return EncodeJsString(Value);

}

 

/// <summary>

/// Encodes a string to be represented as a string literal

/// </summary>

/// <param name="s"></param>

/// <returns></returns>

string EncodeJsString(string s)

{

    StringBuilder sb = new StringBuilder();

    sb.Append("\"");

    foreach (char c in s)

    {

        switch (c)

        {

            case '\"':

                sb.Append("\\\"");

                break;

            case '\\':

                sb.Append("\\\\");

                break;

            case '\b':

                sb.Append("\\b");

                break;

            case '\f':

                sb.Append("\\f");

                break;

            case '\n':

                sb.Append("\\n");

                break;

            case '\r':

                sb.Append("\\r");

                break;

            case '\t':

                sb.Append("\\t");

                break;

            default:

                int i = (int)c;

                if (i < 32 || i > 127)

                {

                    sb.AppendFormat("\\u{0:X04}", i);

                }

                else

                {

                    sb.Append(c);

                }

                break;

        }

    }

    sb.Append("\"");

 

    return sb.ToString();

}

#endregion

 

With string expressions in script code look like this:

 

function GetResourceStrings_Callback(Resources)

{

    // returns a two col array

    if (Resources == null)

    {

        this.ShowMessage(<%= ResC("NoResourcesAvailable") %>);

        return;

    }

 

ResC adds outer quotes and escapes any quotes inside of the string JSON style.

 

For any regular page expressions:

 

<%= Res("NoResourcesAvailable") %>

 

Or if databinding is involved:

 

<%# Res("NoResourcesAvailable") %>

 

 

This makes life somewhat easier. The easiest approach however would be if strongly typed resources worked properly in ASP.NET, but I don’t have time at the moment to build that out.

 

I suppose there could be other ways to tackle this such as pre-generating all the strings into an object on the client and then using the object (like Res.NoResourcesAvailable) to get the resource. But I honestly don't see any big advantages to that except that all literals are all in one place. You still have to assign them into code somehow and ensure that the names match properly. All of this is brittle if there's a typo - the code above deals with this by returning the ResourceId as the result value if the ResourceId was not found.

Posted in ASP.NET  Localization  

The Voices of Reason


 

Rick Strahl's Web Log
November 14, 2006

# Strongly typed resources in ASP.NET - Rick Strahl's Web Log

So I was screwing around today with strongly typed resources in ASP.NET. Another cool side-effect of using Web Application Projects as opposed to stock ASP.NET projects is that WAP uses strongly typed global resources. If you create a global resource file, WAP automatically creates a strongly typed...

Shan Plourde
January 30, 2007

# re: Accessing Localized values in ASP.NET markup and JavaScript

Hi Rick, you could also create a custom ExpressionBuilder to encode string resources to be JavaScript friendly. That way you could still benefit from doing the resource expressions thing if you didn't want to do a ton of other coding.

<%$ wwwJSResource:Blah, Blah %>

You could probably subclass the ResourceExpressionbuilder. Michèle Leroux Bustamante is a smart woman that has some great architecture / design articles. This one is worth the read if you're interested:
http://msdn2.microsoft.com/en-us/library/aa905797.aspx#exaspnet20rpm_topic6

I've created a couple of ExpressionBuilders and they're super easy to do. Of course there's always tons of ways to skin a cat and it might not be the right fit for you, but just thought I'd point it out to you, keep up the great work!

Shan

Rick Strahl
January 31, 2007

# re: Accessing Localized values in ASP.NET markup and JavaScript

Yes I had thought about that as well, but decided it's not really a big advantage to do this since the syntax would actually be longer. I think key for this sort of thing is that the syntax is short so it doesn't get in the way of the readability of the code.

Actually a generic code expression like this:

http://weblogs.asp.net/infinitiesloop/archive/2006/08/09/The-CodeExpressionBuilder.aspx

might actually be the easiest way to do this without inventing new syntax that Microsoft one day will make obsolete <s>...

Matthew Morris
April 05, 2007

# re: Accessing Localized values in ASP.NET markup and JavaScript

Thanks for the article, I am converting an old ASP website to ASP.NET 2 and now adding localization.
Another problem I got is that a lot of calculations are done in Javascript and returned to Text boxs. Since some cultures which are set to the system have different types of decimal points (GB its . but NL its ,)
I will have to implement these correctly, I do not want to write different Js files for each Culture, is there a solution anyone knows

Travich
July 11, 2007

# re: Accessing Localized values in ASP.NET markup and JavaScript

I can't figure out how to pull a global resource from app_globalresources with javascript. I'm going to monkey around with the GetGlobalResourceObject or whatever and see if that will pull my value out.

I am mostly a winforms developer, so I don't really know much about what I'm doing here and could use a simple example of how to do this... ASP.NET 2.0, C#


Travich

Rick Strahl
July 11, 2007

# re: Accessing Localized values in ASP.NET markup and JavaScript

Uhm this article describes exactly what you ask.

Morten Grøtan
February 12, 2009

# re: Accessing Localized values in ASP.NET markup and JavaScript

Perhaps stating the obvious, but in order for inline ASP.NET expressions like this to work, you will of course need to have an "executable" context. By which I mean a usercontrol or similar.
Obviously you do this in your example, as you have a
<script ...
tag at the top.

I just wanted to point this out, because if your JavaScript files are being used as regular include files, using a
<script src="" ...
tag, you'll have to convert them into for instance a usercontrol and register it as such, typically within the
<head ...
tag.

The potential downside of this is that the JavaScript content will be rendered inline in your web form, whereas an include file would be a separate physical file. You'll also not get any proxy server or client browser caching of the otherwise static file, so if you have a rather large JavaScript file, consider refactoring out the portions really needing localization, and keep the rest in the old static file.
Serving the JavaScript file through the WebResource.axd mechanism is no longer an option as well.

For old-timers remembering "Classic ASP", this technique was used back then, too.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024