Convert Page to IPA Pronunciation

Replaces all English words on a webpage with their pronunciation in the international phonetic alphabet. American and British English flavors available!

// ==UserScript==
// @name        Convert Page to IPA Pronunciation
// @description Replaces all English words on a webpage with their pronunciation in the international phonetic alphabet. American and British English flavors available!
// @version     2.0.0
// @require     https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js
// @include     *
// @grant       GM_xmlhttpRequest
// @grant       GM_registerMenuCommand
// @namespace   https://greasyfork.org/en/users/13329-qguv
// ==/UserScript==

/* All thanks, donations, hugs, etc. should go to Oliden, the original author:
 * https://greasyfork.org/en/users/9379-oliden
 * I just cleaned things up a bit and improved performance.
 */

/* fetch_dict fetches the relevant word-to-ipa dictionary from Oliden's site
 * and passes it to a given callback function. Pass variant "US" or "GB" for
 * American or British English pronunciations, respectively. N.b. that
 * everyone's English dialect is different; there is no one 'british' or
 * 'american' pronunciation! */
function fetch_dict(variant, callback) {
  var dict_url = "http://www.olivetti.info/";
  if (variant === "GB-R" || variant === "GB-NR") {
    dict_url += "words.json";
  } else {
    dict_url += "wordsAmE.json";
  }
  return GM_xmlhttpRequest({
    method: "GET",
    url: dict_url,
    onload: function (r) { callback(JSON.parse(r.response)); }
  });
}

/* to_ipa takes a string, a hashmap from English words to their IPA
 * pronunciations, and a flag indicating whether to display stress markers in
 * IPA words. */
function to_ipa(s, wordmap, preserve_stress, variant) {
  if (s.length === 0) { return ''; }

  var this_word   = '';
  var ipa_word    = '';
  var converted  = '';
  var delimeters = ' ,.;:<>()\n!\"—';
  s.split('').forEach(function (c, i) {

    // not a delimeter
    if ((delimeters.indexOf(c) === -1) && (i != (s.length - 1))) {
      this_word += c;

    // is a delimeter or last item
    } else {
      ipa_word = wordmap[this_word];
      if (ipa_word === undefined) {
        ipa_word = this_word;
      } else if (!preserve_stress) {
        ipa_word = ipa_word.replace(/[.ˈ]/g,'').replace(/[ˌ]/g,'');
      }
      var new_rhotic = '';
      if (variant === "GB-R") {
        new_rhotic = 'r';
      }
      ipa_word = ipa_word.replace(/[(]r[)]/g, new_rhotic);
      converted += ipa_word;
      converted += c;
      this_word = '';
    }
  });

  return converted;
}

function transform_webpage_text(page, transform_fn) {
  const TEXT_NODE = 3;
  const ELEMENT_NODE = 1;

  if (page.nodeType === TEXT_NODE) {
    var parent_type = page.parentNode.nodeName.toLowerCase();
    if( parent_type != "style" && parent_type != "script" ){
      ns = transform_fn(page.data.toLowerCase());
      page.data = ns;
    }
  } else if (page.nodeType === ELEMENT_NODE) {
    for (var child = page.firstChild; null != child; child = child.nextSibling) {
      transform_webpage_text(child, transform_fn);
    }
  }
}

function page_to_ipa(variant, preserve_stress) {
  fetch_dict(variant, function (wordmap) {
    if (typeof wordmap == 'undefined') {
      alert("? Couldn't fetch pronunciation dictionary!");
      return;
    }
    transform_webpage_text(document.body, function (s) {
      var i = to_ipa(s, wordmap, preserve_stress, variant);
      console.log("transforming " + s + " to " + i);
      return i;
    });
  });
}

GM_registerMenuCommand(
    "Page to IPA",
    function () { page_to_ipa("US", false); }
);

GM_registerMenuCommand(
    "Page to IPA with stress",
    function () { page_to_ipa("US", true); }
);

GM_registerMenuCommand(
    "Page to IPA (Rhotic British English)",
    function () { page_to_ipa("GB-R", false); }
);

GM_registerMenuCommand(
    "Page to IPA with stress (Rhotic British English)",
    function () { page_to_ipa("GB-R", true); }
);

GM_registerMenuCommand(
    "Page to IPA (Non-Rhotic British English)",
    function () { page_to_ipa("GB-NR", false); }
);

GM_registerMenuCommand(
    "Page to IPA with stress (Non-Rhotic British English)",
    function () { page_to_ipa("GB-NR", true); }
);