Oct
14
2011

Coast to Coast with dojo.string.substitute

I recently relocated from Raleigh, North Carolina to San Francisco, California. My beautiful and ridiculously talented partner of 9 years got a job in Sausalito, and we took the plunge. The moving process involved a cross-country drive that took roughly five days to complete. Here’s an action shot of me driving through Montana, accompanied by my heavily sedated cat, Frenzy.

 

 

I’ve been in San Francisco for about a week now. I know this shouldn’t have come as a surprise, but let me state the obvious. San Francisco is different than Raleigh. HTML5 should include a <DUH> element for assertions like that, but I must say, I did not fully prepare myself for the lifestyle changes associated with such a move. It’s like my life has been passed through a series of 1-to-1 substitutions. Let me see if I can illustrate this through a series of examples, showing off one of my favorite Dojo utilities: dojo.string.substitute.

Substitutions

Have you ever written JavaScript that injects values into the middle of a string? Did you slice, substring, and RegExp your way to victory? You probably did. Unless great care is taken, this approach is fragile and produces code that is difficult to read. Dojo helps solve this problem via an incredibly convenient utility for performing parametrized substitutions on a string, dojo.string.substitute. Let’s look at a quick example.

In this form, dojo.string.substitute allows you to pass it a string with numbered parameters, and an array whose indices correspond to those parameters.

(In all of the subsequent examples, be sure to dojo.require("dojo.string") to gain access to the substitute function).

var template = "In ${0}, Sweet Tea is ${1}";

var raleigh = dojo.string.substitute(template,
    ["Raleigh",
    "abundant and plentiful."]),

var sf = dojo.string.substitute(template,
    ["San Francisco",
    "no where to be found. I'm pretty sure it is illegal."]);

console.log(raleigh);
console.log(sf);

Output

In Raleigh, Sweet Tea is abundant and plentiful.

In San Francisco, Sweet Tea is no where to be found. I'm
pretty sure it is illegal.

Objects as Variables

The second argument to dojo.string.substitute can also be an object. In this case, the variables in the template correspond to the property names of the supplied object.

var template = "Autumn clothing layers for ${city}: ${clothingList}";

var raleigh = dojo.string.substitute(template,
    { city: "Raleigh", clothingList: "Hoodie, T-Shirt, Pants" });

var sf = dojo.string.substitute(template,
    { city:"San Francisco", clothingList: "Rain Coat, Coat, Puffy Vest, Hoodie, Long-Sleeve T-Shirt, Short-Sleeve T-Shirt, Pants, Shorts, Speedo (Optional, but better to be safe)"});

console.log(raleigh);
console.log(sf);

Output

Autumn clothing layers for Raleigh: Hoodie, T-Shirt, Pants

Autumn clothing layers for San Francisco: Rain Coat,
Coat, Puffy Vest, Hoodie, Long-Sleeve T-Shirt,
Short-Sleeve T-Shirt, Pants, Shorts,
Speedo (Optional, but better to be safe)

Nested Objects

When using objects to specify variable values, it is not necessary to use top-level properties. You can use plain ol’ JavaScript dot notation to specify properties nested within objects.

var template =
    "Number of naked people I saw in public in ${nakedPeopleDesc.city}: ${nakedPeopleDesc.count}.";

var raleigh = dojo.string.substitute(template,
{
    nakedPeopleDesc:
        {
          city: "Raleigh",
          count: "Zero"
        }
});

var sf = dojo.string.substitute(template,
{
    nakedPeopleDesc:
        {
            city: "San Francisco",
            count: "Four. And that was just this morning"
        }
});

console.log(raleigh);
console.log(sf);

Output

Number of naked people I saw in public in Raleigh: Zero.

Number of naked people I saw in public in San Francisco: Four.
And that was just this morning.

Your friend in i18n

Probably the most useful case for dojo.string.substitute is when specifying externalized strings in your i18n bundles. (If you aren’t familar with internationalization in Dojo, see my article on the subject). Let’s say you have something like this. This function returns a string to display a greeting to a user, informing them of their unread messages count.

function getGreeting(nameOfPerson, unreadCount) {
   return "Hello, " + nameOfPerson + ". You have " +
        unreadCount + " unread messages.";
}

When it comes time to externalize the string returned by the above function, how would you go about doing it? One option is to slice it up into multiple strings and add each string as an entry in your i18n bundle. That will work fine for English, but what about other languages? I’m no linguist, but I bet there are languages where unreadCount will make more sense in a different context than in between “You have” and “unread messages”. You are making the lives of your translation team more difficult by adopting this slice n’ dice strategy. The translator will have to first recognize that your multiple strings are part of the same message, and then heroically mash them into something that makes sense. Translators are a clever bunch, and they will figure it out, but why put them through the trouble? The more elegant solution to this problem is to externalize a template like this:

"Hello, ${nameOfPerson}. You have ${unreadCount} unread messages."

Now your translators have a single string to work with, and it’s a much easier task to rearrange that string in a manner that makes sense for a specific language. This article on developerWorks demonstrates an example of how to create a mixin that automatically delegates to dojo.string.substitute. Cool stuff, definitely worth a read.

Conclusion

dojo.string.substitute isn’t an earth-shattering API, but used effectively, it can clean up some of the less-than-beautiful string manipulation lurking in your codebase. And in an i18n context, it is absolutely essential.

Wish me luck in San Francisco; I’m doing a decent job of adjusting. Oh, except for one thing. Did you know that NFL games start at 10:00am out here?! That’s just silly.

Related Posts

About the Author: Dan Lee

Dan Lee is a Software Developer and Dojo enthusiast. He is the creator and co-developer of the ReminderFox Firefox add-on and the addictive iOS game, Rhymo. Find him on Twitter here. Any opinions expressed on this blog are his own, and not of his employer.

12 Comments + Add Comment

  • Hilarious and informative as usual!

  • As always, fun to read and informative. Keep it coming!

  • I love the pic of you and your cat – looks like you were on a serious mission! Great article!

  • Great read as always Dan! Congrats on the big cross-country move!

    • Thanks Heidi! I miss working with you and the rest of my IBM people. :)

  • Good luck in the Bay Area, somebody I worked with at Lulu last autumn (when you and I met when I presented to the Triangle Javascript meetup on ExtJS 3 grids) when I contracted there, has also re-located to SF

    • Thanks George! I already miss the fine folks at Triangle JS.

  • I love your posts! Great article! I wish you all the best in SF ;-)

    Greetings from Germany

    • Thank you for those kind words. I’ve never been to Germany, but I hope to visit someday!

  • Welcome to SF!

    • Nearly forgot: you can likely get sweet tea at Farmer Brown. Also, if you like BBQ, you’ll need to make the pilgrimage to Bo’s BBQ in Lafayette and sate your needs in the meantime at Memphis Minnie.

  • Very amusing. I really want to see Cali one day, especially SF and LA…

Leave a comment