自作リアルタイム翻訳ツール

はじめに、この小さなツールの由来について話しましょう。私は11月16日に東京で「AI応用開発の旅」というコミュニティイベントを開催する予定です（https://www.just-agi.com/event.html）。主に中国人向けのイベントなので中国語を使用しますが、友人が日本人を連れてくる予定で、日本語の字幕があるかどうか聞かれました。Teamsを見てみたところ、リアルタイム字幕はあるものの翻訳はありませんでしたので、自分でツールを作ることにしました。

　このツールはWinFormで開発されており、源言語と翻訳後のテキストのみを表示し、その他の部分は透明化しています。リアルタイム翻訳にはMicrosoft Speechの翻訳APIを利用しており、開発には10分ほどしかかからなかったです。

**MainForm.Designer.cs** ファイル：

```csharp
namespace JapneseHelper
{
    partial class MainForm
    {
        /// <summary>
        ///  Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        ///  Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        ///  Required method for Designer support - do not modify
        ///  the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            ZhLab = new Label();
            JaLab = new Label();
            SuspendLayout();
            // 
            // ZhLab
            // 
            ZhLab.BackColor = Color.Transparent;
            ZhLab.Dock = DockStyle.Bottom;
            ZhLab.Font = new Font("Microsoft YaHei UI", 24F);
            ZhLab.ForeColor = Color.White;
            ZhLab.Location = new Point(0, 530);
            ZhLab.Margin = new Padding(5, 0, 5, 0);
            ZhLab.Name = "ZhLab";
            ZhLab.Size = new Size(2259, 67);
            ZhLab.TabIndex = 0;
            ZhLab.Text = "这里是字幕";
            ZhLab.TextAlign = ContentAlignment.MiddleCenter;
            ZhLab.MouseDown += ControlMouseDown;
            ZhLab.MouseMove += ControlMouseMove;
            ZhLab.MouseUp += ControlMouseUp;
            // 
            // JaLab
            // 
            JaLab.BackColor = Color.Transparent;
            JaLab.Dock = DockStyle.Fill;
            JaLab.Font = new Font("Microsoft YaHei UI", 32F);
            JaLab.ForeColor = Color.White;
            JaLab.Location = new Point(0, 0);
            JaLab.Margin = new Padding(5, 0, 5, 0);
            JaLab.Name = "JaLab";
            JaLab.Size = new Size(2259, 530);
            JaLab.TabIndex = 1;
            JaLab.TextAlign = ContentAlignment.BottomCenter;
            JaLab.MouseDown += ControlMouseDown;
            JaLab.MouseMove += ControlMouseMove;
            JaLab.MouseUp += ControlMouseUp;
            // 
            // MainForm
            // 
            AutoScaleDimensions = new SizeF(19F, 41F);
            AutoScaleMode = AutoScaleMode.Font;
            BackColor = Color.Black;
            BackgroundImageLayout = ImageLayout.Stretch;
            ClientSize = new Size(2259, 597);
            Controls.Add(JaLab);
            Controls.Add(ZhLab);
            DoubleBuffered = true;
            Font = new Font("Microsoft YaHei UI", 16F);
            FormBorderStyle = FormBorderStyle.None;
            Margin = new Padding(5);
            Name = "MainForm";
            Text = "字幕";
            TopMost = true;
            TransparencyKey = Color.Black;
            Load += MainForm_Load;
            ResumeLayout(false);
        }

        #endregion
        private Label ZhLab;
        private Label JaLab;
    }
}
```

**MainForm.cs** ファイル：

```csharp
using Microsoft.CognitiveServices.Speech;
using Microsoft.CognitiveServices.Speech.Translation;

namespace JapneseHelper
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }
        private void MainForm_Load(object sender, EventArgs e)
        {
            var sourceLanguage = System.Configuration.ConfigurationManager.AppSettings["sourceLanguage"];
            var targetLanguage = System.Configuration.ConfigurationManager.AppSettings["targetLanguage"];
            var apikey = System.Configuration.ConfigurationManager.AppSettings["apikey"];
            var region = System.Configuration.ConfigurationManager.AppSettings["region"];
            var config = SpeechTranslationConfig.FromSubscription(apikey, region);
            config.SpeechRecognitionLanguage = sourceLanguage;
            config.AddTargetLanguage(targetLanguage);
            var recognizer = new TranslationRecognizer(config);
            recognizer.Recognizing += (s, e) =>
            {
                this.Invoke(() =>
                {
                    ZhLab.Text = e.Result.Text;
                    foreach (var element in e.Result.Translations)
                    {
                        JaLab.Text = element.Value;
                    }
                });
            };

            recognizer.StartContinuousRecognitionAsync().ConfigureAwait(false).GetAwaiter();
        }
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            Rectangle workingArea = Screen.PrimaryScreen.WorkingArea;
            var x = (workingArea.Width - this.Width) / 2 + workingArea.Left;
            var y = workingArea.Bottom - this.Height;
            this.Location = new Point(x, y);
        }

        private Point mouseOffset;
        private bool isMouseDown = false;
        private void ControlMouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                mouseOffset = new Point(-e.X, -e.Y);
                isMouseDown = true;
            }
        }
        private void ControlMouseMove(object sender, MouseEventArgs e)
        {
            if (isMouseDown)
            {
                Point mousePos = Control.MousePosition;
                mousePos.Offset(mouseOffset.X, mouseOffset.Y - this.Height / 2);
                this.Location = mousePos;
            }
        }
        private void ControlMouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                isMouseDown = false;
            }
        }
    }
}
```

**効果画像：**

![画像](https://mmbiz.qpic.cn/sz_mmbiz_png/4CAA63nvHRBqo7eLd9wQooYFOnKrOrEc1Eic1IiaMWPJQ8f1JSNRKsCzPBUtmy4Z1om0Acic2Y9JQdm5b7yicabS7w/640?wx_fmt=png&from=appmsg)

　ちょうど今週、営業部との会議で数回試用しましたが、全体的な意味は理解でき、現場の環境とも少し関係がありました。

(Translated by GPT)