Technical Stuff


Since 1.6.1 Translate And Speak! UI uses ExtJS, jQuery, Chrome i18n support and WebSQL.

The bits I like most


ExtJS is used to render pop up (ballon) from toolbar icon. The main view used is Ext.TabPanel, which displays tabs. Each tab consist of an IFrame object containing separate page:

	var tabs = new Ext.TabPanel({
		renderTo: Ext.getBody(),
		activeTab: 0,
		deferredRender: true,
		items: [{
			title: LANG("OVERVIEW_TAB"),
			html: '<iframe src="overview.html" width="100%" height="100%" border="2"></iframe>'
			title: LANG("PHRASES_TAB"),
			html: '<iframe src="index.html" width="100%" height="100%" border="2"></iframe>'
			title: LANG("OPTIONS_TAB"),
			html: '<iframe src="options.html" width="100%" height="100%" border="2"></iframe>'

During development interesting issue has been noticed: when the popup was displayed for as a extension, the first tab seemed empty. After user changing tabs and then returned to first one, the information has been displayed correctly. This behavior has been caused by race condition between ExtJS and chrome engine – the page must has been rendered before the window for it has been completed thus the width of it has been 0. Automatically all objects with width set to 100% were invisible and seemed not to be displayed. Setting required size for div containing the content in CSS solved the problem.

Making ExtJS look pretty

ExtJS is fine framework for developing data centric application. Unfortunately (or rather fortunately) typical web pages have to maintain not only functionality, but also nice look&feel. To make ExtJS less office-like I decided to:
* Add a background and make the contents slightly opaque:

	opacity: .9;

I am very pleased with the result:

The background has been downloaded as royalty free image from

Debuging Chrome Extension with Internalization

Chrome’s i18n support gives API to access localized messages in form of chrome.i18n.getMessage(string, args); method. Unfortunately this API doesn’t work then the code outside the extension, but produces Uncaught TypeError: Cannot call method 'getMessage' of undefined.

In come cases debugging outside an extension is quicker as you can run only part of code, so I have created dummy wrapper for the API to override the issue:

function LANG(string, args) {
		return chrome.i18n.getMessage(string, args);
	} else {
		//im run outside an extension
		return string;

Second benefit of the method is that you save a lot of keystrokes typing LANG(“MSG_KEY”) than chrome.i18n.getMessage(“MSG_KEY”).

Playing sound from

To play the sound (speach) delivered by Google’s Translate API, the extension reads it all to local variable and then converts it to base64 only just to put it into source of Audio objects. Chrome supports data: protocol in URLs.

function readItAloud(text, lang) {
	xhr=new XMLHttpRequest();
	xhr.onreadystatechange  = function(){ 
		 if(xhr.readyState  == 4) {
			if(xhr.status  == 200) {
				var encoded=BinaryBase64.encodeBinary(xhr.responseText);
				var src="data:audio/mp3;base64,"+encoded;
				var audio=new Audio();
			} else {
				 alert("Audio data can't be retrieved, Error:"+xhr.status);
	xhr.overrideMimeType('text/plain; charset=x-user-defined');
	url=""+lang+"&q="+text;"GET", url,  true); 

Source code

Complete code for the extension is available at GitHub:

Big thanks!

“TAS!” uses some 3rd party components:
* Convert Unicode String to BASE 64 is used to translate output from XMLHttpRequest as standart btoa() method delivered with Chrome can work only with 1 byte per char Strings.
* Option page is based on page from Chrome it later extension.
* Icon has been designed by Fast Icon

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.