あきちゃんの飽き飽き備忘録

ほぼ死んでるブログ

【Qiita Advent Calender 2022】Blazor+Radzen & みんなの翻訳でLine風翻訳あぷりつくってみたよ

初めまして、アキちゃんです。

備忘録をかねてブログを書くことにしました。

今回は初の試みで、Qiita Advent Calender 2022に記事を書いてみることにしました。

内容は「Blazor+Radzen & みんなの自動翻訳@TexTraでLine風翻訳あぷりつくってみたよ」です。

それでは早速・・・

Blazor+Radzen & みんなの自動翻訳@TexTraでLine風翻訳あぷり

(ピクチャインピクチャじゃないと潰れてほぼみえませんね・・・)

Lesson.0 事前準備

ある程度の準備はしておきたいと思います。

1.Blazor Serverのプロジェクトの作成し、Radzen導入だけ済ませたものを用意します。本記事では、プロジェクトの名前は"Honya-kun"として作成します。

akr9915.hatenablog.com

2.みんなの自動翻訳@TexTraのAPIを使いたいため、以下サイトでユーザー登録を行います。

mt-auto-minhon-mlt.ucri.jgn-x.jp

3.2で登録したユーザー情報で、みんなの自動翻訳@TexTraにログインしユーザーの設定からWeb APIAPI keyとAPI secretを確認します。(併せてユーザーIDも後で使うので覚えておきます)

Lesson.1 みんなの自動翻訳API

まずみんなの自動翻訳のAPIを使えるようにしたいため、サイトから公開されているソースコードを取得したいとおもいます。

Dataフォルダを右クリックし"追加"→"クラス"Textra.csを追加し、作成されたファイルのソースコードをすべて消します。

みんなの自動翻訳のページに行きログイン→Web APIのページに行きます。

Web API一覧から自動翻訳リクエスト-一覧をクリック

汎用NT 【 英語 - 日本語 】のAPIのインフォメーションアイコンをクリックします。

自動翻訳 WebAPIという画面が表示されるので、下の方にスクロールしていくとアクセス例がでてきます。OAuth→C#を選択し少し下にスクロールしusing System;・・以下をまるまるコピーして先ほど追加したTextra.csにまるまるペーストします。

貼り付けたソースコードの13行目、724行目、764行目を削除します。

13行目 不要な参照のため削除
using System.Windows.Forms;
724行目 設定は明示的にしたいため削除
private static TexTraPlugin.Properties.Settings MySettings = TexTraPlugin.Properties.Settings.Default;
764行目 ASP.Netでは使えない関数のため削除
if (show_message) MessageBox.Show("XMLの読込に失敗しました。\n\n" + e.Message);

