Open11

MathJaxの数式を含むWebページをGoogle翻訳する

ピン留めされたアイテム
coindarwcoindarw

現状のまとめ

方法1

以下2つのブックマークレットを登録しておき、「1つ目実行」→「ページを翻訳」→「2つ目実行」

javascript:document.querySelectorAll(".MathJax, .mjx-chtml, .MathJax_Preview, .MathJax_CHTML").forEach(e=>{e.parentNode.removeChild(e)}),document.querySelectorAll('script[type="math/tex"]').forEach(e=>{let t=e.innerText||e.textContent,a="$"+t+"$",r=document.createElement("span");r.className="replaced",r.innerHTML=a,e.parentNode.replaceChild(r,e)});
javascript:MathJax.Hub.Config({tex2jax:{inlineMath:[["$","$"]]}}),Array.prototype.forEach.call(document.querySelectorAll(".replaced"),e=>{MathJax.Hub.Typeset(e)});

方法2

以下のブックマークレットを登録して実行する

翻訳後3秒後決め打ちでタイプセットが走るので、適宜調整が必要

javascript:!function(){document.querySelectorAll(".MathJax, .mjx-chtml, .MathJax_Preview").forEach(function(e){e.parentNode.removeChild(e)}),document.querySelectorAll('script[type="math/tex"]').forEach(e=>{var t=e.innerText||e.textContent,a=document.createElement("span");a.className="replaced",a.innerHTML="$"+t+"$",e.parentNode.replaceChild(a,e)});let e=document.createElement("script");e.type="text/javascript",e.src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit",document.body.appendChild(e),window.googleTranslateElementInit=()=>{new google.translate.TranslateElement({pageLanguage:"en",layout:google.translate.TranslateElement.FloatPosition.TOP_LEFT,completionCallback(){console.log("done")}},"google_translate_element")},setTimeout(()=>{MathJax.Hub.Config({tex2jax:{inlineMath:[["$","$"]]}}),Array.prototype.forEach.call(document.querySelectorAll(".replaced"),e=>{MathJax.Hub.Typeset(e)})},3000)}();

問題点

  • アクセシビリティ等をガン無視している
  • 2回呼びだすと壊れるなどコードが雑
  • KaTeX使ってるサイトだと対処不可
  • displaymathなど確認していない形式が多い
  • AsciiMathなど、MathJaxが対応していてもTeX以外の記法は無視している
  • 長くて一度に翻訳されないサイト、数式表示が動的なサイトだとうまくいかない(?未検証)
  • スマホからだと置換ができない コード修正したらできるようになった

追記:3つ上の修正に伴い方法1のブックマークレット修正

coindarwcoindarw

(Notionからコピペする時に肝心の目標が消えていたので追記)
Codeforcesの問題文(例:CF R921 div2 D)をGoogle翻訳拡張等で翻訳しようとするとレイアウトが崩れるので、うまく翻訳してくれるブックマークレットを作ることが目標

innerHTMLをテキストで置き換えるのを検討してみる

改行が無駄に入るのと同じ数式が連続するのが邪魔
Assistive MathMLの設定がtrueだと後ろにMathMLの情報を埋め込んでしまうっぽい

https://github.com/mathjax/MathJax-a11y/issues/35

MathJaxの設定を書き換えても反映されない
typesetしなおす必要がある

https://docs.mathjax.org/en/v1.0/typeset.html

javascript: (() => {
  MathJax.Hub.Queue(
    () => {
      /* assistive MathMLの設定を切る */
      MathJax.Hub.Config({
        menuSettings: { assistiveMML: false },
      });
    },
    ["Reprocess", MathJax.Hub] /* 設定を反映して再度タイプセット */,
    () => {
      Array.prototype.forEach.call(
        /* 問題文内のp,liをテキストで置き換える */
        document.querySelector(".problem-statement").querySelectorAll("p, li"),
        (p) => {
          p.innerHTML = p.innerText;
          MathJax.Hub.Typeset(p);
        }
      );
    }
  );
})();

一応それらしい結果は得られた
ただ上・下付き文字や括線などは反映されない

coindarwcoindarw

やっぱり数式を表示したい

TeX数式がソースの中にあるのでこれを使ってみる
CFデフォルトの$$$で囲んでから翻訳し、それから再度タイプセットする

javascript: (() => {
  document.querySelectorAll('.mjx-chtml,.MathJax_Preview').forEach((elem) => {
    elem.parentNode.removeChild(elem);
  });
  document.querySelectorAll('script[type="math/tex"]').forEach((elem) => {
    const text = elem.innerText || elem.textContent;
    const newText = '$$$' + text + '$$$';
    const newElem = document.createElement('span');
    newElem.innerHTML = newText;
    elem.parentNode.replaceChild(newElem, elem);
  });
})();
javascript: (() => {
    Array.prototype.forEach.call(
      /* 問題文内のp,liをテキストで置き換える */
      document.querySelector(".problem-statement").querySelectorAll("p, li"),
      (p) => {
        p.innerHTML = p.innerText;
        MathJax.Hub.Typeset(p);
      }
    );
  }
)();

悪くはないが、うまくいかないところが多い

coindarwcoindarw

translate=”no”属性をつけて$$$で囲んでみる

javascript: (function () {
  document.querySelectorAll(".mjx-chtml,.MathJax_Preview").forEach((elem) => {
    elem.parentNode.removeChild(elem);
  });
  document.querySelectorAll('script[type="math/tex"]').forEach((elem) => {
    const text = elem.innerText || elem.textContent;
    const newText = "$$$" + text + "$$$";
    const newElem = document.createElement("span");
    newElem.setAttribute("translate", "no");
    newElem.innerHTML = newText;
    elem.parentNode.replaceChild(newElem, elem);
  });
})();
javascript: (() => {
    Array.prototype.forEach.call(
      /* 問題文内のp,liをテキストで置き換える */
      document.querySelector(".problem-statement").querySelectorAll("p, li"),
      (p) => {
        p.innerHTML = p.innerText;
        MathJax.Hub.Typeset(p);
      }
    );
  }
)();

これは駄目、そもそも翻訳がおかしい

coindarwcoindarw

$マーク3つで囲む記法だと翻訳が上手くいかないことが多い。

3つではなく1つで囲むよう変更

置き換えたspanタグにreplacedクラスを設定

javascript: (() => {
  document
    .querySelectorAll(".MathJax, .mjx-chtml, .MathJax_Preview, .MathJax_CHTML")
    .forEach((elem) => {
      elem.parentNode.removeChild(elem);
    });
  document.querySelectorAll('script[type="math/tex"]').forEach((elem) => {
    const text = elem.innerText || elem.textContent;
    const newText = "$" + text + "$";
    const newElem = document.createElement("span");
    newElem.className = "replaced";
    newElem.innerHTML = newText;
    elem.parentNode.replaceChild(newElem, elem);
  });
})();
javascript: (() => {
  MathJax.Hub.Config({
    tex2jax: {
      inlineMath: [["$", "$"]],
    },
  });
  Array.prototype.forEach.call(document.querySelectorAll(".replaced"), (p) => {
    MathJax.Hub.Typeset(p);
  });
})();

かなりうまくいく、これでよさそう

追記:上のスニペットで消すclassに.MathJaxを追加、下のスニペットでMathJax.Hub.Queueに渡す関数内で実行していたのを変更

coindarwcoindarw

1ボタンでやりたい

Google翻訳をJSから呼び出したい

https://pisuke-code.com/js-usage-of-google-trans-api/

javascript: (() => {
  const s = document.createElement("script");
  s.type = "text/javascript";
  s.src =
    "//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit";
  document.body.appendChild(s);

  window.googleTranslateElementInit = () => {
    new google.translate.TranslateElement(
      {
        pageLanguage: "en",
        layout: google.translate.TranslateElement.FloatPosition.TOP_LEFT,
        completionCallback: () => {
          console.log("done");
        },
      },
      "google_translate_element"
    );
  };
})();

これで翻訳機能を呼び出せる

coindarwcoindarw

翻訳完了のコールバックがないのでタイミングがわからない

https://stackoverflow.com/questions/12894222/google-translate-widget-translation-complete-callback

翻訳完了後のタイプセットの時間を決め打ちしたやつ。うまくいかないこともあるがボタン1回でOK

だいぶ無理やりやっているのでまともな方法があれば知りたい

javascript: (() => {
  document
    .querySelectorAll(".MathJax, .mjx-chtml, .MathJax_Preview")
    .forEach((elem) => {
      elem.parentNode.removeChild(elem);
    });
  document.querySelectorAll('script[type="math/tex"]').forEach((elem) => {
    const text = elem.innerText || elem.textContent;
    const newText = "$" + text + "$";
    const newElem = document.createElement("span");
    newElem.className = "replaced";
    newElem.innerHTML = newText;
    elem.parentNode.replaceChild(newElem, elem);
  });

  const s = document.createElement("script");
  s.type = "text/javascript";
  s.src =
    "//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit";
  document.body.appendChild(s);

  window.googleTranslateElementInit = () => {
    new google.translate.TranslateElement(
      {
        pageLanguage: "en",
        layout: google.translate.TranslateElement.FloatPosition.TOP_LEFT,
        completionCallback: () => {
          console.log("done");
        },
      },
      "google_translate_element"
    );
  };

  setTimeout(() => {
    MathJax.Hub.Config({
      tex2jax: {
        inlineMath: [["$", "$"]],
      },
    });
    Array.prototype.forEach.call(
      document.querySelectorAll(".replaced"),
      (p) => {
        MathJax.Hub.Typeset(p);
      }
    );
  }, 3000);
})();
coindarwcoindarw

かなりのゴリ押しなのでもう少しまともな方法も探したい

coindarwcoindarw

方法2の方でGoogle翻訳が上手く呼べていないことがある

coindarwcoindarw

直すところ

  • Google翻訳のところがうまく動かないことがある
  • .replacedをタイプセットしていくところでMathJax.Hub.Queueの中でTypeset呼び出してる、多分途中でいろいろ変更しているうちに別のコードと混ざった? 修正済み
  • ディスプレイ数式だと死ぬ