tetsunosukeのnotebook

tetsunosukeのメモです

[javascript][chrome] Chromeの拡張の習作(英単語翻訳)

いい加減ここもロクに使っていないので、新年を迎えるにあたってどっかに移動しようかなとも思ったのだけど、まあそれはそれでもったいないし使うことにした。

最近社内でちょっとしたツール(ブックマークレットとか)を書いているのですが、まあ社内のツールだし、使うブラウザ限定してもいいよね?ってことで、Google Chromeを使ったいろいろを社内展開しようかなと思っています。

というわけで、ChromeのExtensionでどんなことができるのか?を調べてみました。

大雑把に使えるのは、

  • 拡張のアイコンに対して何かする(Badgeで未読の数を出すとか押したらpopupを出すとか)
  • アドレスバーに対して何かする(URLに応じて押せるボタンを変えるとか)
  • ページを読み込んで何かする(リンクを動的に書き換えるとか)
  • コンテキストメニューを拡張する
  • タブを開く
  • 裏で通信する(拡張同士とか、別のURLからデータを取るとか)
  • Desktop notification

こんな感じ。
なお、今まで作ってみていたのは、社内のグループウェアの特定画面を表示しているときに、ショートカットキーを使っていろいろ動作させる、というもの。ヘルプ機能なんかは、コンテキストメニューとか、popupとして出してもいいかもしれないなと思ってる。

で、とりあえず習作として、今まで全く使ったことがなかった、ContextMenu->Desktop Notificationを試してみた。掲題の通り、選択した文字列からコンテキストメニューを呼び出し、翻訳(Google Ajax API)を行うもの。

以下コード。

まずは、manifest.jsonを作成。外部のURLに対してのアクセスを行うため、permissionsにhttpsのURLを指定(本来はより細かく指定すべきだが手抜き)を行うのと、contextMenu, notificationsを許可しておく。

{
  "name": "English to Japanese",
  "version": "1.0",
  "background_page": "background.html",
  "permissions": [
    "notifications",
    "contextMenus",
    "https://*/*"
  ],
  "browser_action": {
      "name": "English to Japanese",
      "default_icon": "icon.png"
  }
}

background.htmlはとりあえず単純にjsを読むだけのものにしておく。

<html>
<head>
<script src="background.js">
</script>
</head>
</html>

notificationについてもhtmlできちんとレイアウトしてもよいのだが、割愛。

実際のJSのコードは以下のようにした。jQueryとか読んでおいて、$.ajaxの方が楽なのだろうけど、とりあえず流儀に則る。(非同期にする必要はあるんだかないんだか)

var google_translate_api_url = 'https://ajax.googleapis.com/ajax/services/language/translate?v=1.0';
function showTranslatedText(english) {
    url = google_translate_api_url + '&langpair=en|ja&q=' + english;
    // permissionsで外部リソースへのリクエストは許可しておかないと使えない
    var xhr = new XMLHttpRequest();
    xhr.open("GET", url, true);
    xhr.send();
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            data = JSON.parse(xhr.responseText);
            japanese = data.responseData.translatedText;

            // notificationを作成
            var notification = webkitNotifications.createNotification(
                'icon.png',     // icon url (とりあえず)
                english,        // notification のタイトル(とりあえず翻訳対象語)
                japanese        // notification の内容(翻訳結果)
            );
            // 表示。 show()だけだとユーザのアクションがないと消えない
            notification.show();
        }
    }
}
// ------------------------------------------------------------------
// context menu を作成する
var parent = chrome.contextMenus.create({
    "title": "Translate selected English to Japanese",      // コンテキストメニューに表示される文字列。日本語が使えない?
    "contexts": ["selection"],                              // allでも良いが、選択した文字列が存在するときだけにした。arrayでないといけない。
    "onclick": function(onClickData, tab) { 
        // コンテキストメニュー表示時に選択していた文字列
        english = onClickData.selectionText;
        showTranslatedText(english);
    }
});

なんか関数が分離されていない気がするが、とりあえず。