Cloud Translation API で HTMLをまるごと翻訳

前回はGoogleのCloud Translation APIの基本的な利用方法をまとめましたが、このAPIは一般的な文章だけではなく、HTMLを渡すと良い感じに翻訳してくれる機能が備わっています。

今回はHTMLを渡したときの挙動について調べてみたいと思います。

HTMLをまるっと自動翻訳

準備

基本的な設定は前回の記事をご覧ください。 blog.katsubemakito.net

ソースコード

これも前回利用した物を流用します。

const projectId = 'test-translate-k-1234567890';
const location  = 'us-central1';

// 以下にHTMLをセット
const text = `<!DOCTYPE html>
<html>
<head>
  <title>こんにちは!</title>
</head>
<body>
  <h1>こんにちは!こんにちは!</h1>
</body>
</html>`;


const {TranslationServiceClient} = require('@google-cloud/translate').v3beta1;
const translationClient = new TranslationServiceClient();
async function translateText() {
  const request = {
    parent: translationClient.locationPath(projectId, location),
    contents: [text],
    mimeType: 'text/html',         // mime types: text/plain, text/html
    sourceLanguageCode: 'ja_JP',  // 日本語から
    targetLanguageCode: 'en_US',  // 英語に翻訳
  };

  // Run request
  const [response] = await translationClient.translateText(request);

  for (const translation of response.translations) {
    console.log(translation.translatedText);
  }
}

translateText();

前回と異なる点は連想配列requestのmimeTypetext/htmlに変更した点です。

const request = {
  ...
  mimeType: 'text/html', // mime types: text/plain, text/html
  ...
};

またES2015からバッククォートを利用するとテンプレート機能が使えるわけですが、これ内部で改行することが出来るのです。つまり他のスクリプト言語でいうヒアドキュメント的な書き方が可能になります。

// これは文法的に正しい
const text = `<!DOCTYPE html>
<html>
<head>
  <title>こんにちは!</title>
</head>
<body>
  <h1>こんにちは!こんにちは!</h1>
</body>
</html>`;

正式にヒアドキュメントが実装されることを祈ってやみませんw 実行時にパースの処理が重くなっちゃうのでやらないんだろうなぁ……。

実行してみる

上記のコードを実行すると次のような結果が返ってきます。日本語だった部分がしっかり英語になっているのがわかりますね。

$ node index.js
<!DOCTYPE html><html><head><title> Hello! </title></head><body><h1> Hello! Hello! </h1></body></html>

注意点としては以下です。

  • HTMLの部分も文字数としてカウントされる(=課金対象)
  • レスポンスでは余分な改行やタブなどは削除される

Webページをまるっと翻訳する際に、Google先生にすべて託した方が楽ちんではありますが、まるっと課金されてしまいます。とはいえ1箇所づつ抜き出して差し替える処理をするのも面倒なので、どちらを取るかは設計時に考えておく必要がありそうです。

挙動を確認する

ヘッド - head,title,meta

headタグ内で良く見かける物を翻訳してみます。

<head>
  <title>夏目漱石 | 小説のページ</title>
  <meta name="description" content="夏目漱石の「吾輩は猫である」を掲載">
  <meta name="keywords" content="夏目漱石,吾輩は猫である,文学,小説">
  <meta name="author" content="夏目漱石">

  <meta property="og:title" content="夏目漱石 | 小説のページ">
  <meta property="og:description" content="夏目漱石の「吾輩は猫である」を掲載">
  <meta property="og:site_name" content="小説のページ">
</head>

実行結果は以下の通り。

<head><title> Soseki Natsume | Novels Page </title><meta name="description" content="Natsume Soseki&#39;s “I am a cat”"><meta name="keywords" content="Soseki Natsume, niece is a cat, literature, novel"><meta name="author" content="Natsume Soseki"><meta property="og:title" content="Soseki Natsume | Novels Page"><meta property="og:description" content="Natsume Soseki&#39;s “I am a cat”"><meta property="og:site_name" content="小説のページ"></head>
  • titleタグはもちろん変換される
  • metaタグも翻訳対象
    • ただし翻訳されるmetaとされないmetaがある

