Slackで1クリック翻訳できるようにして英語ネイティブメンバーとのコミュニケーションを捗らせた話

## はじめに

この記事は [CrowdWorks Advent Calendar 2020](https://qiita.com/advent-calendar/2020/crowdworks) の20日目の記事です。


初めまして。
株式会社クラウドワークスの社内ネットワーク保守やヘルプデスクを担当しているr_semeです。

この記事では、社内で使われているSlackの翻訳Botを作成する手順を紹介していきます。
<img width="600" alt="完成したもの.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/b1dc213e-87af-2596-9042-80625221055e.gif">

## 背景
クラウドワークスでは、コミュニケーションツールとしてSlackを利用しています。（ワークスペース全体で一日約9000件のPostがあります！）
業務委託のパートナーさん含め約300名いるメンバーのほとんどが日本語ネイティブで、Postされるメッセージも日本語が主となっています。
英語ネイティブのメンバーも約4%在籍していて、その人達はお知らせチャンネルや日々のやり取りをGoogle翻訳等の翻訳ツールを利用してコミュニケーションを取っている状態でした。
そこでヒアリングを実施したところ、以下のような課題感があることがわかりました。

- 日本語の長文は読むのに時間がかかってしまうので、翻訳ツールが必要
- 何度もWebブラウザとSlack間を行き来するのが大変なので、Slack上で翻訳出来るようにしたい
- 無料のSlack Appでは翻訳文字数に制限があるため、使いづらい

→これらの課題感を解決する為、Google Apps Scriptの[LanguageApp](https://developers.google.com/apps-script/reference/language/language-app) というクラスを用いたSlackの翻訳Botを作成することになりました。


## 必要なもの
- Node.jsアプリケーションが動かせる環境（今回は[Glitch](https://glitch.com/)を使用しています）
- Slackワークスペース
- Google Apps Script

## 準備

## Webアプリケーションを作成する

Slack上のイベントを拾うためのWebアプリを用意します。
※Glitchを使うことを前提に進めていきますので、他のサービスを利用する場合は適宜読み替えて設定いただければと思います。

### Glitchアカウントを作成する　
[こちら](https://glitch.happyfox.com/kb/article/35-how-do-i-create-an-account-on-glitch/)を参考に、Glitchアカウントを作成します。

### プロジェクトをRemixして自分用のWebアプリを作成する

[用意したGlitchプロジェクト](https://glitch.com/edit/#!/remix/smooth-brassy-child)を開き、「Remix Project」 をクリックします。
リミックスを行うことでプロジェクトのコピーが作成され、自分のプロジェクトとして編集が行えるようになります。
<img width="500" alt="リミックス作成1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/70a876aa-774a-91cb-66e7-fe41be91df12.png">
<img width="500" alt="リミックス作成2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/7e26ca98-9609-fa96-b03e-1f095d871e3e.png">
※リミックスしたプロジェクト名はSlack app作成時に使うのでメモしておくと良いです。
<img width="500" alt="リミックス完了！.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/48a541b1-87c2-d15d-dab2-4396fa3aa45d.png">

## Slackの設定

###  Slack Appを作成する
https://api.slack.com/apps/ を開いて、 Create New Appボタンをクリックします。

<img width="500" alt="createNewApp.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/464f2e0f-0a98-4696-42ae-efc905763468.png">
アプリ名とデプロイするSlackワークスペースを入力して、Create Appボタンをクリックします。
※アプリ名は後から変更できますが、デプロイ先は変更できないのでご注意ください。
<img width="500" alt="createNewApp.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/435d4e65-40b5-8665-7ddd-0728719f755a.png">

### Slack Appの設定

Slack Appの作成が完了したら、次に各種設定を行います。

### スコープを追加する

画面左の `Features` から、「OAuth & Permissions」 をクリックします。
<img width="500" alt="createNewApp.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/9426d911-8c49-d577-1bb5-28cc3496e474.png">

Scopes の項目までスクロールして、「Bot Token Scopes」に以下のスコープを追加します。
<img width="500" alt="createNewApp.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/962ab676-f10d-e18c-5ba4-93efd44c6f4e.png">


**chat:write**

追加されたチャンネルやダイレクトメッセージに対する書き込みを許可します。

**reactions:read**

ワークスペース上で付けられたreactionの履歴を取得します。

**channels:read**

ワークスペース上にあるパブリックチャンネルの情報を取得します。


**history系のスコープ**
翻訳Botが追加されたチャンネルやダイレクトメッセージの情報を取得します。

**channels:history**

**groups:history**

**im:history**

**mpim:history**



### Slack Appの名前を設定する

スコープの設定が完了したら、ワークスペース上のSlack Appの表示名とメンション名を設定します。

画面左の `Features` から、App Home をクリックして、App Display Name の横にある「Edit」ボタンをクリックします。
<img width="500" alt="createNewApp.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/48b10986-82a2-1658-1ec9-d93a0f70d945.png">

Display Nameにワークスペース上で表示名と、Default usernameにメンション名を設定して、「Add」ボタンをクリックします。
<img width="500" alt="createNewApp.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/356a2979-6735-e4db-5d85-a9636a8436e2.png">



### Slack App をワークスペースにインストールする

スコープの設定と表示名、メンション名の設定が完了したら、ワークスペースにSlack App をインストールします。

画面左の項目からInstall App を選択するか、Basic Information を開き、Install your appを展開して表示される「Install to Workspace」 をクリックします。
<img width="500" alt="アプリをワークスペースにインストール1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/64e193a2-61f8-190e-cd3a-d86f81ed79a6.png">
確認画面に移動するので、「許可する」ボタンをクリックします。
<img width="500" alt="アプリをワークスペースにインストール2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/4d6f3428-baa9-090c-4ef5-7bbe30b6646a.png">


### Event Subscriptionsを有効化する
「Bot User OAuth Access Token」と、「Signing Secret」をコピーします。
※「Bot User OAuth Access Token」はOAuth & Permissions から、「Signing Secret」はBasic information から確認できます。
<img width="500" alt="Bot User OAuth Access Tokenの確認方法.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/19d6e11a-ba23-449d-30f6-c464529232a4.png">
<img width="500" alt="Event Subscriptions設定2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/0c8f3c1e-61e3-4330-952a-2f4654215666.png">
リミックスしたGlitchプロジェクトに戻り、 `.env` ファイルにそれぞれコピーした資格情報を入力します。
<img width="500" alt=".envファイルに資格情報を入力する.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/ea53bf92-fac9-6901-9398-e39e12cf7c02.png">
Slack appの設定画面に戻り、画面左もしくはBasic Informationから「Event Subscriptions」をクリックします。
<img width="500" alt="Event Subscriptionsにアクセス.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/016fd12d-ef04-d885-41b5-1c5525b7d58b.png">
Enable Events を有効化して、Request URLに `https://リミックスしたGlitchプロジェクト名.glitch.me/slack/events` と入力します。
正しく資格情報が入力されていると *Verified ✓* と表示されます。 
<img width="500" alt="Request URLを入力.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/6ea21ddd-77d5-1353-08cc-946b71d1de87.png">
Subscribe to bot events を展開して、以下のイベントを追加します。
**reaction_added**
**message.channels**
**message.groups**
**message.im**
**message.mpim**

追加が完了したら、「Save Changes」をクリックします。
<img width="500" alt="Eventsを入力して保存する.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/bba673e7-5eb7-4081-b2a1-581f69e8c810.png">
これでワークスペースに投稿されたメッセージとリアクションを取得できるようになります。


### カスタムemojiを登録する
次に、翻訳したいメッセージにつけるリアクション用のemojiを登録します。
メッセージフィールドにあるスマイリーフェイスアイコンをクリックして、絵文字メニューを開きます。
<img width="500" alt="emoji追加1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/34fb5396-df27-5f41-5d4e-856e6c9917bf.png">

絵文字メニューから、「絵文字を追加する」をクリックします。
<img width="500" alt="emoji追加2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/466dee84-383e-e825-0dcd-19ea64a640c8.png">
emojiとして登録したい画像をアップロードして、名前を設定します。
※英訳の場合は `translate_english` 、和訳の場合は `translate_japanese` と名前を付けて登録してください！


## GASをWebアプリケーションとして公開する

[ 【GAS】翻訳APIを無料で使用したかったので作ってみた](https://traveler0401.com/gas-google-translate-api/) を参考に作成しています。

### GASを新規作成する
https://script.google.com/home を開き、画面左上の「新しいプロジェクト」をクリックします。
<img width="500" alt="GAS作成1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/1b70392e-dcea-6832-6003-51b9469ab4ae.png">

### 翻訳前/翻訳後のメッセージを暗号化するためのライブラリを追加する

リソース→ライブラリを開き、Add a library のテキストフィールドに文字列 `MSJnPeIon6nzdLewGV60xWqi_d-phDA33` を入力して、ライブラリに `cCryptoGS` を追加して保存をクリックします。
<img width="500" alt="GAS作成2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/a25b2d3d-e9c6-8455-e75b-8aa619c07d1b.png">
<img width="500" alt="GAS作成3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/817b894d-4294-9225-8725-226a3d7f22af.png">

ファイル→プロジェクトのプロパティ→スクリプトのプロパティを開き、プロパティ `ENCRYPT_KEY` と 値を追加して、保存をクリックします。
※値は任意の文字列を設定して下さい。
<img width="500" alt="GAS作成4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/5d23ebf9-9777-9cf7-6784-22034184f251.png">

リミックスしたGlitchプロジェクトの `.env` ファイルにも同じ名前、同じ値を登録してください。
<img width="500" alt="GAS作成5.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/b7b2e52d-d46b-008f-7bbd-c39b33e33ed9.png">

### 翻訳機能を実装する

以下のソースコードをコード.gsに貼り付けます。

```javascript:code.gs
const ENCRYPT_KEY = PropertiesService.getScriptProperties().getProperty('ENCRYPT_KEY');
const cipher = new cCryptoGS.Cipher(ENCRYPT_KEY, "AES");
/**
 * POST実行時
 */
function doPost(e) {
    Logger.log(e);
    var param          = e.parameter;
    var translatedText = fetchTranslatedText(param);
    var responseBody   = fetchResponseBody(translatedText);
    var response       = fetchResponse(responseBody);
    return response;
}
 
/**
 * 翻訳を取得する
 *
 * @param クエリパラメータ
 *
 * NOTE: LanguageAppクラスを使用することで無料利用できる、みたい。
 */
function fetchTranslatedText(param) {
    return LanguageApp.translate(cipher.decrypt(param.trans_text), param.source, param.target);
}
 
/**
 * レスポンスボディを取得する
 *
 * @param 翻訳情報
 */
function fetchResponseBody(translatedText) {
    if (translatedText) {
        return fetchResponseBodyJson(200, cipher.encrypt(translatedText));
    } else {
        return fetchResponseBodyJson(500, "Error");
    }
}
 
/**
 * レスポンスボディJSONを取得する
 *
 * @param ステータスコード
 * @param 翻訳情報、もしくはエラーメッセージ
 */
function fetchResponseBodyJson(code, text) {
    return {
        code: code,
        text: text
    };
}
 
/**
 * レスポンスを取得する
 *
 * @param レスポンスボディ
 */
function fetchResponse(body) {
    var response = ContentService.createTextOutput();
    response.setMimeType(ContentService.MimeType.JSON);
    response.setContent(JSON.stringify(body));
    return response;
}
```
### ウェブアプリケーションとして導入する

画面上部の公開タブ→ウェブアプリケーションとして導入する を開いて、 Execute the app as: を `Me` 、 Who has access to the app を `Anyone, even anonymous` に設定して「Deploy」をクリックします。
<img width="500" alt="GAS作成6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/e2a811df-3f47-5ea9-584c-e2035d7bb222.png">
<img width="500" alt="GAS作成7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/ca5ceb96-64c9-0b67-c947-7ffc51cf0b7c.png">

Web app URLが作成されるので、コピーしてGlitchの `.env` ファイルに入力します。
<img width="500" alt="GAS作成8.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/0d01ff40-9972-378d-2d4a-79634862caf0.png">

以上で完了です！翻訳Botのメッセージタブを開いてメッセージを入力するか、チャンネルに翻訳Botをinviteして、メッセージに登録したemojiでリアクションを付けてみましょう。
     
## 反響
今回作成したSlack appを社内のお知らせチャンネルにて周知したところ、思った以上の反応をいただきました！
（いろいろな所で使われているのを覗き見て、一人ニヤニヤしていました。気持ち悪い。）
<img width="500" alt="反響.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/941633/59d9556f-7351-03e9-3f8f-85123e886982.png">

Slack上で翻訳が完結するようになり、翻訳したいメッセージにリアクションを付けるだけで翻訳が行えるのでよりスムーズにコミュニケーションが取れるようになった、という英語ネイティブのメンバーの声も聞けて嬉しかったです。

## 参考にさせていただいたもの
今回のSlackの翻訳Bot作成にあたり、以下の記事やソースコードを参考にさせていただきました。ありがとうございます！

- [Hello World, Bolt! ⚡️ Bolt フレームワークを使って Slack Bot を作ろう](https://qiita.com/tomomi_slack/items/93538f9a69eb4015f951)
- [Reacjilator for Slack](https://github.com/slackapi/reacjilator.git)
- [ 【GAS】翻訳APIを無料で使用したかったので作ってみた](https://traveler0401.com/gas-google-translate-api/)