Google Slides の翻訳アドオンを Internal apps として Private 公開する

# 目的

- [Google Slides を翻訳する Google App Script - Qiita](https://qiita.com/khayama/items/e3b3b84d7c643a79b303)

上記の記事で作成した Google App Script を、アドオンとして Google Workspace Marketplace に Private 公開します。

# 参考リンク

- [Google Spreadsheet用の組織内アドオンを作成する【GAS】 🌴 officeの杜 🥥](https://officeforest.org/wp/2022/12/24/google-spreadsheet%E7%94%A8%E3%81%AE%E7%B5%84%E7%B9%94%E5%86%85%E3%82%A2%E3%83%89%E3%82%AA%E3%83%B3%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%E3%80%90gas%E3%80%91/)

こちらの記事がとても参考になりました。

以下に引っかかった部分について、記載します。

# `appsscript.json` 

- `urlFetchWhitelist`
    - DeepL の API を呼ぶために `https://api-free.deepl.com/` を明示して追加する必要があります。
- `oauthScopes`
    - 現在開いている Google Slides の操作に`presentations.currentonly` が必要です。
    - DeepL の API を呼ぶために `script.external_request` が必要です
- `addOns.common`
    - `name` と `logoUrl` （サイドバーに表示される画像）が必須フィールドとして必要です。
    - [AddOns manifest resource  |  Apps Script  |  Google for Developers](https://developers.google.com/apps-script/manifest/addons#common)
- `homepageTrigger`
    - カードビューが表示されるように、`Code.gs` 内で定義した `onHomePage` 関数を指定する必要があります。

```json:appsscript.json
{
  "timeZone": "Asia/Tokyo",
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8",
  "urlFetchWhitelist": [
    "https://api-free.deepl.com/v2/translate"
  ],
  "oauthScopes": [
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/presentations.currentonly"
  ],
  "addOns": {
    "common": {
      "name": "slidesToJapanese",
      "logoUrl": "https://3.bp.blogspot.com/-a2XrpxvR3L0/VXOUPsoa7UI/AAAAAAAAuI8/iUkVw_GYrJk/s400/hata_kokki_flag_japan.png"
    },
    "slides": {
      "homepageTrigger": {
        "runFunction": "onHomePage",
        "enabled": true
      }
    }
  }
}
```

# `Code.gs` 

- [Get team member details in Google Workspace  |  Apps Script  |  Google for Developers](https://developers.google.com/apps-script/add-ons/teams-addon-sample#code.gs)

上記の記事を参考にして、以下の内容を追加しました。

- `onOpen` トリガーによるメニュー追加
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/6c7c47b3-a83e-ae3c-f77e-d9fe4c70f713.png)
    - ※ [`onInstall`](https://developers.google.com/apps-script/guides/triggers#oninstalle) は、Google Workspace Marketplace のアドオンには使用できない
      - > The trigger won't run when a user installs the add-on from the Google Workspace Marketplace
- `onHomePage` によるサイドバーメニュー表示
    - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/05c943c5-a440-ab01-72b5-a9098b11ca85.png)


```javascript
function onOpen(e) {
  var ui = SlidesApp.getUi()
  var menu = ui.createAddonMenu() // メニューの追加、（セルを結合した表が一つでもあると、処理が行われません。）
  menu
  .addItem('[全スライド]DeepL翻訳(英>日)', 'translateAllDeepL')
  .addItem('[特定ページ]DeepL翻訳(英>日)','specifiedPageTranslateDeepL')
  .addItem('[全スライド]Google翻訳(英>日)', 'translateAll')
  .addItem('[特定ページ]Google翻訳(英>日)','specifiedPageTranslate')
  .addToUi();  
}

function buildSearchCard(opt_error) {
  var banner = CardService.newImage()
  .setImageUrl('https://2.bp.blogspot.com/-8-ypfalviWA/WjCryBf7m9I/AAAAAAABIx4/3VAOGejdWogMnchjAO_F2rJG-ZeOmWJEQCLcBGAs/s400/building_nihongo_gakkou.png');

  var ontranslateAllDeepLAction = CardService.newAction()
  .setFunctionName("translateAllDeepL")
  .setLoadIndicator(CardService.LoadIndicator.SPINNER);

  var translateAllDeepLButton = CardService.newTextButton()
  .setText("[全スライド]DeepL翻訳(英>日)")
  .setOnClickAction(ontranslateAllDeepLAction);

  var onspecifiedPageTranslateDeepLAction = CardService.newAction()
  .setFunctionName("specifiedPageTranslateDeepL")
  .setLoadIndicator(CardService.LoadIndicator.SPINNER);

  var specifiedPageTranslateDeepLButton = CardService.newTextButton()
  .setText("[特定ページ]DeepL翻訳(英>日)")
  .setOnClickAction(onspecifiedPageTranslateDeepLAction);

  var ontranslateAllAction = CardService.newAction()
  .setFunctionName("translateAll")
  .setLoadIndicator(CardService.LoadIndicator.SPINNER);

  var translateAllButton = CardService.newTextButton()
  .setText("[全スライド]Google翻訳(英>日)")
  .setOnClickAction(ontranslateAllAction);

  var onspecifiedPageTranslateAction = CardService.newAction()
  .setFunctionName("specifiedPageTranslate")
  .setLoadIndicator(CardService.LoadIndicator.SPINNER);

  var specifiedPageTranslateButton = CardService.newTextButton()
  .setText("[特定ページ]Google翻訳(英>日)")
  .setOnClickAction(onspecifiedPageTranslateAction);

  var section = CardService.newCardSection()
  .addWidget(banner)
  .addWidget(translateAllDeepLButton)
  .addWidget(specifiedPageTranslateDeepLButton)
  .addWidget(translateAllButton)
  .addWidget(specifiedPageTranslateButton);

  if (opt_error) {
    var message = CardService.newTextParagraph()
    .setText("Note: " + opt_error);
    section.addWidget(message);
  }

  return CardService.newCardBuilder()
  .addSection(section)
  .build();
}

function onHomePage() {
  var card = buildSearchCard();
  return [card];
}
```

# アドオンの更新
New deployment 時のバージョンと Deployment ID を使います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/a7df8ce3-e200-6456-c2c0-3095827553a2.png)

以下のリンクから「App Configuration」の設定を変更します。

- https://console.cloud.google.com/apis/api/appsmarket-component.googleapis.com/googleapps_sdk

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/71148bcb-c315-b3e6-2c8c-9f9d23eb7f69.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/a319b7cc-24ad-61e5-a91e-c767be5b8acc.png)

# 公開できた！
1つのアドオンを社内公開するのに、1つのプロジェクトを使ったり、いろいろと設定しなければならない項目はありましたが、何とか形にできました。
自分の App Script をそのまま展開するより、アドオンとして社内展開できるとその恩恵を享受できるユーザ層も広がりそうでいいですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/101361/2e9217f4-ef0d-8189-34e7-17338247aff0.png)


# 参考：コード内容

GitHub に置いておきました

- [kyouheicf/slidesToJapanese](https://github.com/kyouheicf/slidesToJapanese/tree/main)

# その他参考リンク

- [Google Workspace Addon を作成し、社内アプリとして展開する方法 - Link and Motivation Developers' Blog](https://link-and-motivation.hatenablog.com/entry/2023/07/21/120000)
- [Apps Scriptではじめる🤖Google Chatアプリ開発ガイド（ユーザー認証編） - BIGLOBE Style ｜ BIGLOBEの「はたらく人」と「トガッた技術」](https://style.biglobe.co.jp/entry/2023/08/30/100000)