create simple Chrome Translator extension (JavaScript only)

Gl
5 min readSep 1, 2022

--

In short, how this extension work — user selects text segment and selection gets replaced with its translation to other chosen language.

source code (complete, but has some minor code changes)
video tutorial (has more in-depth info, recommended to try after this project)

Before(language detected automatically)
After(French)

Let’s break it into 3 simple steps:

1 Translation software required(can be used from other companies as well) — in this case Microsoft Translation API, available at RapidAPI website which provides free subscription(no credit card needed);
2 Extension setup making extension required files — manifest.json and content.js. And adding extension to chrome browser;
3 Code setup — consists of :
Accessing selected text;
Making API call(Microsoft Translator API) which sends selected text, then waits for response;
Display(replacing selection with translated phrase);

1.Translation software (getting the API key)

https://rapidapi.com/microsoft-azure-org-microsoft-cognitive-services/api/microsoft-translator-text/pricing

This website requires only an account, if you want to use it for free in “pricing” tab choose “Basic”. Also there is no need to add payment methods at all. When registered and subscribed to Basic plan, go to “endpoints”, and somewhere in the middle it will contain API key.

Sequence of random letters and digits is the key

2.Extension setup

create a folder Translator 0.1 inside of it make 2 files — content.js and manifest.json

to access the content of these files, right click and “open with” — notepad. manifest.json is the configuration file of extension. So here is sample template of manifest.json

manifest.json Final version

{
"name":"Translator",
"description":"Translate text from one language to another",
"version": "0.1",
"manifest_version":3,
"content_scripts":[
{
"matches":["<all_urls>"],
"js":["content.js"]
}
]
}

After manifest.json is filled(for now leave content.js empty) you can try to add it to the browser, by going to chrome://extensions/ click “Developer mode”, “Load unpacked” and then choose folder containing both files, if everything is right extension will be added to the page.

content.js is responsible for site behaviour and its graphics (can access basic parameters like mouse movement, selected text, etc.). Further code will be related to content.js. Note that whenever you make changes in code don’t forget to refresh the extension by visiting extensions page listed above and hitting refresh button on the extension itself, not the page.

3.Code setup

(API call and response reading)

Now it’s time to make API initialization, replace ??? with your key.

const API_KEY = "???",
XHR = new XMLHttpRequest();
XHR.withCredentials = true;
// These variables will be required for restoring the state, before replacing the translated text
var prev = '', prevRange = '';

API call function (accepts 3 arguments:
text=the selected word, target=output language in this case German ‘de’, source=can be specified when given text language is known, if empty uses autodetection).
All of the available languages and its shortcuts are listed on microsoft api page “overview”.
API request:

function apiRequest(text, target = ‘de’, source = ‘’) {
XHR.open("POST", "https://microsoft-translator-text.p.rapidapi.com/translate?to="
+ target.toString() +
"&api-version=3.0&"
+ source +
"profanityAction=NoAction&textType=plain");
XHR.setRequestHeader("content-type", "application/json");
XHR.setRequestHeader("x-rapidapi-key", API_KEY);
XHR.setRequestHeader("x-rapidapi-host", "microsoft-translator-text.p.rapidapi.com");
XHR.send(JSON.stringify([{"text": text}]));
}

Handling API response function(getting the translation):

XHR.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
const responseData = JSON.parse(this.responseText)[0];
let translation = responseData.translations[0].text;
if (window.getSelection().toString().length > 1) {
prev = window.getSelection().toString();
replaceSelectedText(translation);}}
});

All that’s left is to get selected text and replace it.
Mouse selection listener:

// Handles mouse clicks on the page
window.addEventListener('mouseup', function () {
let selection = window.getSelection();
console.log(selection);
// If user has closed the selection, revert text to the initial state
if (selection.isCollapsed === true && prev != '') {
try {
prevRange.deleteContents();
prevRange.insertNode(document.createTextNode(prev));
} catch (error) { };
return
}
// used with language autodetection
apiRequest(selection.toString(), 'de');
});

Replace selection function:

// Replaces the selected text with the translation
function replaceSelectedText(replacementText) {
var sel, range;
if (window.getSelection) {
sel = window.getSelection();
if (sel.rangeCount) {
range = sel.getRangeAt(0);
prevRange = range;
range.deleteContents(); range.insertNode(document.createTextNode(replacementText));}}
}

content.js Final version

var prev = '',
prevRange = '';
const API_KEY = "???",
XHR = new XMLHttpRequest();
XHR.withCredentials = true;
// Makes the HTTP request using the selected text as the query string
function apiRequest(text, target = 'de', source = '') {
XHR.open("POST", "https://microsoft-translator-text.p.rapidapi.com/translate?to="
+ target.toString() +
"&api-version=3.0&"
+ source +
"profanityAction=NoAction&textType=plain");
XHR.setRequestHeader("content-type", "application/json");
XHR.setRequestHeader("x-rapidapi-key", API_KEY);
XHR.setRequestHeader("x-rapidapi-host", "microsoft-translator-text.p.rapidapi.com");
XHR.send(JSON.stringify([{ "text": text }]));
}
// Handles the translation response
XHR.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
const responseData = JSON.parse(this.responseText)[0];
let translation = responseData.translations[0].text;
if (window.getSelection().toString().length > 1) {
prev = window.getSelection().toString();
replaceSelectedText(translation);
}
}
});
// Handles mouse clicks on the page
window.addEventListener('mouseup', function () {
let selection = window.getSelection();
console.log(selection);
// If user has closed the selection, revert text to the initial state
if (selection.isCollapsed === true && prev != '') {
try {
prevRange.deleteContents();
prevRange.insertNode(document.createTextNode(prev));
} catch (error) { };
return
}
// used with language autodetection
apiRequest(selection.toString(), 'de');
});
// Replaces the selected text with the translation
function replaceSelectedText(replacementText) {
var sel, range;
if (window.getSelection) {
sel = window.getSelection();
if (sel.rangeCount) {
range = sel.getRangeAt(0);
prevRange = range;
range.deleteContents();
range.insertNode(document.createTextNode(replacementText));
}
}
}

--

--