724行目を削除した段階でおびただしい数のエラーが発生します、代わりの構造体を用意してあげるために22行目APIAccessor_jaの宣言の直下に以下のコードを追加します。

    public static class APIAccessor_ja
    {
        private static TexTraPlugin MySettings = new TexTraPlugin()
        {
          API_URL = "",
          API_KEY = "",
          API_SECRET = "",
          API_USER = ""
        };
        public class TexTraPlugin
        {
            public string API_自動翻訳 { get; set; }
            public string API_URL { get; set; }
            public string API_KEY { get; set; }
            public string API_SECRET { get; set; }
            public string API_USER { get; set; }
            public string proxy { get; set; }
            public string proxy_id { get; set; }
            public string proxy_password { get; set; }
            public int proxy_port { get; set; }
        }
      #region "API"

371行目辺りにinit_settings()という関数がありますが、この中に定義されているUrlが若干違うのでgeneral→generalNTに修正します。

"https://mt-auto-minhon-mlt.ucri.jgn-x.jp/api/mt/generalNT_zh-CN_ja/"
"https://mt-auto-minhon-mlt.ucri.jgn-x.jp/api/mt/generalNT_zh-TW_ja/"
"https://mt-auto-minhon-mlt.ucri.jgn-x.jp/api/mt/generalNT_ja_zh-CN/"
"https://mt-auto-minhon-mlt.ucri.jgn-x.jp/api/mt/generalNT_ja_zh-TW/"
"https://mt-auto-minhon-mlt.ucri.jgn-x.jp/api/mt/generalNT_ja_en/"
"https://mt-auto-minhon-mlt.ucri.jgn-x.jp/api/mt/generalNT_ja_ko/"
"https://mt-auto-minhon-mlt.ucri.jgn-x.jp/api/mt/generalNT_en_ja/"
"https://mt-auto-minhon-mlt.ucri.jgn-x.jp/api/mt/generalNT_ko_ja/"

実際のところは"https://mt-auto-minhon-mlt.ucri.jgn-x.jp/api/mt/generalNT_ja_en/"だけ変えればいいんですが、今後使う機会があるかもしれないので全部変えておきましょう。

24行目に追加したMySettingsに設定を入れようと思います。

API_URLは今回日本語→英語の想定なので"https://mt-auto-minhon-mlt.ucri.jgn-x.jp/api/mt/generalNT_ja_en/"を入力します。それ以外の項目はLesson.0で確認した値を入力します。

private static TexTraPlugin MySettings = new TexTraPlugin()
{
      API_URL = "https://mt-auto-minhon-mlt.ucri.jgn-x.jp/api/mt/generalNT_ja_en/",
      API_KEY = "ここは自分のAPI Keyを入れます",
      API_SECRET = "ここは自分のAPI Secretを入れます",
      API_USER = "ここは自分のUser Nameを入れます"
};

API Keyはユニークであり、第三者に知られると悪用されることもあるため絶対に自分以外の人間にはばれないようにしましょう。(というか知られたら120%悪用されると思ってください)

ここまできたら動くか確認しましょう、Pages/Counter.razorを以下のように修正します。

@page "/counter"
@using static TexTra.APIAccessor_ja
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
<RadzenTextBox @bind-Value=@orgValue></RadzenTextBox>
<RadzenTextBox @bind-Value=@newValue></RadzenTextBox>
@code {
    private int currentCount = 0;
    string orgValue = string.Empty;
    string newValue = string.Empty;
    private void IncrementCount()
    {
        currentCount++;
        var get = TexTra.APIAccessor_ja.get_auto_trans(orgValue, Language.ja, Language.en, out APIResponseBean aPIResponseBean);
        if (get.Any())
        {
            newValue = ((TexTra.APIAccessor_ja.AutoTransInfo)get[0].value).text_translated;
        }
    }
}

アプリケーションを起動しCounterに遷移します。

左側のテキストボックスに”野球”と入力し、Click meを押下後右側のテキストボックスにBaseballと表示されたらここまでは完了です。

Lesson.2 Line風導入

あとはLine風の送信画面を追加しようと思います。

RadzenにはHtmlEditorがあるので、これにCssを反映させてそれっぽい画面を作っていこうと思います。

Line風のCssは以下サイトを参考にさせてもらおうと思います。

jisuijisan.com

Pagesフォルダを右クリック後、追加→RadzenコンポーネントからChat.razorを追加し、Chat.razorに作成時書かれているコードを削除します。

取り敢えず上記のサイトように表示できることを確認したいため、HtmlとCssを拝借して以下のコードをChar.razorにコピペします。

Char.razor(クリックで展開) Char.razor(クリックで圧縮)
@page "/chat"
<RadzenHtmlEditor @bind-Value=@value></RadzenHtmlEditor>
@code {
    string value = string.Empty;
    string chatCss
    {
        get => "<style>" +
               "/*==============" +
               "LINE風フキダシ" +
               "===============*/" +
               "/*フレームとフォント*/" +
               ".kaiwa.line {" +
               "    width: 100%;" +
               "    max-width: 500px;" +
               "    margin: 0 auto;" +
               "    padding: 10px 0;" +
               "    background: #769ece;" +
               "    font-family: \"ヒラギノ角ゴ Pro W3\",\"Hiragino Kaku Gothic Pro\",\"Helvetica Neue\", \"Lucida Sans Unicode\", \"Arial\";" +
               "    font-size: 16px;" +
               "    color: #333;" +
               "    line-height: 1.4;" +
               "    overflow: hidden;" +
               "}" +
               "/*フキダシ共通*/" +
               ".kaiwa.line .fukidasi {" +
               "    position: relative;" +
               "    display: inline-block;" +
               "    max-width: 192px;" +
               "    margin: 8px 0 0;" +
               "    padding: 9px 14px;" +
               "    border-radius: 19px;" +
               "    overflow-wrap: break-word;" +
               "    clear: both;" +
               "    box-sizing: content-box;/*はてな用*/" +
               "}" +
               "/*フキダシ左*/" +
               ".kaiwa.line .fukidasi.left {" +
               "    float: left;" +
               "    margin-left: 62px;" +
               "    background: white;" +
               "}" +
               "/*グループのときのフキダシ*/" +
               ".kaiwa.line .name + .fukidasi.left {" +
               "    margin-top: 5px;" +
               "}" +
               "/*フキダシ右*/" +
               ".kaiwa.line .fukidasi.right {" +
               "    float: right;" +
               "    margin-right: 12px;" +
               "    background: #7adc40;" +
               "}" +
               "/*相手の名前*/" +
               ".kaiwa.line .name {" +
               "    clear: right;" +
               "    margin-left: 62px;" +
               "    color: white;" +
               "}" +
               "/*ユーザアイコン*/" +
               ".kaiwa.line .icon {" +
               "    position: absolute;" +
               "    width: 40px;" +
               "    height: 40px;" +
               "    left: -54px;" +
               "    top: -2px;" +
               "    border-radius: 20px;" +
               "}" +
               "/*グループのときのユーザアイコン*/" +
               ".kaiwa.line .name + .left .icon {" +
               "    top: -1.8em;" +
               "}" +
               "/*しっぽ共通*/" +
               ".kaiwa.line .fukidasi::after {" +
               "    position: absolute;" +
               "    content: \"\";" +
               "    width: 24px;" +
               "    height: 36px;" +
               "    top: -21px;" +
               "}" +
               "/*しっぽ左*/" +
               ".kaiwa.line .fukidasi.left:after {" +
               "    left: -10px;" +
               "    border-radius: 18px 0 6px 18px/18px 0 1px 18px;" +
               "    box-shadow: -3px -15px 0 -5px white inset;" +
               "}" +
               "/*しっぽ右*/" +
               ".kaiwa.line .fukidasi.right::after {" +
               "    right: -10px;" +
               "    border-radius: 0 18px 18px 6px/0 18px 18px 1px;" +
               "    box-shadow: inset 3px -15px 0 -5px #7adc40;" +
               "}" +
               "/*フキダシが続いてしっぽがないとき*/" +
               ".kaiwa.line .left + .left::after," +
               ".kaiwa.line .right + .right::after {" +
               "    content: none;" +
               "}"+
               "</style>" ;
    }
    protected override void OnParametersSet()
    {
        value = chatCss;
        value += "<div class=\"kaiwa line\">"+
        "    <div class=\"name\">"+
        "        おなまえ"+
        "    </div>"+
        "    <div class=\"fukidasi left\">"+
        "        <img class=\"icon\" src=\"img/icon.png\" alt=\"\">LINE風です。"+
        "    </div>"+
        "    <div class=\"fukidasi left\">"+
        "        続けて喋るとフキダシのしっぽはつきません。"+
        "    </div>"+
        "    <div class=\"fukidasi right\">"+
        "        HTMLとCSSでできます。"+
        "    </div>"+
        "    <br><!-- 次のフキダシにしっぽをつけたいときはbrを挿入 -->"+
        "    <div class=\"fukidasi right\">"+
        "        続けても、しっぽをつけたいときは間にbrを入れます。"+
        "    </div>"+
        "    <div class=\"fukidasi left\">"+
        "        <img class=\"icon\" src=\"img/icon.png\" alt=\"\">グループじゃないとき。" +
        "    </div>" +
        "</div>";
    }
}

Shared/NavMenu.razorのNavLinkに以下のコードを追加します。

  <div class="nav-item px-3">
          <NavLink class="nav-link" href="chat">
              <span class="oi oi-chat" aria-hidden="true"></span>Chat
            </NavLink>
  </div>

ここまできたら動くか確認しましょう、アプリを実行し左のタブからChatに移動し、以下画面が表示されたらここまでは完了です。

Lesson.3 Line風画面Component化

上記までである程度できてきましたが、もう少しそれっぽい画面にしたいと思います。

プロジェクトにComponentsフォルダを作成し、そのフォルダにLineChat.razorを作成します。

作成したLineChat.razorに以下のコードを貼り付けます。

<RadzenHtmlEditor @bind-Value=@Value class="w-100" style="font-family:Source Han Code JP;height:100%;" UploadUrl="upload/image" Disabled=@false>
    <RadzenHtmlEditorSeparator />
</RadzenHtmlEditor>
@code {
    string _Value = string.Empty;
    [Parameter]
    public string Value
    {
        get => _Value;
        set
        {
            if (_Value == value) return;
            _Value = value;
            ValueChanged.InvokeAsync(value);
        }
    }
    [Parameter]
    public EventCallback<string> ValueChanged { get; set; }
}

Pages/Chat.razorを以下のように修正します。

@page "/chat"
@using Radzen
<RadzenSplitter Orientation="Orientation.Vertical" Style="height:850px;">
    <RadzenSplitterPane Size="90%">
        <div class="h-100" style="overflow-y: scroll;">
            <Honya_kun.Components.LineChat @bind-Value=@value></Honya_kun.Components.LineChat>
        </div>
    </RadzenSplitterPane>
    <RadzenSplitterPane Size="10%">
        <RadzenSplitter Orientation="Orientation.Horizontal">
            <RadzenSplitterPane Size="70%">
                <RadzenTextArea class="w-100 h-100" @bind-Value=@sendStr></RadzenTextArea>
            </RadzenSplitterPane>
            <RadzenSplitterPane Size="30%">
                <RadzenButton class="w-100 h-100" Text="送信" Click=@SendClick></RadzenButton>
            </RadzenSplitterPane>
        </RadzenSplitter>
    </RadzenSplitterPane>
</RadzenSplitter>
@code {
    string value = string.Empty;
    string sendStr = string.Empty;
  string chatCss・・・(省略)
    protected override void OnParametersSet()
    {
        value = chatCss;
        value += "<div class=\"kaiwa line\">" +
        "    <div class=\"name\">" +
        "        ほんやくん" +
        "    </div>" +
        "    <div class=\"fukidasi left\">" +
        "        <img class=\"icon\" src=\"img/icon.png\" alt=\"\">LINE風です。" +
        "    </div>" +
        "    <div class=\"fukidasi left\">" +
        "        続けて喋るとフキダシのしっぽはつきません。" +
        "    </div>" +
        "    <div class=\"fukidasi right\">" +
        "        HTMLとCSSでできます。" +
        "    </div>" +
        "    <br><!-- 次のフキダシにしっぽをつけたいときはbrを挿入 -->" +
        "    <div class=\"fukidasi right\">" +
        "        続けても、しっぽをつけたいときは間にbrを入れます。" +
        "    </div>" +
        "    <div class=\"fukidasi left\">" +
        "        <img class=\"icon\" src=\"img/icon.png\" alt=\"\">グループじゃないとき。" +
        "    </div>" +
        "</div>";
    }
    async Task SendClick()
    {
        await Task.Delay(100);
    }
}

chatCss { get => を以下のように修正します。

 get => "<style>" +
               "/*==============" +
               "LINE風フキダシ" +
               "===============*/" +
               "/*フレームとフォント*/" +
               ".kaiwa.line {" +
               "    width: 100%;" +
               "    height:100%;" +
               //"    max-width: 500px;" +
               "    margin: 0 auto;" +
               "    padding: 10px 0;" +
               "    background: #769ece;" +
Console.WriteLine("Hello, World!");

ここまできたら実行してみて以下画面が表示されたらここまでは完成です。

Lesson.4 送信ボタン実装

任意のテキストを送り変換する送信ボタンを実装しようと思います。

まず、通信している間のBusyフラグを追加します。

@using static TexTra.APIAccessor_ja
<RadzenSplitter Orientation="Orientation.Vertical" Style="height:850px;">
    <RadzenSplitterPane Size="90%">
        <div class="h-100" style="overflow-y: scroll;">
            <Honya_kun.Components.LineChat @bind-Value=@value></Honya_kun.Components.LineChat>
        </div>
    </RadzenSplitterPane>
    <RadzenSplitterPane Size="10%">
        <RadzenSplitter Orientation="Orientation.Horizontal">
            <RadzenSplitterPane Size="70%">
                <RadzenTextArea class="w-100 h-100" @bind-Value=@sendStr></RadzenTextArea>
            </RadzenSplitterPane>
            <RadzenSplitterPane Size="30%">
              <RadzenButton class="w-100 h-100" Text="送信" Click=@SendClick  IsBusy=@IsBusy BusyText="通信中"></RadzenButton>
            </RadzenSplitterPane>
        </RadzenSplitter>
    </RadzenSplitterPane>
</RadzenSplitter>
@code {
    string value = string.Empty;
    string sendStr = string.Empty;
  bool IsBusy = false;

OnParameterSet()の中を以下のように修正します。

    protected override void OnParametersSet()
    {
        value = chatCss;
        value +=
        "<div class=\"kaiwa line\">" +
        "    <div class=\"name\">" +
        "        ほんやくん" +
        "    </div>" +
        "    <div class=\"fukidasi left\">" +
        "        <img class=\"icon\" src=\"img/icon.png\" alt=\"\">こんにちは!" +
        "    </div>" +
        "    <div class=\"fukidasi left\">" +
        "        日本語→英語の翻訳ができるほんや君です!" +
        "    </div>" +
        " </div>";
  }

SendClickの中を以下のように修正します。

    async Task SendClick()
    {
        if (string.IsNullOrEmpty(sendStr))
        {
            // Nothing
        }
        else
      {
            IsBusy = true;
            List<APIResponseBean> get = new List<APIResponseBean>();
            value = value.TrimEnd(new char[6] { '<', '/', 'd', 'i', 'v', '>' });
            value += "<div class=\"fukidasi right\">" + sendStr + "</div>";
            await Task.WhenAll(new Task[] {
                Task.Factory.StartNew(() => { get = TexTra.APIAccessor_ja.get_auto_trans(sendStr, Language.ja, Language.en, out APIResponseBean aPIResponseBean); }) });

            if (get.Any())
            {
                var newValue = ((TexTra.APIAccessor_ja.AutoTransInfo)get[0].value).text_translated;
              value += "<div class=\"fukidasi left\">><img class=\"icon\" src=\"img/icon.png\" alt=\"\">" + newValue + "</div>";
            }
            else
            {
                value += "<div class=\"fukidasi left\">" + "翻訳できませんでした・・・" + "</div>";
            }
            value += " </div>";
           IsBusy = false;
        }
  }

chatCssのフキダシ共通を以下のように修正します

"/*フキダシ共通*/" +
".kaiwa.line .fukidasi {" +
"    position: relative;" +
"    display: inline-block;" +
"    max-width: 500px;" +
"    margin: 8px 0 0;" +
"    padding: 9px 14px;" +
"    border-radius: 19px;" +
"    overflow-wrap: break-word;" +
"    clear: both;" +
"    box-sizing: content-box;/*はてな用*/" +
"}" +

ほんやくんのアイコンを追加したいのでwwwrootの直下にiconフォルダを作り、おなじみのイラストやさんの力をかりicon..pngをiconフォルダに入れます。

www.irasutoya.com

ここまできたら実行して任意の文字を入力し、送信ボタンを押すとほんやくんが返事してくれると思います!

Lesson.5 あとがき

おもったよりも長い記事になってしまいました、何かの役に立てれば幸いです。

以上!

github.com