【GAS】画像から文字を起こすLINEbotに翻訳機能を追加（言語サポート全部乗せ）

## 概要
先日、画像を送ると文字に起こしてくれるLINEbotを作成して便利に使っていたんだけど、ついでに翻訳してくれたらなぁ～ってのが今回。

Qiita記事：[【GAS】画像を送ると文字に起こすLINEbot【OCR】](https://qiita.com/YasumiYasumi/items/49479bfaa683fefd09c5)

上記リンク先で紹介したコードに少し足したら作れたので、追記部分を紹介するのがこの記事。

## 実行結果
画像送信
　 ↓
文字起こし
　 ↓
言語コード送信※
　 ↓　↑
翻訳（繰り返しOK）

LINEbotで画像から文字起こしするたびにスプレッドシートに起こした文字が記録され、言語コードを受け取ると記録された文字を翻訳する設計。

※Googleの翻訳機能でサポートされてる言語は何でも行けるようにしてみた^^)b

Translation API：[言語サポート](https://cloud.google.com/translate/docs/languages?hl=ja)

そんなわけで、洋酒のラベルをLINEbotに送信。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/708687/ef5964d8-e638-1c2e-2469-fb341693b3de.png)
ここまでは前と同じ。文字起こしされても私には読めない^^;

と言うことで、日本語（言語コード：ja）に翻訳！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/708687/cbd2b0c8-68d2-9204-cee1-f593123365be.png)
なんかちょっと変だけど、翻訳精度はGoogle翻訳に依存。

韓国語（ko）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/708687/9ed29233-04f4-639b-ca1e-0e817ba87333.png)

マラヤーラム文字（ml）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/708687/01ee71c4-eecf-7e61-8eac-5633544f29ac.png)
もちろん韓国語やマラヤーラム文字が読めるわけではない（ ´_ゝ`）デザインがクール

## コード
全文掲載。追加したのは４ヶ所（量は少し）、コード内で軽く触れつつ後程説明。その他の部分の説明は[前の記事](https://qiita.com/YasumiYasumi/items/49479bfaa683fefd09c5)を参照。

```javascript
var TOKEN = "xxxxxxxxxxxxxxxxxxxx";
var replyURL = "https://api.line.me/v2/bot/message/reply";

//追加コード①：スプレッドシートを定義
var sheet = SpreadsheetApp.openById('シートID').getSheetByName('シート名');

function doPost(event) {

  var json = JSON.parse(event.postData.contents);
  var replyToken = json.events[0].replyToken;
  var type = json.events[0].message.type;
  var messageId = json.events[0].message.id;

  //追加コード②：メッセージがテキストだった場合
  if (type === "text"){

    //言語コードを受け取るためにメッセージを取得
    var userMessage = json.events[0].message.text;
  
    //A1セルを取得（文字起こし前なら空欄）
    var origText = sheet.getRange('A1').getValue();
  
    //A1セルが空欄でなければ翻訳する ※追加コード④へ
    if(origText){
      translationText(userMessage, origText, replyToken);
    }

  }
  
  if (type !== "image"){
    replyBot(replyToken);
    return;
  }

  var imageURL = "https://api-data.line.me/v2/bot/message/" + messageId + "/content";
  var image = getImage(imageURL);
  
  //var folder = DriveApp.getFolderById("1gTJgvoX5ldwB69oPRelKEY-89dxGa_Ru");
  //folder.createFile(image);
  
  var ocrText = getText(image);
  
  //追加コード③：起こした文字を記録
  sheet.getRange('A1').setValue(ocrText);
  
  replyText(ocrText,replyToken);
}


//追加コード④：翻訳してLINEで返信
function translationText(lang, origText, replyToken) {
  
  //ターゲット言語が無効の場合return
  try{
    var transText = LanguageApp.translate(origText, "", lang);
  }catch(e){
    return;
  }
  
  //メッセージ作成・送信
  var payload = JSON.stringify({
      "replyToken": replyToken,
      "messages": [{
        "type": "text",
        "text": transText
      }]
  });
  UrlFetchApp.fetch(replyURL, {
      "headers": {
        "Content-Type": "application/json; charset=UTF-8",
        "Authorization": "Bearer " + TOKEN,
      },
      "method": "post",
      "payload": payload
  });
  return;
}