見出し・段落 - h1,p

body内に記述する基本的なタグですね。

<section>
  <h1>吾輩は猫である</h1>
  <p>吾輩は猫である。名前はまだ無い。</p>
</section>

実行結果です。これはイメージ通りではないでしょうか?

<section><h1> I am a cat </h1><p> I am a cat. There is no name yet. </p></section>

リンク - a

2行目はわざとURLエンコードせずに書きました。

<a href="/" title="トップページ">トップページ</a>
<a href="/q?search=パンダ">検索</a>

実行結果です。被リンク文字列はもちろん、title属性も翻訳されますね。ただしhref属性はノータッチのようです。

<a href="/" title="top page">Top page</a> <a href="/q?search=パンダ">search</a>

画像 - img

img要素で日本語を使うのは主にalt属性でしょうか。

<img src="xxx.png" alt="パンダ">

実行結果です。バッチリ変わってますね。

<img src="xxx.png" alt="Panda">

ルビ - ruby

難読漢字や中二病的なセリフの上に乗せるルビ(よみがな)です。

<p><ruby>吾輩<rt>わがはい</rt></ruby><ruby><rt>ねこ</rt></ruby>である。名前はまだ無い。</p>

実行結果を見ると翻訳してくれてはいますが、ちょっと不自然ですね。漢字で「吾輩」は読みづらいですが、英訳するとシンプルに「I」なので、わざわざルビが振ってあると特別な意味があると捉えられてしまいそう。ルビはGoogle先生に渡す前に削除しておいても良いかもしれません。

<p><ruby> I <rt> My yes </rt></ruby> Is <ruby> Cat <rt> Cat </rt></ruby> It is. There is no name yet. </p>

引用 - blockquote

引用文をまるっと指定する際のblockquote。

<blockquote>吾輩は猫である。名前はまだ無い。</blockquote>

容赦なく翻訳されます。

<blockquote> I am a cat. There is no name yet. </blockquote>

整形済みテキスト - pre

こいつは半角スペースや改行が特別な意味を保つ場合があるので余計なことはしないで欲しいところですが…。

<pre>
1) 柑橘類
  ・みかん
  ・伊予柑
  ・オレンジ
      - バレンシアオレンジ
      - ブラッドオレンジ
  </pre>

実行結果です。ってなんだこりゃ!うーん、preタグは鬼門のようですね。

<pre>
1) Citrus, tangerines, Iyokan, orange-Valencia orange-Blood orange </pre>

プログラム - code

プログラムを掲載する時に使うcodeタグですが、これはどうなるでしょう?

<code>
  /**
   * メイン関数
   */
  int main(){
    printf("こんにちは!こんにちは!");
  }
</code>

実行結果です。翻訳もされていませんし、改行やスペースもそのままですね。

<code>
  /**
   * メイン関数
   */
  int main(){
    printf("こんにちは!こんにちは!");
  }
</code>

CSS - style

スタイルシートはどうでしょう?ここは通常触って欲しくない部分ですね。

<style>
  header{
    border: 1px solid gray;  /* 線を引く */
  }
  h1:before{
    content: "超";  /* タイトルの先頭に「超」を付加 */
  }
</style>

実行結果は以下の通り。まったく同じ状態で返ってきました。styleタグは丸ごとスキップされるようです。

<style>
  header{
    border: 1px solid gray;  /* 線を引く */
  }
  h1:before{
    content: "超";  /* タイトルの先頭に「超」を付加 */
  }
</style>

JavaScript - script

CSSに続きこれも触ってほしくない箇所。

<script>
window.onload = () => {
  const message = "こんにちは!";
  alert(message + "いらっしゃいませ!");
}
</script>

実行結果は以下の様になりました。これも丸ごとスキップされました。良かったw

<script>
window.onload = () => {
  const message = "こんにちは!";
  alert(message + "いらっしゃいませ!");
}
</script>

ただ逆に言えば、例えばJSON形式で保存されている文章や、エラーメッセージなどを翻訳したい場合はHTMLとしてではなくテキスト形式で渡す必要がありそうですね。

参考ページ