String Formatting / Interpolation

Monday, 8th December 2014

Unlike other programming languages, JavaScript does not (yet) provide native methods for variable interpolation in a string. However it is very useful, and also completely removes excessively long and arduous string concatenation expressions. At least once a project I find myself needing to do some kind of string formatting, and I always fallback on the following very simple implementation.

function format(str, dict) {
    return str.toString().replace(/\{([^}]+)\}/g, function(match, key) {
        return dict[key];
    });
}

As you can see it's a very small, rather simple function which takes a template-like string and a dictionary object.

Let's take a rather silly example and say that we are creating a site that displays the number of apples a user has. Both the user and the number of apples in this application are dynamic. With string concatenation we would do the following:

var username = 'Dave',
    numberOfApples = 8;

var output = username + ' has ' + numberOfApples + ' apple(s).';

console.log(output); // Dave has 8 apple(s).

We would obviously see the correct output of Dave has 8 apple(s)., but with string formatting we can make the whole thing alot more readable:

var tmpl = '{username} has {numberOfApples} apple(s).';

var output = format(tmpl, {
    username: 'Dave',
    numberOfApples: 8
});

console.log(output); // Dave has 8 apple(s).

As you can see, now we have separated our template string from our variables, we have gained quite a lot of control. Without messing around with a long concatenation we can change the template in any way we want:

var tmpl = '{numberOfApples} apple(s), right {username}?';

var output = format(tmpl, {
    username: 'Dave',
    numberOfApples: 8
});

console.log(output); // 8 apple(s), right Dave?.

The true value, however, lies in internationalisation. Say our apple counting website was to be rolled out in Russia and the template was to be translated into Russian. We can never guarantee that our sentence in another language is structured the same way, eg. name > helping verb > number > noun. It doesn't matter what order we have the values, because we use a dictionary lookup we can interpolate values at any point independent of order.

var tmpl = 'у {username} {numberOfApples} яблок';

var output = format(tmpl, {
    username: 'Dave',
    numberOfApples: 8
});

console.log(output); // у Dave 8 яблок.

This is obviously a very simple implementation for internationalisation and would require alot more work to be considered 'production ready'.

The Future - ES6 Template Strings

Template strings are one of the new features of the ECMAScript 6 (ES6) standards. Instead of single or double-quotes, template strings are denoted by backticks (`) and allow us to interpolate values into strings very easily.

let username = 'Dave';
let numberOfApples = 8;
let output = `${username} has ${numberOfApples} apple(s).`;

console.log(output); // Dave has 8 apple(s).

There is more to template strings in ES6, but they're not widely supported yet, even in bleeding edge node. So let's save that for another time.