Skip to content

Instantly share code, notes, and snippets.

@adielBm
Last active June 27, 2024 20:24
Show Gist options
  • Save adielBm/21762fe5e964071cb820a0c46896da34 to your computer and use it in GitHub Desktop.
Save adielBm/21762fe5e964071cb820a0c46896da34 to your computer and use it in GitHub Desktop.
ipa for google-translate
// ==UserScript==
// @name IPA for translate.google
// @namespace https://gist.github.com/adielBm/21762fe5e964071cb820a0c46896da34
// @version 2024-06-27
// @description Convert phonetic transcription to IPA on Google Translate
// @author adielBm
// @match https://translate.google.com/*
// @grant none
// @updateURL https://gist.githubusercontent.com/adielBm/21762fe5e964071cb820a0c46896da34/raw
// @downloadURL https://gist.githubusercontent.com/adielBm/21762fe5e964071cb820a0c46896da34/raw
// ==/UserScript==
(function () {
"use strict";
function getIPA(str) {
const mapping = {
oi: "ɔɪ",
ou: "aʊ",
ô: "ɔ",
ä: "ɑ",
a: "æ",
æʊ: "aʊ",
i: "ɪ",
ē: "i",
o͝o: "ʊ",
o͞o: "u",
e: "ɛ",
ā: "eɪ",
ī: "aɪ",
ō: "oʊ",
NG: "ŋ",
TH: "θ",
T͟H: "ð",
CH: "tʃ",
SH: "ʃ",
ZH: "ʒ",
j: "dʒ",
y: "j",
};
let result = "";
let i = 0;
const strLength = str.length;
while (i < strLength) {
let foundReplacement = false;
// Check for multi-character replacements
for (const key in mapping) {
if (str.startsWith(key, i)) {
result += mapping[key];
i += key.length;
foundReplacement = true;
break;
}
}
if (!foundReplacement) {
result += str[i];
i++;
}
}
return result;
}
// Target element selectors
const targetSelectors = ["[jsname=toZopb]", ".D4w5q"];
// Function to be executed when a target element is created or its inner text changes
function convertTextToIPA(element) {
const text = element.innerHTML;
if (text.length > 0 && text.charAt(0) !== "/") {
element.innerText = `/${getIPA(text)}/`;
}
}
// Create a new MutationObserver instance
const observer = new MutationObserver((mutationsList) => {
const processedElements = new Set();
for (const mutation of mutationsList) {
if (mutation.type === "childList" || mutation.type === "characterData") {
// Check added/modified nodes
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
targetSelectors.forEach((selector) => {
if (node.matches(selector)) {
convertTextToIPA(node);
processedElements.add(node);
} else {
node.querySelectorAll(selector).forEach((child) => {
if (!processedElements.has(child)) {
convertTextToIPA(child);
processedElements.add(child);
}
});
}
});
}
});
// Check directly modified nodes
if (
mutation.type === "characterData" &&
mutation.target.nodeType === Node.TEXT_NODE
) {
const parent = mutation.target.parentElement;
if (parent) {
targetSelectors.forEach((selector) => {
if (parent.matches(selector) && !processedElements.has(parent)) {
convertTextToIPA(parent);
processedElements.add(parent);
}
});
}
}
}
}
});
// Start observing the document for mutations
observer.observe(document.body, {
childList: true,
characterData: true,
subtree: true,
});
// Initial processing of existing elements
targetSelectors.forEach((selector) => {
document.querySelectorAll(selector).forEach(convertTextToIPA);
});
})();
@huan
Copy link

huan commented Oct 30, 2023

Thanks for sharing! I think this script desires a new Chrome Extension for easy install and use for language learners who want to see the IPA from the Google Translate site!

@Assignmentsymbol
Copy link

It helps me a lot, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment