Google関連

Google Docs用アドオンを作成する。

Google Docs用アドオンストアがオープン、表計算や文書作成に新機能を追加可能に」にあるように、Google ドキュメントの文書とスプレッドシートに機能を追加・拡張する「アドオン」を公開するためのプラットフォーム、「アドオンストア」がオープンしました。

このアドオンは一般の開発者もGoogle Apps Scriptを使って簡単に開発できるとのことなので、早速試してみました。

  1. Google ドキュメントで文書を新規作成します。
  2. ツール」メニューから「スクリプト エディタ」をクリックします。
  3. GoogleDocsAddOn_01_01

  4. ようこそ画面(welcome screen)が表示されるので「空のプロジェクト」をクリックします。
  5. GoogleDocsAddOn_01_02

  6. 最初に表示されるコードをすべて選択して削除します。
  7. GoogleDocsAddOn_01_03

  8. 下記コードを貼りつけます。
  9. /**
     * Creates a menu entry in the Google Docs UI when the document is opened.
     */
    function onOpen() {
      DocumentApp.getUi().createAddonMenu()
          .addItem('Start', 'showSidebar')
          .addToUi();
    }
    
    /**
     * Runs when the add-on is installed.
     */
    function onInstall() {
      onOpen();
    }
    
    /**
     * Opens a sidebar in the document containing the add-on's user interface.
     */
    function showSidebar() {
      var ui = HtmlService.createHtmlOutputFromFile('Sidebar')
          .setTitle('Translate');
      DocumentApp.getUi().showSidebar(ui);
    }
    
    /**
     * Gets the text the user has selected. If there is no selection,
     * this function displays an error message.
     *
     * @return {Array.<string>} The selected text.
     */
    function getSelectedText() {
      var selection = DocumentApp.getActiveDocument().getSelection();
      if (selection) {
        var text = [];
        var elements = selection.getSelectedElements();
        for (var i = 0; i < elements.length; i++) {
          if (elements[i].isPartial()) {
            var element = elements[i].getElement().asText();
            var startIndex = elements[i].getStartOffset();
            var endIndex = elements[i].getEndOffsetInclusive();
    
            text.push(element.getText().substring(startIndex, endIndex + 1));
          } else {
            var element = elements[i].getElement();
            // Only translate elements that can be edited as text; skip images and
            // other non-text elements.
            if (element.editAsText) {
              var elementText = element.asText().getText();
              // This check is necessary to exclude images, which return a blank
              // text element.
              if (elementText != '') {
                text.push(elementText);
              }
            }
          }
        }
        if (text.length == 0) {
          throw 'Please select some text.';
        }
        return text;
      } else {
        throw 'Please select some text.';
      }
    }
    
    /**
     * Gets the stored user preferences for the origin and destination languages,
     * if they exist.
     *
     * @return {Object} The user's origin and destination language preferences, if
     *     they exist.
     */
    function getPreferences() {
      var userProperties = PropertiesService.getUserProperties();
      var languagePrefs = {
        originLang: userProperties.getProperty('originLang'),
        destLang: userProperties.getProperty('destLang')
      };
      return languagePrefs;
    }
    
    /**
     * Gets the user-selected text and translates it from the origin language to the
     * destination language. The languages are notated by their two-letter short
     * form. For example, English is 'en', and Spanish is 'es'. The origin language
     * may be specified as an empty string to indicate that Google Translate should
     * auto-detect the language.
     *
     * @param {string} origin The two-letter short form for the origin language.
     * @param {string} dest The two-letter short form for the destination language.
     * @param {boolean} savePrefs Whether to save the origin and destination
     *     language preferences.
     * @return {string} The result of the translation.
     */
    function runTranslation(origin, dest, savePrefs) {
      var text = getSelectedText();
      if (savePrefs == true) {
        var userProperties = PropertiesService.getUserProperties();
        userProperties.setProperty('originLang', origin);
        userProperties.setProperty('destLang', dest);
      }
    
      var translated = [];
      for (var i = 0; i < text.length; i++) {
        translated.push(LanguageApp.translate(text[i], origin, dest));
      }
    
      return translated.join('\n');
    }
    
    /**
     * Replaces the text of the current selection with the provided text, or
     * inserts text at the current cursor location. (There will always be either
     * a selection or a cursor.) If multiple elements are selected, only inserts the
     * translated text in the first element that can contain text and removes the
     * other elements.
     *
     * @param {string} newText The text with which to replace the current selection.
     */
    function insertText(newText) {
      var selection = DocumentApp.getActiveDocument().getSelection();
      if (selection) {
        var replaced = false;
        var elements = selection.getSelectedElements();
        if (elements.length == 1 &&
            elements[0].getElement().getType() ==
            DocumentApp.ElementType.INLINE_IMAGE) {
          throw "Can't insert text into an image.";
        }
        for (var i = 0; i < elements.length; i++) {
          if (elements[i].isPartial()) {
            var element = elements[i].getElement().asText();
            var startIndex = elements[i].getStartOffset();
            var endIndex = elements[i].getEndOffsetInclusive();
    
            var remainingText = element.getText().substring(endIndex + 1);
            element.deleteText(startIndex, endIndex);
            if (!replaced) {
              element.insertText(startIndex, newText);
              replaced = true;
            } else {
              // This block handles a selection that ends with a partial element. We
              // want to copy this partial text to the previous element so we don't
              // have a line-break before the last partial.
              var parent = element.getParent();
              parent.getPreviousSibling().asText().appendText(remainingText);
              // We cannot remove the last paragraph of a doc. If this is the case,
              // just remove the text within the last paragraph instead.
              if (parent.getNextSibling()) {
                parent.removeFromParent();
              } else {
                element.removeFromParent();
              }
            }
          } else {
            var element = elements[i].getElement();
            if (!replaced && element.editAsText) {
              // Only translate elements that can be edited as text, removing other
              // elements.
              element.clear();
              element.asText().setText(newText);
              replaced = true;
            } else {
              // We cannot remove the last paragraph of a doc. If this is the case,
              // just clear the element.
              if (element.getNextSibling()) {
                element.removeFromParent();
              } else {
                element.clear();
              }
            }
          }
        }
      } else {
        var cursor = DocumentApp.getActiveDocument().getCursor();
        var surroundingText = cursor.getSurroundingText().getText();
        var surroundingTextOffset = cursor.getSurroundingTextOffset();
    
        // If the cursor follows or preceds a non-space character, insert a space
        // between the character and the translation. Otherwise, just insert the
        // translation.
        if (surroundingTextOffset > 0) {
          if (surroundingText.charAt(surroundingTextOffset - 1) != ' ') {
            newText = ' ' + newText;
          }
        }
        if (surroundingTextOffset < surroundingText.length) {
          if (surroundingText.charAt(surroundingTextOffset) != ' ') {
            newText += ' ';
          }
        }
        cursor.insertText(newText);
      }
    }

    GoogleDocsAddOn_01_04

  10. ファイル」メニューの「新規作成」から「HTMLファイル」をクリックします。
  11. GoogleDocsAddOn_01_05

  12. ファイルを作成ダイアログでファイル名を「Sidebar」として、「OK」ボタンをクリックします。
  13. GoogleDocsAddOn_01_06

  14. Sidebar.htmlが表示されるので、コードをすべて選択して削除します。
  15. GoogleDocsAddOn_01_07

  16. 下記コードを貼りつけます。
  17. <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
    <!-- The CSS package above applies Google styling to buttons and other elements. -->
    
    <style>
    .branding-below {
      bottom: 56px;
      top: 0;
    }
    
    .branding-text {
      left: 7px;
      position: relative;
      top: 3px;
    }
    
    .col-contain {
      overflow: hidden;
    }
    
    .col-one {
      float: left;
      width: 50%;
    }
    
    .logo {
      vertical-align: middle;
    }
    
    .radio-spacer {
      height: 20px;
    }
    
    .width-100 {
      width: 100%;
    }
    </style>
    
    <div class="sidebar branding-below">
      <form>
        <div class="block col-contain">
          <div class="col-one">
            <b>Selected text</b>
            <div>
              <input type="radio" name="origin" id="radio-origin-auto" value="" checked="checked">
              <label for="radio-origin-auto">Auto-detect</label>
            </div>
            <div>
              <input type="radio" name="origin" id="radio-origin-en" value="en">
              <label for="radio-origin-en">English</label>
            </div>
            <div>
              <input type="radio" name="origin" id="radio-origin-fr" value="fr">
              <label for="radio-origin-fr">French</label>
            </div>
            <div>
              <input type="radio" name="origin" id="radio-origin-de" value="de">
              <label for="radio-origin-de">German</label>
            </div>
            <div>
              <input type="radio" name="origin" id="radio-origin-ja" value="ja">
              <label for="radio-origin-ja">Japanese</label>
            </div>
            <div>
              <input type="radio" name="origin" id="radio-origin-es" value="es">
              <label for="radio-origin-es">Spanish</label>
            </div>
          </div>
          <div>
            <b>Translate into</b>
            <div class="radio-spacer">
            </div>
            <div>
              <input type="radio" name="dest" id="radio-dest-en" value="en">
              <label for="radio-dest-en">English</label>
            </div>
            <div>
              <input type="radio" name="dest" id="radio-dest-fr" value="fr">
              <label for="radio-dest-fr">French</label>
            </div>
            <div>
              <input type="radio" name="dest" id="radio-dest-de" value="de">
              <label for="radio-dest-de">German</label>
            </div>
            <div>
              <input type="radio" name="dest" id="radio-dest-ja" value="ja" checked="checked">
              <label for="radio-dest-ja">Japanese</label>
            </div>
            <div>
              <input type="radio" name="dest" id="radio-dest-es" value="es">
              <label for="radio-dest-es">Spanish</label>
            </div>
          </div>
        </div>
    
        <div class="block form-group">
          <label for="translated-text"><b>Translation</b></label>
          <textarea class="width-100" id="translated-text" rows="10"></textarea>
        </div>
    
        <div class="block">
          <input type="checkbox" id="save-prefs">
          <label for="save-prefs">Use these languages by default</label>
        </div>
    
       <div class="block" id="button-bar">
          <button class="blue" id="run-translation">Translate</button>
          <button id="insert-text">Insert</button>
        </div>
      </form>
    </div>
    
    <div class="sidebar bottom">
      <img alt="Add-on logo" class="logo" width="27" height="27"
          src="https://googledrive.com/host/0B0G1UdyJGrY6XzdjQWF4a1JYY1k/translate-logo-small.png">
      <span class="gray branding-text">Translate sample by Google</span>
    </div>
    
    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
    </script>
    <script>
      /**
       * On document load, assign click handlers to each button and try to load the
       * user's origin and destination language preferences if previously set.
       */
      $(function() {
        $('#run-translation').click(runTranslation);
        $('#insert-text').click(insertText);
        google.script.run.withSuccessHandler(loadPreferences)
            .withFailureHandler(showError).getPreferences();
      });
    
      /**
       * Callback function that populates the origin and destination selection
       * boxes with user preferences from the server.
       *
       * @param {Object} languagePrefs The saved origin and destination languages.
       */
      function loadPreferences(languagePrefs) {
        $('input:radio[name="origin"]')
            .filter('[value=' + languagePrefs.originLang + ']')
            .attr('checked', true);
        $('input:radio[name="dest"]')
            .filter('[value=' + languagePrefs.destLang + ']')
            .attr('checked', true);
      }
    
      /**
       * Runs a server-side function to translate the user-selected text and update
       * the sidebar UI with the resulting translation.
       */
      function runTranslation() {
        this.disabled = true;
        $('#error').remove();
        var origin = $('input[name=origin]:checked').val();
        var dest = $('input[name=dest]:checked').val();
        var savePrefs = $('#save-prefs').is(':checked');
        google.script.run
            .withSuccessHandler(
              function(translatedText, element) {
                $('#translated-text').val(translatedText);
                element.disabled = false;
              })
            .withFailureHandler(
              function(msg, element) {
                showError(msg, $('#button-bar'));
                element.disabled = false;
              })
            .withUserObject(this)
            .runTranslation(origin, dest, savePrefs);
      }
    
      /**
       * Runs a server-side function to insert the translated text into the document
       * at the user's cursor or selection.
       */
      function insertText() {
        this.disabled = true;
        $('#error').remove();
        google.script.run
            .withSuccessHandler(
              function(returnSuccess, element) {
                element.disabled = false;
              })
            .withFailureHandler(
              function(msg, element) {
                showError(msg, $('#button-bar'));
                element.disabled = false;
              })
            .withUserObject(this)
            .insertText($('#translated-text').val());
      }
    
      /**
       * Inserts a div that contains an error message after a given element.
       *
       * @param msg The error message to display.
       * @param element The element after which to display the error.
       */
      function showError(msg, element) {
        var div = $('<div id="error" class="error">' + msg + '</div>');
        $(element).after(div);
      }
    </script>

    GoogleDocsAddOn_01_08

  18. ファイル」メニューから「すべてを保存」をクリックします。
  19. GoogleDocsAddOn_01_09

  20. プロジェクト名を変更ダイアログでプロジェクト名を「Translate Quickstart」として、「OK」ボタンをクリックします。
  21. GoogleDocsAddOn_01_10

  22. スクリプト エディタを終了し、1.で作成した文書も一度閉じます。
  23. 12.で閉じた文書を再度開くと「アドオン」メニューに「Translate Quickstart」が追加されていることが確認できます。
  24. GoogleDocsAddOn_01_11

  25. アドオン」メニューの「Translate Quickstart」から「Start」をクリックします。
  26. GoogleDocsAddOn_01_12

  27. 承認画面が表示されたら「続行」ボタンをクリックし、続いて表示されるウィンドウで「承認する」ボタンをクリックします。
  28. GoogleDocsAddOn_01_13

    GoogleDocsAddOn_01_14

  29. Google ドキュメントの画面右側に「Translate」が表示されることが確認できます。
  30. GoogleDocsAddOn_01_15

  31. 文書中の文字列を選択後、Translate上で言語を選び「Translate」ボタンをクリックすると、テキストエリアに翻訳された文字列が表示されます。
  32. GoogleDocsAddOn_01_16

  33. さらに「Insert」ボタンをクリックすることで、テキストエリアの文字列を文書に挿入することができます。
  34. GoogleDocsAddOn_01_17