//画像でも翻訳リクエストでもない場合 画像を求めるメッセージを返す
//出来心で少し改変したので後程説明
function replyBot(replyToken) {

  var title = '画像を送ってね';
  var text  = '画像を送ると文字に起こすよ。\n翻訳するには文字起こし後に言語コードを送信。';
  
  var payload = JSON.stringify({
      "replyToken": replyToken,
      "messages": [{
        "type": "template",
        "altText": "ヒント",
        "template": {
          "type": "buttons",
          "title": title,
          "text": text,
          "actions": [
            {
              "type": "uri",
              "label": "カメラを起動する",
              "uri":"https://line.me/R/nv/camera/",
            },
            {
              "type": "uri",
              "label": "画像を選択する",
              "uri":"https://line.me/R/nv/cameraRoll/single",
            },
            {
              "type": "uri",
              "label": "サポート言語を見る",
              "uri":"https://cloud.google.com/translate/docs/languages",
            }
          ]
        }
      }]
  });
  UrlFetchApp.fetch(replyURL, {
        "headers": {
        "Content-Type": "application/json; charset=UTF-8",
        "Authorization": "Bearer " + TOKEN,
      },
      "method": "post",
      "payload": payload
  });
  return;
}


//投稿から画像を取得（変更無し）
function getImage(imageURL) {

  var image = UrlFetchApp.fetch(imageURL, {
       "headers": {
         "Content-Type": "application/json; charset=UTF-8",
         "Authorization": "Bearer " + TOKEN,
       },
       "method": "get"
  }).getBlob();
  
  return image;
}


//画像を文字に起こす（変更無し）
function getText(image) {
  
  var title = image.getName();
  var mimeType = image.getContentType();
  
  var resource = {title: title, mimeType: mimeType};
  var fileId = Drive.Files.insert(resource, image, {ocr: true}).id;
  
  var document = DocumentApp.openById(fileId);
  var ocrText = document.getBody().getText().replace("\n", "");
  Drive.Files.remove(fileId);
  
  return ocrText;
}


//起こした文字をLINEで返信（変更無し）
function replyText(ocrText,replyToken) { 

  var replyURL = "https://api.line.me/v2/bot/message/reply"; 
  
  var payload = JSON.stringify({ 
      "replyToken": replyToken, 
      "messages": [{ 
        "type": "text", 
        "text": ocrText 
      }] 
  }); 
  UrlFetchApp.fetch(replyURL, { 
      "headers": { 
        "Content-Type": "application/json; charset=UTF-8", 
        "Authorization": "Bearer " + TOKEN, 
      }, 
      "method": "post", 
      "payload": payload 
  }); 
  return; 
}
```

## 解説
まずは追加コード①でスプレッドシートを定義。

前のコードではテキスト判定は行わなかったけど、今回は「追加コード②」でテキスト判定を行っている。テキストでなく画像であれば文字起こし→「追加コード③」でスプレッドシートへ記録。

テキストメッセージが送られてきたら、それをA1セルの文字と一緒に「追加コード④」へ送る。「追加コード④」では、テキストメッセージを言語コードとして`.translate`メソッドでA1セルを翻訳。（翻訳前の言語を指定する部分を空欄にしているので、言語は自動で判定。）

翻訳先の言語コードがサポートされていないコードや関係ないテキストだった場合、通常ならエラーになってスクリプトが停止してしまうけど`try...catch`文で停止回避、翻訳エラーの場合はreturnさせる。

これでサポートされている言語を全部使える^^

returnされたのであれば、メッセージタイプは画像ではないので画像を求めるメッセージを返す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/708687/667a2a70-43c1-4985-57cf-28a188efb4fa.png)
前のままでも使えたけど、カメラ起動・カメラロール・言語サポートリンクのボタンテンプレートを返すようにした。

### おしまい