Microsoft Translator テキスト API で、日本語を英語に翻訳するサンプル

## やること
Microsoft Translator テキスト API へ日本語の文字を送り、英語に翻訳されたデータを受け取る
JavaScript で実装する

## 流れ
1. Microsoft Translator テキスト APIを有効化して、認証キーを取得する
2. トークンを取得する
3. トークンを使ってTranslator テキスト APIを叩く
4. サンプルコード
5. 参考情報


## Microsoft Translator テキスト API を有効化して、認証キーを取得する

最初に、Translator テキスト APIを利用するため、Microsoft Azureから認証キーを取得する必要があります。詳細は以下に書かれています。

https://docs.microsoft.com/ja-jp/azure/cognitive-services/translator/translator-info-overview

- Microsofut Azure アカウントを持っていない場合は、 https://azure.microsoft.com/ja-jp/ で Azure アカウントにサインアップする
- Azure アカウントに Microsoft Translator のサブスクリプションを追加する      
- [すべてのリソース] メニューにアクセスしてサブスクリプションをクリックし、認証キーを取得する      



![azure-tranlator-api.png](https://qiita-image-store.s3.amazonaws.com/0/83767/bcbbba62-37da-3b32-9f9f-1f44a3d96005.png)

下記の項目を設定します。

* Account Name
    * 適宜名前をつけます。なんでもOK。
* サブスクリプション
    * サブスクリプションを選択
* APIタイプ
    * Cognitive サービスで使えるAPIを選択する。「Translator Text API」を選ぶ
* 価格
    * 利用する価格帯を選ぶ。詳細は価格のページを参照。
    * https://azure.microsoft.com/ja-jp/pricing/details/cognitive-services/
* リソースグループ
    * Translator テキスト APIのリソースグループを選択。
* Resource Group Location
    * ロケーションを選択

設定したら、リソースの詳細画面を開きます。
[Resource Management]の中にある[Keys]を選択すると、Translator テキスト APIを利用するためのAPIキーが表示されます。このキーを利用して、APIを叩きます。

![azure-tranlator-api-2.png](https://qiita-image-store.s3.amazonaws.com/0/83767/f227c6e0-6543-1f8d-4ca8-0793e6144055.png)


Translator テキスト APIを利用するための流れは

* APIキーをつかってトークンを取得する
* 取得したトークンを使って、Translator テキスト APIを叩く

となります。

## トークンを取得する

取得したAPIキーを使ってトークンを取得します。詳細は以下のドキュメントに書いています。

https://docs.microsoft.com/ja-jp/azure/cognitive-services/translator/reference/v3-0-reference

エンドポイント [https://api.cognitive.microsoft.com/sts/v1.0/issueToken] に対して

* APIキー
* Content Type 
* Accept

の3つを指定してPOSTすると、トークンが取得できます。
crulを使う場合は

curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/jwt' --header 'Ocp-Apim-Subscription-Key: 取得したAPIキー' 'https://api.cognitive.microsoft.com/sts/v1.0/issueToken'

となります。

ドキュメントによると、取得したトークンの有効期間は10分と、かなり短めとなっているようです。ご注意ください。

## トークンを使ってTranslator Text APIを叩く

トークンを利用して、Translator テキスト APIを叩きます。
Translator テキスト API のエンドポイントは、以下のドキュメントに説明があります。

http://docs.microsofttranslator.com/text-translate.html

単純に一語句、もしくは一文章を翻訳したい場合は [Translate]というエンドポイントをGETメソッドで叩きます。[Translate]を叩くためには、以下の3つの項目が必須となります。

* appid
    * 送信する文字列は [Bearer] + [(半角スペース)] + [トークン] となる。トークンだけを投げてもうまくいかないため要注意。
* text
    * 翻訳したい文字列を指定
* to
    * 翻訳したい言語を指定。日本語に翻訳したい場合は [ja]。英語に翻訳したい場合は [en]となる。



## サンプルコード

上記を踏まえて、簡単な翻訳アプリを作ってみました。Azure のアカウントをお持ちの方は

* APIキーを取得
* 下記のコードにAPIキーを記述して、htmlとして保存する

さえすれば、すぐ動くと思います。サーバーに上げずに、ローカルのPCでも動きました。


```
<!DOCTYPE html>
<html lang="ja">
<head>
<title>Microsoft Translator テキスト API で英訳を行うサンプルコード</title>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>

  "use strict"

  $(function() {

// 文字が入力されたらイベント発火

    $("#word").change(function() {

// 認証トークンを取得するための関数 [getToken] を定義
// http://docs.microsofttranslator.com/oauth-token.html

      const getToken = function() {
        const defer = $.Deferred();
        $.ajax({
          url: 'https://api.cognitive.microsoft.com/sts/v1.0/issueToken',
          type: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/jwt',
            'Ocp-Apim-Subscription-Key': 'Azureで取得したキーの文字列を記述します',
          },
        }).done(function(data) {

            const token = data;
            defer.resolve(token);

        });
            return defer.promise();
      };

// 関数 [getToken] 実行後、取得したトークンを 引き渡す
// フォームから入力したデータとともに、 Microsoft Translator テキストAPIへ送信

      $.when(getToken()).done(function(token) {
        const key = 'Bearer ' + token;
        const text = $("#word").val();
        const response = $.ajax({
          url: 'https://api.microsofttranslator.com/v2/http.svc/Translate',
          type: 'GET',
          data: {
            'appid': key,
            'Accept': 'application/xml',
            'text': text,
            'to': 'en',
          },
        async: false,
        })

// Translator テキスト APIを通じて取得したデータから、翻訳語が含まれるプロパティを取得
// replace関数でタグを除去し、翻訳データのみを抽出して表示する

        const data = response.responseText;

        const translation = data.replace(/<("[^"]*"|'[^']*'|[^'">])*>/g, '');

        $("#english").text(translation);
      })
    })
  })
 
</script>
</head>

<body>

  <h1>Microsoft Translator テキスト API サンプル</h1>
  <h2>入力データを英語に翻訳します。</h2>

  <input type="text" id="word" placeholder="何か入力してください" size="40">
  <div id="english"></div>


</body>
</html>
```

今回のサンプルプログラムでは毎回トークンを取得しています。トークンを取得後、Translator テキスト APIに値を渡すため、jQuery.Deferred とasync/false で、非同期処理ではなく同期処理を行いました。

エンドポイント [Translate] からの返り値はXMLデータとなるため、正規表現で翻訳語句のみを抜き出し、画面に表示しています。


毎回トークンを取得するのではなく

* 取得したトークンをsessionStorageに保存する
* トークンが有効期間内であれば再利用する
* 有効期限が切れた場合、トークンを再取得する

パターンも考えてみました。

```
<!DOCTYPE html>
<html lang="ja">
<head>
<title>Microsoft Translator テキスト API で英訳を行うサンプルコード</title>
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
"use strict"
$(function() {
  // 文字が入力されたらイベント発火

  $("#word").change(function() {

// 現在の時刻をUNIX Time に変換して取得

    const now = new Date();
    const nowtime = now.getTime();

// 認証トークンを取得するための関数 [getToken] を定義
// http://docs.microsofttranslator.com/oauth-token.html

    const getToken = function() {
      const defer = $.Deferred();

// 現在時刻と、sessionStorageに保存されている時刻を比較
// sessionStorageに保存されているトークンが8分以内に発行されたものであれば、そのまままトークンを返す
// 8分以上経っている場合、もしくはトークンが存在しない場合、新規にトークンを取得。
// 取得したトークン、および取得時間をUNIX Time に変換したデータをJSON [datalist] に格納
// sessionStorage [tdata] にJSONを保存する
      
      const arr = JSON.parse(sessionStorage.getItem("tdata"));

      if (arr === null || arr.time + 1000 * 60 * 8 < nowtime) {
        $.ajax({
          url: 'https://api.cognitive.microsoft.com/sts/v1.0/issueToken',
          type: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/jwt',
            'Ocp-Apim-Subscription-Key': 'APIキーを入力する',
          },
          async: false,
        }).done(function(data) {

          const datalist = {
            time: nowtime,
            token: data,
          }
          sessionStorage.setItem('tdata', JSON.stringify(datalist));
        });
      }

// sessionStorage に保存されたデータを変数 arr2 に格納
// JSONを文字列に変換後、トークンデータを引き出して翻訳用の関数にひきわたす

      const arr2 = JSON.parse(sessionStorage.getItem("tdata"));
      const token = arr2.token;
      defer.resolve(token);
      return defer.promise();
    };

// 関数 [getToken] 実行後、取得したトークンを 受け取る
// フォームから入力したデータとともに、 Microsoft Translator テキストAPIへ送信

    
    $.when(getToken()).done(function(token) {
      const key = 'Bearer ' + token;
      const text = $("#word").val();
      const response = $.ajax({
          url: 'https://api.microsofttranslator.com/v2/http.svc/Translate',
          type: 'GET',
          data: {
            'appid': key,
            'Accept': 'application/xml',
            'text': text,
            'to': 'en',
          },
          async: false,
        })

// Translator テキスト APIを通じて取得したデータから、翻訳語が含まれるプロパティを取得
// replace関数でタグを除去し、翻訳データのみを抽出して表示する

      const data = response.responseText;
      const translation = data.replace(/<("[^"]*"|'[^']*'|[^'">])*>/g, '');
      $("#japanese").text(translation);

    })
  })
})

</script>
</head>

<body>

  <h1>Microsoft Translator テキスト API サンプル</h1>
  <h2>フォームの入力データを英語に翻訳します。</h2>

  <input type="text" id="word" placeholder="何か入力してください" size="40">
  <div id="japanese"></div>


</body>
</html>
```

![azure-tranlator-api-3.png](https://qiita-image-store.s3.amazonaws.com/0/83767/23d122a9-afa6-cc0d-f432-53bbee22177e.png)

※サンプル実装なので、APIキーを直接コードに書いていますが、**APIキーを第三者が認識できる状態にするのはとても危険です**。ご注意ください。

## 参考情報

以下のドキュメントを参考にしました。

https://www.microsoft.com/ja-jp/translator/getstarted.aspx
https://www.microsoft.com/cognitive-services/en-us/documentation
http://docs.microsofttranslator.com/text-translate.html

## 積み残し

複数の文字列を同時翻訳する「TranslateArray」の利用がうまくいかないので要調査