#背景
TerrariaというゲームでModを利用するのに、ゲーム中にリアルタイムで英語を翻訳したくなり、とりあえず簡単に出来そうな方法でやってみたものです。
#方法
APIは有料ですし、許されるであろう方法としてブラウザーでアクセスするのと同じ手段で翻訳する事にしました。
まずは試しに翻訳する文字列を含めたUrlを送って、DocumentCompletedで読み取ってみようとしましたが、うまくいきませんでしたので、翻訳ボタンを押して少し待機して結果欄から読み取る方法としています。
タスクの処理など含めて、まだまだ微妙なところはありますが、とりあえず次の方法で実現できています。
WebBrowserを利用しているのは、単に操作が楽であったのと、Terrariaで利用できる方法であったからです。
他の方法でもやりようはあると思いますし、そういったサンプルも他に多数あるかと思います。
#実際のコード
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TooltipTranslator
{
public class Translat
{
private WebBrowser web;
private string sourceLang;
private string resultLang;
private Dictionary<string, string> dic;
private List<string> list;
private bool isLoaded;
private bool isRunning;
public Translat(string sourceLang, string resultLang)
{
this.sourceLang = sourceLang;
this.resultLang = resultLang;
web = new WebBrowser();
web.ScriptErrorsSuppressed = true;
web.Navigate($"https://translate.google.co.jp/#{sourceLang}/{resultLang}");
web.DocumentCompleted += (a, b) => isLoaded = true;
dic = new Dictionary<string, string>();
list = new List<string>();
}
public string Translation(string src)
{
string result = string.Empty;
if (!dic.ContainsKey(src))
{
dic.Add(src, "");
list.Add(src);
}
else
{
result = dic[src];
}
if (isLoaded && 0 < list.Count && !isRunning)
{
isRunning = true;
Task.Run(() =>
{
try
{
while (0 < list.Count)
{
string str = list[0];
var source = GetElementById("source");
var submit = GetElementById("gt-submit");
var result_box = GetElementById("result_box");
source.InnerText = str;
submit.InvokeMember("click");
while (true)
{
Task.Delay(10);
if (result_box.InnerText != null && !result_box.InnerText.Equals("翻訳しています..."))
{
dic[str] = result_box.InnerText;
result_box.InnerText = null;
list.RemoveAt(0);
break;
}
}
}
}
catch { }
isRunning = false;
});
}
return result;
}
private HtmlElement GetElementById(string id)
{
HtmlElement result = null;
if (web.InvokeRequired)
{
web.Invoke((MethodInvoker)delegate () { result = GetElementById(id); });
}
else
{
result = web.Document.GetElementById(id);
}
return result;
}
}
}
#利用方法
このコードはTerrariaというゲームで、アイテムにカーソルを合わせた際に表示されるツールチップを置き換える際に利用しています。
ツールチップの表示はカーソルを合わしている間、毎フレーム読込まれるので、翻訳が出来た瞬間に、string.Empty以外が返されて、その翻訳されたテキストに置き換えるようにしています。
#課題
翻訳された際に明確に結果を得たい場合、同期処理とするか、あるいは翻訳完了時に通知するなりの対応が必要になるかと思います。
Google翻訳の仕様を十分に把握しておらず、もっと確実な方法があるかもしれませんので、その辺を調べる必要があるかとは思っています。