C#）DeepL API で翻訳した結果をボイスロイドにしゃべってもらいたい！（１）

# 背景
これは「[自由研究室 AIRS-Lab](https://www.airs-lab.jp)」の [Advent Calendar](https://qiita.com/advent-calendar/2021/airs-lab)、6日目の記事です。

ここから先は読まなくてもいいです…）最近、スパイキングニューラルネットワークに興味が出てきていろいろ調べたりしているのですが、圧倒的に日本語の記事が少ないです…で、いよいよ英語を読まなきゃダメかな…と英語よわよわ勢の私は思っていたのですが、そうだ。翻訳APIがあるじゃない。DeepLとか精度良さそうじゃない。と思い（思い出し）、そういえば前から DeepL で翻訳した結果をスミレさん（ボイスロイド）にしゃべってもらいたいと思っていたなぁ…スマホの「やることリスト」にも書いたままだし…ん？[AIRS-Lab](https://www.airs-lab.jp)のアドベントカレンダー？いやー、記事のネタがないし（ないことはないけどVBAでライフゲームとかボイドモデルとか書き散らしてるだけでまとめるの面倒だし…）、あ、いい機会だから長いこと棚上げしていた「DeepL 翻訳した結果をボイスロイドにしゃべってもらうミッション」に着手するか。VOICEROID2だとちょっと面倒だから、.NET連携のAPIが提供されてる [CeVIO AI](https://cevio.jp) を使ってみよう。せっかくだから日本語と英語の両対応できるように、[マキマキ（弦巻マキ）](https://www.ah-soft.com/cevio/maki/)を使ってみよう。ポチー。というわけで、数日前にマキマキをお迎えして無事 DeepL 翻訳した結果をしゃべってもらえるようになったので、その内容を書いてみようと思います。

ぎゅんぎゅんいくよー！

# やりたいこと
- DeepL API を使って英語を日本語に、日本語を英語に翻訳する。
- 翻訳した結果を ボイスロイド（CeVIO AI）にしゃべってもらう。
- というのを C# で実現する。

※ 今回の記事範囲は 「DeepL API を使って英語を日本語に、日本語を英語に翻訳する」までの内容となります。
※ ボイスロイド（CeVIO AI）連携は別記事に分けています。

【最終的な完成イメージ】
<iframe width="560" height="315" src="https://www.youtube.com/embed/W2eI6WaMapU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# DeepL API を使って翻訳をしてみる

## この記事範囲で作成するアプリのイメージ
こんな感じです。左側のテキストボックス（元の文章）に入力されたテキストを DeepL で翻訳して、右側のテキストボックス（翻訳結果）に表示します。ラジオボタンで選択することで、英語 → 日本語 翻訳、日本語 → 英語 翻訳のどちらにも対応します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276318/3699253d-abbc-c1d1-ad38-28b8ee700260.png" width=64%>

では、さっそく作っていきましょう！

## DeepL API
なにはともあれ、DeepL API です。

### DeepL API 認証キーの取得
まずは DeepL API を使えるようにしないといけません。ひとまず無料版（DeepL API Free）でよいでしょう。[DeepL翻訳ツール](https://www.deepl.com/ja/pro-api?cta=header-pro-api/) のサイトにいって登録を済ましてしまいましょう。クレジットカードの登録が必要となりますが、JCBだと受け付けてもらえないので注意です。登録が済むと「DeepL APIで使用する認証キー」が発行されるので、メモ帳などにコピーしておきましょう。下の図の赤枠部分です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276318/deaffbc6-25b6-16b7-a213-119fe0bfa9f2.png" width=60%>

### DeepL API の使い方の確認
DeepL API のページを見るとAPIの使い方が載っています。ですが…これ C# でどう使うの？？？と、とりあえず結果は JSON で返ってくるみたいですね（汗;

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276318/b8165f80-c108-7b90-7203-aeb9fd83e82c.png" width=80%>

### curl のコンバート
すごいぜ！インターネッツ！というわけで、こんなイカしたサイトがありましたよ！
「[curl to C# converter](https://curl.olsh.me)」
ここに飛んで「DeepL API の使い方」に載っていた curl の Request文をコピー・貼り付けして「Convert」してみましょう。
すると C# のコードが出力されます。これでなんとかなりそう！
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276318/fc41d3c6-e3cc-d095-2786-ae59394f22c3.png" width=70%>

## C# プロジェクト
さて、C# で何とかなりそうなことがわかったのでプロジェクトを作成していきましょう。

### プロジェクトの作成
VisualStudioを立ち上げてプロジェクトを新規作成しましょう。作成するプロジェクトの種類は「Windows フォーム アプリケーション(.NET Framework)」です。プロジェクト名は適当なものにしてください。フレームワークは「.NET Framework 4.8」を選んでおきましょう（CeVIO AI ユーザーズガイドで「.NET Framework 4.8」を指定するように指示されています）。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276318/58d87304-8fb8-0438-6246-0215bbc3e6cb.png" width=70%>


### フォームのデザイン
このようなフォームを作成しましょう。各コントロールのプロパティは下図の通りです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276318/f043a516-8115-9acb-be9f-2eb6a1b59609.png">

### ［翻訳］ボタンのクリックイベント作成
btnTranslate のクリックイベントを作成しましょう。
上で C# のコードにコンバートした結果をコピーして、btnTranslate_Click() イベントに貼り付けます。
エラーがでるので、次の2つをインポートしましょう。また、非同期エラーがでてるので、btnTranslate_Click() に async 修飾子もつけます。

```c#
using System.Net.Http;
using System.Net.Http.Headers;
```

```c#:btnTranslate_Click()
private async void btnTranslate_Click(object sender, EventArgs e)
{
    using (var httpClient = new HttpClient())
    {
        using (var request = new HttpRequestMessage(new HttpMethod("POST"), "https://api-free.deepl.com/v2/translate"))
        {
            var contentList = new List<string>();
            contentList.Add("auth_key=[yourAuthKey]");
            contentList.Add("text=Hello, world!");
            contentList.Add("target_lang=DE");
            request.Content = new StringContent(string.Join("&", contentList));
            request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");

            var response = await httpClient.SendAsync(request);
        }
    }
}
```

### 認証キーの設定、その他
`"auth_key=[yourAuthKey]"` の [yourAuthkey] の部分を、上で取得した「DeepL API 認証キー」に書き換えます。
また、今回翻訳したいテキストは、txtSource のテキストなので、`"text=Hello, world!"` を以下のコードのように書き換えます。
日本語翻訳、英語翻訳のどちらにも対応できるように、`"target_lang=DE"` の部分も修正しましょう。

```c#:btnTranslate_Click()
private async void btnTranslate_Click(object sender, EventArgs e)
{
    using (var httpClient = new HttpClient())
    {
        using (var request = new HttpRequestMessage(new HttpMethod("POST"), "https://api-free.deepl.com/v2/translate"))
        {
            var contentList = new List<string>();
            contentList.Add("auth_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
            contentList.Add("text=" + txtSource.Text);

            if (radioJA.Checked)
            {
                contentList.Add("target_lang=JA");
            }
            else if (radioEN.Checked)
            {
                contentList.Add("target_lang=EN");
            }

            request.Content = new StringContent(string.Join("&", contentList));
            request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");

            var response = await httpClient.SendAsync(request);
        }
    }
}
```

## JSON の操作
### 翻訳結果の JSON から必要な部分を取り出したい
「DeepL API の使い方」を見ると、以下のような結果が返ってくるとありますね。今回欲しいのは `Hallo, Welt!` の部分なので、ここをどうにかして取り出すようにします。 

```
{
    "translations": [{
      "detected_source_language":"EN",
      "text":"Hallo, Welt!"
    }]
}
```

### Newtonsoft.Json のインストール
今回は C# で簡単に JSON を扱いたいので、外部ライブラリをインストールします。VisualStudio の「NuGet パッケージの管理」から外部ライブラリのインストール画面を開いて、「Newtonsoft.Json」を探してインストールしましょう。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276318/bb716351-6f48-450a-bbf9-435450b94553.png" width=50%>

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276318/b97f2134-8dbc-1d16-4cf7-5d761cb51237.png">

### JSON から必要な部分を取り出してテキストボックスに表示
先ほどインストールした「Newtonsoft.Json」への参照を追加したら、btnTranslate_Click() に JSON から必要な部分を取り出して txtResult に表示するコードを追記します（下3行）。これで翻訳結果を翻訳結果のテキストボックス（txtResult）に表示できるようになりました。

```c#
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
```

```c#:btnTranslate_Click()
private async void btnTranslate_Click(object sender, EventArgs e)
{
    using (var httpClient = new HttpClient())
    {
        using (var request = new HttpRequestMessage(new HttpMethod("POST"), "https://api-free.deepl.com/v2/translate"))
        {
            var contentList = new List<string>();
            contentList.Add("auth_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
            contentList.Add("text=" + txtSource.Text);

            if (radioJA.Checked)
            {
                contentList.Add("target_lang=JA");
            }
            else if (radioEN.Checked)
            {
                contentList.Add("target_lang=EN");
            }

            request.Content = new StringContent(string.Join("&", contentList));
            request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");

            var response = await httpClient.SendAsync(request);

            var resBodyStr = response.Content.ReadAsStringAsync().Result;
            JObject deserial = (JObject)JsonConvert.DeserializeObject(resBodyStr);
            txtResult.Text = deserial["translations"][0]["text"].ToString();
        }
    }
}
```

## 最後にひと処理追加
最後に使い勝手の向上のため、ひと処理追加しましょう。
元の文章（txtSource）の内容が変更されたら、翻訳結果（txtResult）の内容をクリアする処理を追加します。

```c#:txtSource_TextChanged()
private void txtSource_TextChanged(object sender, EventArgs e)
{
    txtResult.Text = "";
}
```

# 完成！
お疲れさまでした！これで完成です。実行して動作確認してみましょう。
元の文章のテキストボックスに文章（英文）を入力し［翻訳］ボタンを押し、翻訳結果が表示されたら成功です！
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276318/3699253d-abbc-c1d1-ad38-28b8ee700260.png" width=64%>

# 次回…
今回、DeepL API を使って翻訳までできました。
次回はこの結果をボイスロイド（CeVIO AI）にしゃべってもらう機能を追加したいと思います～。

こちら →　[C#）DeepL API で翻訳した結果をボイスロイドにしゃべってもらいたい！（２）](https://qiita.com/fuji_t/items/2ff27f9d73a9893c0b86)