Posts Tagged ‘best practices’

Worry Free JavaScript Internationalization (i18n)

Sunday, April 13th, 2008

There’s a right way and a wrong way to go about i18n. Just to be clear, I don’t subscribe to the idea of right vs. wrong unless there’s a good reason for it, otherwise I just chalk it up to preference. Sometimes I consider something as a matter of preference until someone points out a compelling argument either for or against it. It’s with that perspective that I address the issue of i18n.

I’ve often found that when first confronted with the need for i18n, the temptation is to do something like this:

var lang = getLang();
var msg = "";
if (lang === "en") {
    msg = "Hello world!";
} else if (lang === "fr") {
    msg = "Bonjour Monde !";
}

That will work fine, but what happens if there’s a bunch of text throughout the app that needs i18n? That’s a whole lot of if/else blocks. And what happens if you suddenly have to support three, four or fifteen languages?

Object literals to the rescue! JavaScript has this wonderful little thing called the object literal represented by a set of brace brackets: {}. It creates a singleton object that can be nested within other objects and can contain pretty much anything. The syntax is very straight forward, all you need are key/value pairs separated by commas:

var data = {
    helloworld: {
        en: "Hello World!",
        fr: "Bonjour Monde !"
    }
}

In this case we have an object being assigned to a variable named data. That object in turn contains another object named helloworld. Finally, helloworld contains two strings, one named en and the other fr. These values can now be accessed like so:

msg = data.helloworld.en;

Of course what we need is to be able to dynamically access the language node in our dataset. This is where index notation comes to the rescue. So far we’ve accessed our data via dot notation, but it’s also possible to access data via index notation like so:

msg = data.helloworld["en"];

I’m sure you can see where this is going. Now that we can specify the last node of our dataset with a string value, all we need to do is substitute it with a variable.

var lang = getLang();
msg = data.helloworld[lang];

Here, getLang determines what the current language setting is and returns a string value accordingly. Once that string value has been received, it can be placed into the index portion of our data object and voila! No more if/else logic, and this technique can be used to support an infinite number of languages without ever having to modify the code itself. You want Spanish? Just add an sp node to your dataset. That’s it, that’s all.

Enjoy!

Update: I neglected to mention that I implemented this solution in the context of a Yahoo! Widget where all of the data is stored locally on the desktop. This solution doesn’t make much sense in the context of a website since you’ll be sending way too much data that won’t be used down the pipe. Thanks to AB for pointing out my oversight.

When Browser Detection Isn’t a Bad Thing

Wednesday, April 9th, 2008

One of the pillars of the Web Standards movement–reinforced in Zeldman‘s seminal Designing With Web Standards–is the idea that browser detection is a bad thing and should be avoided. As with another idea spawned at around the same time, that “tables are bad”, it isn’t wholely true. There are situations where tables are good and even appropriate, likewise there are situations where browser detection is appropriate.

Old School: Browser Detection

Traditionally, browser detection was used for code forking in order to support two or more highly incompatible browsers. So if Netscape 3 was detected, one block of JavaScript was executed, and if Internet Explorer 3 was detected then an entirely different block of JavaScript was executed. The trouble with this model was, and still is, that it’s expensive to maintain. To say nothing of it being error prone. It also doesn’t do a great job of anticipating future versions of browsers.

An example of this was on the Microsoft Games site. Visiting it with the new beta of Internet Explorer 7 would cause the site to hide its content and display a message asking that the visitor please upgrade to Internet Explorer 6 or newer.

New School: Feature Detection

The alternative to browser detection is feature detection. Feature detection means checking to see if a feature exists prior to implementing it. So for example, if a developer wanted to use getElementById, he’d first check for it like so:

if (document.getElementById) {
    var foo = document.getElementById("foo");
}

The New Browser Detection

This works great, unless a browser says it can do something and actually can’t. In other words, if browser X implemented getElementById but it was buggy, it would still pass the test but fail in the code. This is where browser detection comes back into play, but not like in the bad old days. No, this time around browser detection would be used to target and fix–or deny–a feature in a browser known to have issues with it.

An example of this sort of thing would be Safari 2.x’s trouble with cellIndex. Normally, checking a table cell’s cellIndex property would return a number representing its position within a row. Not so with Safari 2.x, in its case cellIndex always returns 0. So testing for cellIndex doesn’t help since it is there, it just doesn’t work.

There are also edge cases that simply can’t be tested for. For example, background images inside an animated iframe in Internet Explorer 6 will flicker throughout the animation sequence. There is no way to do feature detection in this case, however the issue is known. So, the solution may well be to simply test for the browser and if Internet Explorer 6 is detected, to simply deny it the animation and just snap to the last frame.

Summary

So, the new browser detection if you will, is all about damage control in cases where features can’t be detected yet problems are known to exist. I those cases, specific versions of specific browsers are targeted and dealt with appropriately. The mechanism for this may be in the form of conditional comments or JavaScript code written for the purpose.

Worry Free Web Development

Sunday, March 23rd, 2008

Yesterday I gave a presentation at Coder’s Saturday called Worry Free Web Development. Here are the slides.

On Event Throttling

Saturday, December 8th, 2007

The Problem

Recently I had to use the window object’s onresize event in a project I was working on. I needed it in order to reposition some elements on a page whenever the browser’s window size changed. The trouble was, the function was relatively intense and was causing IE to choke. The reason? Different browsers fire the event at different intervals. In Firefox, it fires only once the user stops resizing the window. In IE, it fires continuously while the user is resizing the window. This of course, meant that IE was trying to run my function once every millisecond or so.

(more…)

Design by committee

Tuesday, May 15th, 2007

CamelDesign by committee has long been considered a bad idea. Yet it only dawned on me yesterday that this is exactly how we build the spec for the web. From CSS to Microformats, we not only design the spec by committee, but we’ve managed to take the idea of a committee to a whole new level. Now, anyone from the four corners of the world with an internet connection and an email address can contribute.

A camel is a horse designed by committee

Is this wrong? Is it really a bad idea? After all the web is supposed to be a democracy of sorts. There isn’t an internet police and if everyone has a voice, then no one can complain. But it was Molly who asked only a few days ago What are the most critical issues we need to solve regarding the current fragmenting state of HTML (and XHTML)? (emphasis mine). I can’t help but think that eliminating the approach of a design by committee wouldn’t be a good start. After all, Douglas Crockford single handedly wrote the spec for JSON.

So what do we do? Do we lock a few brains up in a room until they come up with the next version of HTML? Or do we watch the community continue to fragment into HTML 5, XHTML 2 and who knows what else? What are your thoughts?