LINE×GAS｜LINEでドイツ語→日本語・英語に翻訳するアプリを作成

:::note warn
本記事に記載のコードの中身については、全てを1から私が記載したわけではありません。
こちらの記事は、あくまでも参照元に倣って自分でも作ってみて、つまづいたポイント・自分で追加調査したところ・追加改造を記録した記事です。
:::

# 参照元
https://zenn.dev/njn0te/articles/a6c0d8640cdede

https://qiita.com/njn0te/items/2c08c936661a9febb3b0



# ゴール
- LINEでドイツ語を送ったら、英語・日本語で返ってくる。
- スプレッドシートに記録される。


### LINEの画面
![trans_2022_09_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687068/034bf08f-c752-6af8-bfb3-ce170b41f1d6.png)

### スプレッドシート
![LINEで翻訳_-_Google_スプレッドシート_と_翻訳_-_Google_検索.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687068/097901e3-83f5-05cf-7313-1f42ae9915cb.png)



### コードの中身
```js:コード.gs
// 応答メッセージURL
const REPLY = "https://api.line.me/v2/bot/message/reply";

// アクセストークン
const ACCESS_TOKEN = "＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊";

// スプレッドシート情報
const SHEET_ID   = '＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊';
const SHEET_URL  = 'https://docs.google.com/spreadsheets/d/＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊＊';
const SHEET_LOG = SpreadsheetApp.openById(SHEET_ID).getSheetByName('検索履歴');

function doPost(e) {

  //メッセージ受信
  const data = JSON.parse(e.postData.contents).events[0];
  //ユーザーID取得
  const lineUserId = data.source.userId;
  // リプレイトークン取得
  const replyToken = data.replyToken;
  // 送信されたメッセージ取得
  const postMsg = data.message.text;
  // 翻訳
  const lang = 'de'
  const englishMsg = LanguageApp.translate(postMsg, lang,'en');
  const japaneseMsg = LanguageApp.translate(postMsg, lang,'ja');

  // 検索履歴にユーザーID、原文、翻訳（英語・日本語）、日時を記載
  debugLog(lineUserId, postMsg, englishMsg, japaneseMsg);
  
  // LINEに送信
  sendMessage(replyToken, `EN: ${englishMsg}\nJA: ${japaneseMsg}`);
  
}

//デバック記録
function debugLog(userId, text, eng, jap) {
  const date = Utilities.formatDate( new Date(), 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss');
  SHEET_LOG.appendRow([userId, text, eng, jap, date]);
}

// LINEに送信
function sendMessage(replyToken, replyText) {
  const postData = {
    "replyToken" : replyToken,
    "messages" : [
      {
        "type" : "text",
        "text" : replyText
      }
    ]
  };
  const headers = {
    "Content-Type" : "application/json; charset=UTF-8",
    "Authorization" : "Bearer " + ACCESS_TOKEN
  };
  const options = {
    "method" : "POST",
    "headers" : headers,
    "payload" : JSON.stringify(postData)
  };
  return UrlFetchApp.fetch(REPLY, options);
}

```

# 翻訳されない！
よ〜し、動いてくれよ〜ポチ〜、翻訳されない！
![LINE.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687068/383e98e2-3472-ef55-b4e8-4d9f3c9eeda2.png)