以上の手順で、自分でアドオンを作成・実行することができます。
上記手順は、「Quickstart: Add-on for Google Docs」に載っている手順に画像を付け足しただけですが、おおよその概要は掴めるかと思います。

作成したアドオンをストアで公開するには、審査にパスする必要があるようです。詳しくは下記ページをご参照ください。

・Publishing an Add-on – Google Apps Script – Google Developers
https://developers.google.com/apps-script/add-ons/publish

しかしながらこの機能、当ブログで取り扱っている、Microsoft Officeの「Office 用アプリ」にそっくりですね!
今後も要注目の機能です。

■ 関連Webページ

・Google Developers Blog: Building Sheets and Docs Add-ons
http://googledevelopers.blogspot.jp/2014/03/building-sheets-and-docs-add-ons.html
・Google Apps Script – Google Developers
https://developers.google.com/apps-script/add-ons/

ExcelのWebクエリからのアクセス情報前のページ

[Google Apps Script]メニューの追加と確認ダイアログの表示次のページ

関連記事

  1. Google関連

    [Google Apps Script]郵便番号から住所を取得する自作関数と住所から地図画像のURL…

    郵便番号検索APIを使って郵便番号から住所を取得する自作関数と、Sta…

  2. Office関連

    Google スライドで新規プレゼンテーションを作成するVBAマクロ

    ここ数日PowerPointのマクロに加え、Google Apps S…

  3. Office関連

    Outlookを使ってGmail送信を行うVBAマクロ

    下記G Suite アップデート ブログにある通り、今年の6月には“安…

  4. Google関連

    Google AdSenseで「PC のパフォーマンスが低下しています」を表示しないようにする。

    下記のサイトでも話題になっていますが、Google AdSenseの怪…

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

Time limit is exhausted. Please reload CAPTCHA.

※本ページはプロモーションが含まれています。

Translate

最近の記事

アーカイブ

PAGE TOP