Clean Markup with Chrome Extension I18n

Having written both an IE extension and a Chrome extension, I must say that writing the Chrome extension was a far, far better experience. Let’s just say that I really don’t want to ever write an IE extension again.

For the IE extension, you have conflicting forum posts and MSDN articles from years ago that only partially apply to the current version of IE, and there isn’t any real documentation or developer’s guide to speak of. You can write the IE extension in C#, but there is no guidance on how to do so, and the prevailing advice is to write the extension in C++.

Chrome, however, provides a great developer’s guide, tutorials, and a wide collection of sample extensions. The Chrome extension is written completely in Javascript, CSS, and HTML, languages which web developers are already familiar with.

Now that I’ve finished my rant, let’s leave IE behind and focus on Chrome.

Today, we’ll be looking at adding internationalization (i18n) support to a Chrome Extension. We’ll also look at a pattern that uses the data-* attribute in HTML5 to provide clean markup that gets internationalized.

But before we show how this is done, let’s first look at the i18n support for Chrome Extensions.

Why is internationalization abbreviated as i18n? Because it’s a really big word, and there are 18 letters between the ‘i’ at the beginning of the word and the ‘n’ at the end of the word, and it’s easier to type i18n. Similarly, localization can be abbreviated as L10n - note the capital L to disambiguate it from i18n.

I18n in Chrome involves 2 steps: defining and translating strings of text, and inserting something into your extension that will render the text for the user’s current language. The text is defined in a series of json files, one per language. Let’s suppose we want to create a Save button in our extension with the ‘Save’ text internationalized. The english json file would contain this:

1
2
3
4
5
6
7
8
{
...
"saveButtonText": {
"message": "Save",
"description": "Text for Save Button"
},
...
}

And the Spanish json file:

1
2
3
4
5
6
7
{
...
"saveButtonText": {
"message": "Archivar"
},
...
}

And the text can then be retrieved using javascript:

1
var translatedText = chrome.i18n.getMessage("saveButtonText");

In this example, translatedText will have a value of "Save" or "Archivar", depending on the locale settings of the browser.

It’s great that Chrome has this support, but the i18n support is focused on javascript and CSS. Unfortunately, HTML is left out. However, a little bit of jQuery magic can help internationalize our markup.

First, we’ll add a data-resource attribute to the HTML elements that we want to internationalize. Let’s see what this looks like on the markup for our Save button.

1
<button id="save" data-resource="saveButtonText">Save</button>

Note the data-resource attribute. This is an attribute I made up, and, as far as I know, has no particular semantic meaning other than what we assign to it.

Now for the fun part. Here is a snippet of javascript that will find all of the elements in the DOM with a data-resource attribute, retrieve the appropriate internationalized text for the element, and insert the text into the element.

1
2
3
4
5
6
$('[data-resource]').each(function() {
var el = $(this);
var resourceName = el.data('resource');
var resourceText = chrome.i18n.getMessage(resourceName);
el.text(resourceText);
});

And the resulting button for a browser set to Spanish:

Save button, internationalized for Spanish

The nice part about this solution is that when your extension needs a new string, such as the text for a Cancel button, to be internationalized, you can add it to each of JSON files (one per language) and add an HTML element with the data-resource attribute. As long as you already have the 6 lines of javascript above, no additional javascript is needed when adding new internationalized strings.

Note that this javascript requires jQuery. I would recommend including jQuery as part of your extension’s package rather than relying on a CDN so that your extension can load without a network delay.