オフショア開発するので翻訳botを作った

この記事は[Monstar Lab, Inc. Advent Calendar 2016](http://qiita.com/advent-calendar/2016/monstar-lab) 16日目の記事です。

少し前にSIer(?)から、モンスター・ラボにやってきた岸田です。
とあるシステムの改修作業を細々やっていたと思ったら、いつの間にかオフショア開発を行っている会社にいました。

当社はベトナムや中国、バングラデシュなどをオフショア拠点とし、一緒にプロジェクトを進めています。
私は今、バングラデシュと開発を進めるプロジェクトを進めているサーバサイドエンジニアです。

オフショアとの開発はマネジメントや認識合わせが大変ですが、バングラデシュのエンジニア/PMたちはかなり優秀で、技術力もあり仕事に対しての責任感もあります。
日本で、自分たちだけで開発を行う以上に刺激的です。

### が、
英語がつらい。

## 問題点
- メンバー全員がストレスなく英語を読めるわけではない
	- 自分もそんなにスラスラ読めない
	- 返信に時間がかかる
	- コミュニケーションにオーバーヘッドが発生する
- チャットなどで発言するのが億劫になる
	- ミスコミュニケーションの温床

よくない。

よし、Slackに翻訳bot作ろう。
ということで作りました。(細かい手順は書けてない

## 構成
- AWS Lambda/API Gateway
- Microsoft translator(翻訳)
- Node.js

## 手順
1. Microsoft Translatorに登録
	- 他に記事があると思うのでそちらで
1. AWS Lambda functionを作成
	2. Blue printでmicroservice-http-endpointを選択
	3. function名とかを適当に
	4. zipをアップロード(今回は大したことないので、直接書いてしまった)
	5. Microsoft Translatorに使う`client_secret`とかを環境変数に設定
1. AWS API Gatewayの設定
	2. `method`がデフォルトで`ANY`になっていたので、`POST`を設定
	1. Slackからは`x-www-form-encoded`でくるので、それの設定
2. Slackの設定
	3. outgoingWebhookでAPI GatewayのURLを指定
	4. `Trigger Word(s)`に`toEn,toJa`を設定
1. Slackで使う

## コード
```index.js
'use strict';

const http = require('http');
const https = require('https');
const qs = require('querystring');

exports.handler = (event, context) => {
  let blank = " ";
  let texts = decodeURIComponent(event.text).replace(/\+/g, blank);
  getAccessToken((token) => {
    translate(token, texts, (translated) => {
      context.done(null, { text: translated });
    });
  });
};

function getAccessToken(callback) {
  let body = '';
  var access_token = '';
  let data = {
    'client_id': process.env.環境変数名,
    'client_secret': process.env.環境変数名,
    'scope': 'http://api.microsofttranslator.com',
    'grant_type': 'client_credentials'
  };

  let options = {
    host: 'datamarket.accesscontrol.windows.net',
    path: '/v2/OAuth2-13',
    method: 'POST'
  };

  let req = https.request(options, (res) => {
    res.setEncoding('utf8');
    res.on('data', (chunk) => {
      body += chunk;
    }).on('end', () => {
      let resData = JSON.parse(body);
      callback(resData.access_token);
    })
  }).on('error', (err) => {
    console.log(err);
  });
  req.write(qs.stringify(data));
  req.end();
}

function translate(token, text, callback) {
  let fromTo = text.indexOf('toEn') === 0 ? 'from=ja&to=en' : 'from=en&to=ja';
  let options = fromTo + '&text=' + qs.escape(text.slice(4)) + '&oncomplete=translated';
  let body = '';
  let req = http.request({
        host: 'api.microsofttranslator.com',
        path: '/V2/Ajax.svc/Translate?' + options,
        method: 'GET',
        headers: {
          "Authorization": 'Bearer ' + token
        }
    }, (res) => {
        res.setEncoding('utf8');
        res.on('data', (chunk) => {
            body += chunk;
        }).on('end', () => {
            eval(body);
        });
    }).on('error', (err) => {
        console.log(err);
    });
    req.end();

    function translated(text) {
        callback(text);
    }
}

```
`let texts = decodeURIComponent(event.text).replace(/\+/g, blank)`
これはAPI Gatewayの設定でなんとかできる気がするんですが、ちょっと時間が...。

Microsoft Translatorから返ってくるのが、
`translated("翻訳された文字列")`だったのがびっくりしたぐらいで、ほかは簡単ですね。


## はまったこと
`context.done(null, { text: translated });`
って書くところを
`context.node(null, { text: translated });`
と書いてるのに気付かなかったこと。

(つまり簡単でした


## 結果
こんな感じです。
![こなん感じ](https://qiita-image-store.s3.amazonaws.com/0/86504/6cdd51ff-04bb-1dc1-b472-19258663cc8f.png "スクリーンショット 2016-12-18 0.33.07.png")


今日作ったのでまだ導入してません。

が、思ったより精度が低いです...。
![スクリーンショット 2016-12-18 0.37.48.png](https://qiita-image-store.s3.amazonaws.com/0/86504/c31fb095-9e78-027a-7617-22407a9cdd13.png "スクリーンショット 2016-12-18 0.37.48.png")
こんなのとかね。

Google translatorの方がいい感じに訳してくれるので、導入するか迷うところですね。
月の無料翻訳可能数にも制限があることですし。

## 大事なこと
英語を勉強しよう。
あとは、日本だけでなくいろいろな国や人とうまくコラボレートできるように試行錯誤することですね。

そして、投稿遅れてすみません🙇

~~本当は、KoltinでSpring Cloud Streamとか全部KotlinでWebアプリケーション作ってみたとかをやりたかったなぁ...~~