## 原因はシート名にあった
▶︎[解説](https://www.youtube.com/watch?v=ynQJITwpXyo&t=570s)

スプレッドシートの情報を取得する以下のコードの
```js:
// スプレッドシート情報
const SHEET_ID   = '1nHSP6a2yBk2nQfsbuersE9iv4eNu6mx9o73jH79JIzw';
const SHEET_URL  = 'https://docs.google.com/spreadsheets/d/1nHSP6a2yBk2nQfsbuersE9iv4eNu6mx9o73jH79JIzw/edit#gid=0';
const SHEET_LOG = SpreadsheetApp.openById(SHEET_ID).getSheetByName('検索履歴');
```

シート名を取得する部分に注目。
```js:
getSheetByName('検索履歴')
```
「シート名が「検索履歴」というシートを取得」という内容のコードなのに、シート名がデフォルトの「シート1」だった。シート名を「検索履歴」に変更することで解消。

![trans_2022_09_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687068/763d3ca5-5d14-cbfd-6783-ed9c3e91c59d.png)

![LINEで翻訳_-_Google_スプレッドシート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687068/e4f9caac-0fb4-c930-dad8-4b5e6d31f3aa.png)



でも、なんかエラーがまだ出る
![翻訳_-_プロジェクト編集者_-_Apps_Script.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687068/e743f5f9-d5cc-fc9b-7087-a99da4c2ac43.png)

```js:
ReferenceError: replyToken is not defined
doPost	@ コード.gs:35
```
内容的に、replyTokenがないですよ〜っていう話っぽい。
do　postの機能テストのためにコメントアウトした、部分（以下）が原因かも。
```js:
// //メッセージ受信
  // const data = JSON.parse(e.postData.contents).events[0];
  // //ユーザーID取得
  // const lineUserId = data.source.userId;
  // // リプレイトークン取得
  // const replyToken = data.replyToken;
  // // 送信されたメッセージ取得
  // const postMsg = data.message.text;
  // // 翻訳
```
<br />
<br />

コメントアウトを消して、テストのために入力した以下も消した上で、再テスト
```js:
const postMsg = 'neu'
const lineUserId = 'test'
```
<br />
<br />

replyTokenがないですよ〜っていうエラーは消えて、下記エラーが表示された。
これは、「postData」が定義されてないよっていうエラー。そもそもユーザから翻訳したい言葉（データ）を受信してないから、postDataは定義しようがない。なので、このエラーは出ても無視してOK。
▶︎[参照](https://qiita.com/hiropoon/items/e8054e6f8a556c65f215#typeerror-cannot-read-property-postdata-of-undefined-at-dopost)
```js:
TypeError: Cannot read property 'postData' of undefined
doPost	@ コード.gs:15
```


# 自分向けに手順を整理
**「※」がついた手順の詳細は[コチラ](https://qiita.com/njn0te/items/2c08c936661a9febb3b0)を参照する。**



1. スプレッドシートを用意
1. シート名を「検索履歴」に変更
1. スクリプトをコピペ
1. LINE Botを準備※
1. LINE Botのアクセストークンを取得し、以下部分に入力※
    ```js:
    // アクセストークン
    const ACCESS_TOKEN = "************************";
    ```
1. スプレッドシートの情報を以下に入力
    ```js:
    // スプレッドシート情報
    const SHEET_ID   = '************************';
    const SHEET_URL  = '************************';
    ```
1. GASとLINE Botを連携※
    GASをデプロイして、URLをLINE BotのWebhook URLに入力。

<br />

# 追加改造
「ドイツ語→日本語・英語」だったのを、「英語→日本語」に改造する。

### LINEの画面
![trans_2022_09_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687068/0e489351-050d-5960-53ae-a78443ba9533.png)


### スプレッドシート
![LINEで翻訳｜日本語→英語_-_Google_スプレッドシート_と_Qiita_-_LINE×GAS｜LINEでドイツ語→日本語・英語に翻訳するアプリをつくる_-_Qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687068/941a8657-cecd-9385-0882-5f377363c0c6.png)

### 改変した箇所のコード

```js:コード.gs
  const lang = 'ja'

  const englishMsg = LanguageApp.translate(postMsg, lang,'en');
  
  // 検索履歴にユーザーID、原文、翻訳（英語）、日時を記載
  debugLog(lineUserId,postMsg,englishMsg);
  
  // LINEに送信
  sendMessage(replyToken,`${englishMsg}`);
  
}

//デバック記録
function debugLog(userId, text, eng) {
  const date = Utilities.formatDate( new Date(), 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ss');
  SHEET_LOG.appendRow([userId, text, eng, date]);
}
```


# 感想・学び

- スプレッドシートを用いるときは「シート名」が結構重要になる。
- エラーが出たらうわ〜ってなるけど、ちゃんと読んだら意外と意味がわかったりする。
- ドイツ語からの翻訳っていう内容だったけど、違う言語にしたり、もう少しカスタマイズして学びを自分のものにしたい。
- LINEとGASとの連携には「Webhook URL」がポイントです。
- コードをいじったら、デプロイし直してWebhook　URLも更新する必要があるので、要注意。
- ただ倣うだけでなく、追加改造することで気づけたりコードの構成がわかったりするので、追加改造は大事。