HoloLensで始めるCognitive Services（Translator Text API編）


[HoloLensで始めるCognitive Services（Emotion APIサンプル編）](http://qiita.com/morio36/items/152bc8b971658094c594)と
[HoloLensで始めるCognitive Services（Computer Vision APIサンプル編）](http://qiita.com/morio36/items/44717c7ef928709ebca9)で
CognitiveServicesの基礎を確認しました。

今回はCognitive ServicesのTranslator Text APIを使用して、
英語の文字列を日本語に変換してみましょう！
この流れを一度押さえておけば、日本語から英語でも英語からスペイン語でも
Translator Text APIがサポートしている言語であれば好きなように変換できます！

##Translator Text APIとは
変換したい文字列を送信すると、Azure側で変換して返してくれる
Cognitive Servicesのサブスクリプションです。
詳しくは下記をご参照ください。
https://azure.microsoft.com/ja-jp/services/cognitive-services/translator-text-api/

##環境
OS：Windows 10 CreatersUpdate
Unity：5.6.0f3
VisualStudio 2017

##完成イメージ
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://t.co/ouIMeHZuir">https://t.co/ouIMeHZuir</a><br>に手を加えて元素記号の解説文をMicrosoft Translator Text APIで日本語化した結果。 <a href="https://t.co/T2lfb7dKAO">pic.twitter.com/T2lfb7dKAO</a></p>&mdash; morio@6/25～米国 (@morio36) <a href="https://twitter.com/morio36/status/877445739533680640">2017年6月21日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

##流れ
０．事前準備
１．MRDesignLabs_Unityを確認
２．翻訳処理を追加
３．動作確認
##０．事前準備
本サンプルを試すためには、Azureのアカウントが必要です。
また、Translator Text APIのサブスクリプションも必要となります。
下記の方の記事を参考にアカウント作成、サブスクリプション作成を行ってください。
[人工知能パーツ Microsoft Cognitive Services を使った表情分析アプリを作ろう！[サブスクリプション準備編] 2017年6月版](http://qiita.com/annie/items/251d4b85c86aa9321665)
作成すべきサブスクリプションはTranslator Text APIに読み替えてください。
##１．MRDesignLabs_Unityを確認
せっかくなので、MixedRealityにおける標準的なUIとなるであろう
MRDesignLabsを元にしてみたいと思います。
MRDesignLabsについては下記の記事を参考に構築、動作確認してください（丸投げ）。
[Mixed Reality Design Labsのサンプルをとりあえず動かしてみる - Periodic Table of the Elements](http://qiita.com/miyaura/items/f4d81a222dcb27c828da)

MRDesignLabsについては、下記の記事も非常に参考になります。
[MRDesignLabを使いジェスチャー入力を取り扱う](http://blog.d-yama7.com/archives/850)
##２．翻訳処理を追加
「１．MRDesignLabs_Unityを確認」で、元素記号をタップすると
解説文などが表示されることまで確認できた前提で、次に進みます。

英語の解説文がすでにPeriodicTableJSON.json内で定義されているので、
これをAzureに投げて翻訳（日本語化）する処理を追加してみましょう。
初期処理ですべての元素について日本語化して取ってくると処理時間や課金が気になるので、
タップしたタイミングで対象元素のみを日本語化することにします。
<ol>
<li>日本語化メソッドの追加
元素記号がタップされた際のイベントはElementButton.csのPressedが呼び出されます。
ここに翻訳処理を追加します。

```ElementButton.cs
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
//
using System;
using HUX.Buttons;
using HUX.Interaction;
using UnityEngine;
using System.Collections.Generic;
using System.Xml;
using System.IO;

public class ElementButton : Button {

    public override void Pressed(InteractionManager.InteractionEventArgs args)
    {
        Element element = gameObject.GetComponent<Element>();

        StartCoroutine(ExecuteTranslate(element.ElementDescription.text)); //翻訳処理の呼び出し

        // User has clicked us
        // If we're the active element button, reset ourselves
        if (Element.ActiveElement == element)
        {
            // If we're the current element, reset ourselves
            Element.ActiveElement = null;
        }
        else
        {
            Element.ActiveElement = element;
            element.Open();
        }
    }

    //追加メソッド
    System.Collections.IEnumerator ExecuteTranslate(string text)
    {
        string translateTokenUrl = "https://api.cognitive.microsoft.com/sts/v1.0/issueToken";
        var translateHeaders = new Dictionary<string, string>() {
            { "Content-Type" , "application/json" },
            { "Ocp-Apim-Subscription-Key", "APPKEY" } //自身のAPPキーを入力
        };

        WWW tokenWWW = new WWW(translateTokenUrl, new byte[1], translateHeaders);
        yield return tokenWWW;

        string req = text.Replace(" ", "%20"); //英文に含まれる半角スペースを変換

        string japanUrl = "https://api.microsofttranslator.com/v2/http.svc/Translate?appid=Bearer%20" + tokenWWW.text + "&text=" + req + "&from=en&to=ja";

        WWW getWWW = new WWW(japanUrl);
        yield return getWWW;

        XmlDocument xmlDoc = new XmlDocument();
        xmlDoc.Load(new StringReader(getWWW.text));
        XmlNode root = xmlDoc.FirstChild;
        XmlNodeList talkList = xmlDoc.GetElementsByTagName("string");
        XmlNode talk0 = talkList[0];
        string jaString = talk0.InnerText;

        SingletonText.Instance.SetText(jaString);
    }
    
    public override void OnStateChange(ButtonStateEnum newState)
    {
        Element element = gameObject.GetComponent<Element>();

        switch (newState)
        {
            case ButtonStateEnum.ObservationTargeted:
            case ButtonStateEnum.Targeted:
                // If we're not the active element, light up
                if (Element.ActiveElement != this)
                {
                    element.Highlight();
                }
                break;

            default:
                element.Dim();
                break;
        }

        base.OnStateChange(newState);
    }
}
```

Azureからの戻り値はXMLのタグ指定で取得するようにしました。

元素のGameObject一つ一つに日本語反映用テキストエリアをアタッチするのは非常に大変なので、
SingletonにしてSetTextしています。

```SingletonText.cs
using HoloToolkit.Unity;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class SingletonText : Singleton<SingletonText>
{

    public void SetText(string s)
    {
        gameObject.GetComponent<Text>().text = s;
    }
}
```
</li>
<li>翻訳語文字列表示用テキストエリアの追加
下記のようなイメージで、テキストエリアを追加してください。
（どういうUIにするかはお好みで）
![2.PNG](https://qiita-image-store.s3.amazonaws.com/0/114630/2d1af70d-554a-7950-ab75-7c8c05869f4c.png)

追加したTextには上述のSingletonコンポーネントのアタッチを忘れないようにしてください。
![3.PNG](https://qiita-image-store.s3.amazonaws.com/0/114630/e2a62d00-cdfb-a77b-9ad1-712241db45ab.png)

</li>
<li>ビルド＆デプロイ
通常のHoloLensアプリと同様にUnityでビルドを行ってください。
元のMRDesignLabsを上書きしたくない方は、Product NameなどのOther Settingsを
「MRDesignLabsTranslateDemo」のような名前に変更してください。
![4.PNG](https://qiita-image-store.s3.amazonaws.com/0/114630/b0db2941-22fc-0c40-7205-b1259a21e15d.png)

Unityビルド時はCapabilitiesのInterNet Clientの有効化を忘れないようにしましょう。
![1.PNG](https://qiita-image-store.s3.amazonaws.com/0/114630/4f005153-a6fc-0220-62c5-4553802092ea.png)

忘れると下記のようなことになってしまいます。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">UnityエディタではうまくいくのにHolo実機ではAzureからの戻りが空でNG。ログ出したらCouldn&#39;t resolve hostが出てて？？？しばらくしてCapabilityのInterNet Clientにチェックを入れてなかったことに気づいた。凡ミス共有。</p>&mdash; morio@6/25～米国 (@morio36) <a href="https://twitter.com/morio36/status/877442657168924672">2017年6月21日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

出力されたMRDesignLabsTranslateDemo.slnをVisualStudioで開き、
HoloLens実機にビルド＆デプロイしてください。
</li>

##３．動作確認
元素記号をタップし、追加したTextエリアに日本語訳が表示されたら成功です！
![20170621_194739_HoloLens.jpg](https://qiita-image-store.s3.amazonaws.com/0/114630/31f422e5-dff6-441f-42d1-b306488eb973.jpeg)

若干日本語に違和感があるのは現在のところの限界なので、許容しましょう。

以上、簡単ですね！

##ソースコード
下記にアップしていますので、必要に応じてご参照ください。
https://github.com/haveagit/TranslatorDemo

次回こそはBing Speech APIのサンプルを実装します！