2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Firefoxの拡張機能でコンテキストメニューをいじってみる

Posted at

Firefoxの拡張機能を作ってみたので、作り方をまとめてみました。
この記事はFirefox 82.0.2で動作確認しています。

作成する拡張機能

ページの翻訳機能と、文章の翻訳機能を作ります。
右クリックで出るコンテキストメニューをクリックすると、翻訳ページに遷移する拡張機能を作ります。
ページ翻訳機能では、ページ全体を翻訳したページに、文章の翻訳機能は、選択した文章を翻訳したページに遷移します。

サンプルを動かす

とりあえず動かしてみるため、公式のサンプルを動かして、動作確認してみます。

下のリンクからサンプル集をクローンします。
https://github.com/mdn/webextensions-examples

サンプルは大量にあるのですが、今回はMenu APIを使うので、
その中の、menu-demoフォルダを使います。

拡張機能のデバッグ

手っ取り早く拡張機能を動かすには、拡張機能のデバッグ機能を使います。
Firefoxのアドレスバーに、about:debugging#/runtime/this-firefoxを打ち込み、デバッガを出します。
デバッガから、一時的な拡張機能 → 一時的なアドオンを読み込む を選び、ファイル選択ダイアログを出します。
ファイル選択ダイアログで、先ほど入手したmenu-demoフォルダの「manifest.json」を選び実行します。

動作確認として、ブラウザの適当なところを右クリックしてみます。
うまく動作していれば、コンテキストメニューに、Menu demoと表示されています。
表示まで確認できたら、サンプルの中身を見ていきます。

サンプルのファイルについて

サンプルのファイル構成は次のようになっています。

  • _locales
  • icons
  • sidebar
  • background.js
  • manifest.json
  • README.md

今回必要なのは、manifest.json、_locales、background.jsの3つだけです。
それぞれ何に使うのか下に書きます。

  • manifest.json
    • 拡張機能のメタデータや、他のファイルの参照を記述するファイルです。
    • 今回はメタデータ(名前など)、パーミッションを指定するために使います。
  • background.js
    • 拡張機能の処理を書くファイルです。
  • _locales
    • 拡張機能を多言語に切り替えられるように、文字列を定義するフォルダです。
    • 多言語に対応しないのであれば不要です。

#マニフェストファイルの作成
manifest.jsonには、拡張機能の名前、説明などを書くことができます。
最も重要なのはpermissionsで、APIへのアクセス権を付与します。
今回は、コンテキストメニューの追加と、タブの生成を行うので、menustabsを指定します。
iconssidebar_actionは今回は使わないので、削除します。

manifest.json
{
    "manifest_version": 2,
    "name": "__MSG_extensionName__",
    "description": "__MSG_extensionDescription__",
    "version": "1.0",
    "default_locale": "en",
    "browser_specific_settings": {
        "gecko": {
            "strict_min_version": "56.0a1"
        }
    },

    "background": {
        "scripts": ["background.js"]
    },
  
    "permissions": [
        "menus",
        "tabs"
    ]
}

スクリプトの作成

それでは実際に、スクリプトを書いて動かしてみましょう。
サンプルのbackground.jsは、大きく分けて3つの部分からできています。

  • ボタンのイベント登録
    • onCreated、onRemoved、onErrorが定義されている部分です。
    • サンプルではログへの書き込みしか行っていないので、今回は使いません。
  • メニューボタンの追加
    • browser.menus.create()が呼ばれている部分です。
    • ボタンの文字や、ボタンの種類(チェックボックスやラジオボタン)の定義をしています。
  • 処理部分
    • 上記以外の部分です。
    • メニューボタンを押した際のイベントや、クリック時の処理の実装をしています。

###メニューボタン
まずはコンテキストメニューにボタンを追加してみます。
browser.menus.create()が呼び出されているあたりを、以下に書き換えます。

background.js
// 選択範囲翻訳
browser.menus.create({
    id: "translation-selection",
    title: "選択範囲を翻訳する",
    contexts: ["selection"],
}, onCreated);

// ページ翻訳
browser.menus.create({
    id: "translation-page",
    title: "このページを翻訳する",
    contexts: ["all"],
}, onCreated);
  • id
    • ボタンのID。クリック時のイベント処理で使います。
  • title
    • ボタンの文言。
  • contexts
    • ボタンの表示される条件を指定します。(詳細)
    • allは常時表示されます。
    • selectionは選択しているものがある場合のみ表示されます。選択範囲翻訳は選択中のみ使用可能なのでこっち。

###処理の実装
次は、ボタンをクリックしたときの処理を実装していきます。

background.js
browser.menus.onClicked.addListener((info, tab) => {
    var url = "";
    switch (info.menuItemId) {
        case "translation-selection":
            url = CreateTranslationURL(info.selectionText, null);
            break;
        case "translation-page":            
            url = CreateTranslationURL(null, info.pageUrl );
            break;
    }
    OpenTranslationText(url, tab.index + 1);             // 直後のタブに生成
});

info.menuItemIdに押したボタンのIDが入っているので、switch文で各ボタンを押した際の処理に振り分けます。
今回は、ボタンに応じて、ページ翻訳 or 文章翻訳のURLを生成し、そのURLを開く処理を行っています。

URL生成はこんな感じ。
google翻訳のクエリストリングを参考に、無理やり作ってます。

CreateTranslationURL
function CreateTranslationURL(text = null, targetUrl = null){
    var isTextTranslate = text != null;
    
    // URL生成
    var url = "https://translate.google.co.jp/";
    if (!isTextTranslate){
        // ページ翻訳の場合
        url += "translate";
    }
    
    // 共通部クエリ生成
    var query = "?";
    query += "sl=auto";                               //  翻訳元言語 : 自動検出
    query += "&tl=ja";                                   //  翻訳先言語 : 日本語
    
    // テキスト翻訳orページ翻訳で固有のクエリ
    if(isTextTranslate){
        query += "&op=translate";                          // テキスト翻訳
        query += "&text=" + text;                       //  翻訳対象テキスト
    }else{
        query += "&u=" + encodeURI(targetUrl);
    }
    url += query;
    
    return url;
}

最後にタブを開く部分の処理を実装します。
tabsのAPIを使って、URLを新しいタブで開きます。

OpenTranslationText
function OpenTranslationText(url, index) {   
    browser.tabs.create({
        "url" :  url,
        "active" : true,
        "index" : index
    }).then(function(value) {
    // 非同期処理が成功した場合
        console.log('実行結果:' + value); 
    }).catch(function(value) {
        // 非同期処理が失敗した場合
        console.log('実行結果:' + value); 
    });
}
  • url
    • タブのURLです。
  • active
    • 開いたタブをアクティブにするか設定できます。
  • index
    • タブを何番目に生成するか設定できます。現在のタブの直後に生成するため、tab.index + 1を呼び出し側で指定しています。

###動作確認
ここまで実装したら、動作確認してみます。拡張機能のデバッグと同様に実行します。
以下の項目ができればOKです。

  • コンテキストメニューに「このページを翻訳する」が表示される
  • 「このページを翻訳する」をクリックすると、ページ全体を翻訳したタブが開く
  • 文字列を選択しているとき、コンテキストメニューに「選択範囲を翻訳する」が表示される
  • 「選択範囲を翻訳する」をクリックすると、選択範囲の文字列を翻訳したタブが開く

動かない場合は、デバッガから原因を特定できます。拡張機能のデバッグを参照して、デバッガを開きます。
デバッガにはデバッグ中の拡張機能が表示されます。そこの調査ボタンを押すと、拡張機能用のデベロッパーツールが表示されるので、ブレークポイント等で、調査してみてください。

#多言語対応
メニューボタンでは、言語を日本語で定義しました。このままでは、日本以外のユーザが使えないので、英語でも表示できるようにします。(詳細)

###スクリプトの多言語対応
拡張機能では、ブラウザの言語によって自動的に、対応する言語に文字列をを切り替える機能が付いています。
_localesフォルダは、各言語の文字列定義することができます。まずは日本語用の文字列を定義してみます。

_locales/ja/messages.jsonを作成し、以下のように文字列を定義します。

_locales/ja/messages.json
{
  "menuItemTranslationSelection": {
    "message": "選択範囲を翻訳する",
    "description": "選択範囲の文章を、Google翻訳で翻訳します"
  },
  
    "menuItemTranslationPage": {
    "message": "このページを翻訳する",
    "description": "このページを、Google翻訳で翻訳します"
  }
}

同じように、英語の文字列を_locales/en/messages.jsonに定義します。

_locales/en/messages.json
{
  "menuItemTranslationSelection": {
    "message": "Translate selected range ",
    "description": "Translate selected range with Google Translation"
  },
  
    "menuItemTranslationPage": {
    "message": "Translate this page",
    "description": "Translate this page with Google Translation"
  }
}

この文字列は、browser.i18n.getMessage("menuItemTranslationSelection")の形式で呼び出すことができます。
background.jsメニューボタンを、以下のように書き換えます。

background.js
// 選択範囲翻訳
browser.menus.create({
    id: "translation-selection",
    title: browser.i18n.getMessage("menuItemTranslationSelection"),
    contexts: ["selection"],
}, onCreated);

// ページ翻訳
browser.menus.create({
    id: "translation-page",
    title: browser.i18n.getMessage("menuItemTranslationPage"),
    contexts: ["all"],
}, onCreated);

変更点は、titleを文字列定義から呼び出すようにしただけです。
確認する場合は、ブラウザの言語を英語にすることで確認できます。
さらに他の言語を追加する際は、言語コードのフォルダと、messages.jsonを追加すればOKです。

###マニフェストファイルの多言語対応
manifest.jsでは、ブラウザAPIが使えないので、他の方法を使います。
manifest.js内で、__MSG_XXXXXXX__と記述すると、各言語のmessages.jsonファイルから、XXXXXXXキーと一致する文字列に置換します。

ですので、manifest.jsと、messages.jsonファイルを以下のように変更します。

manifest.json(抜粋)
    "name": "__MSG_extensionName__",
    "description": "__MSG_extensionDescription__",
_locales/ja/messages.json(抜粋)
  "extensionName": {
    "message": "Translation konjac",
    "description": ""
  },

  "extensionDescription": {
    "message": "Google翻訳へのリンクを追加する拡張機能です",
    "description": ""
  },

これで、マニフェストも他言語に対応させることができるようになります。

DEMO

Translation-konjac

参考URL

ブラウザー拡張機能

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?