【Unity】エディタ上でGoogle翻訳が使えるEditor拡張 GoogleTranslateWindow

# 📖概要
エディタ上でGoogle翻訳が使えるEditor拡張「GoogleTranslateWindow」を作りました。
メニューバーから Tools -> Utility -> GoogleTranslateWindow をクリックするとウィンドウが開きます。

![GoogleTranslateWindow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307985/faa7c44f-16d1-c674-c44e-d373bb552578.png)

# 📜コード

<details><summary>GoogleTranslateWindow.cs</summary><div>

このコードはEditorフォルダに入れてください。

``` GoogleTranslateWindow.cs
using UnityEngine;
using UnityEditor;

public class GoogleTranslateWindow : EditorWindow
{
    GoogleTranslate.Language
        sourceLang, beforeSourceLang,
        targetLang, beforeTargetLang;
    string inputText, outputText;

    Vector2 inputTextScroll, outputTextScroll;

    GoogleTranslate translate;

    [MenuItem("Tools/Utility/GoogleTranslateWindow")]
    static void ShowWindow()
    {
        GetWindow<GoogleTranslateWindow>("GoogleTranslate");
    }

    void OnGUI()
    {
        EditorGUILayout.BeginVertical();
        {
            sourceLang = (GoogleTranslate.Language)EditorGUILayout.EnumPopup(sourceLang);
            if (beforeSourceLang != sourceLang) translate.SetSourceLanguage(sourceLang);

            inputTextScroll = EditorGUILayout.BeginScrollView(inputTextScroll);
            inputText = EditorGUILayout.TextArea(inputText, GUILayout.ExpandHeight(true));
            EditorGUILayout.EndScrollView();


            EditorGUILayout.BeginHorizontal();
            {
                EditorGUILayout.LabelField("↓", GUILayout.MaxWidth(24f));

                if (GUILayout.Button("Swap"))
                {
                    SwapLanguage();
                    GUI.FocusControl("");
                }

                EditorGUILayout.EndHorizontal();
            }


            targetLang = (GoogleTranslate.Language)EditorGUILayout.EnumPopup(targetLang);
            if (beforeTargetLang != targetLang) translate.SetTargetLanguage(targetLang);

            outputTextScroll = EditorGUILayout.BeginScrollView(outputTextScroll);
            outputText = EditorGUILayout.TextArea(outputText, GUILayout.ExpandHeight(true));
            EditorGUILayout.EndScrollView();


            EditorGUILayout.EndVertical();
        }


        if (GUILayout.Button("Translate"))
        {
            Run();
            GUI.FocusControl("");
        }
    }

    private void Run()
    {
        outputText = "Translating...";
        translate.Run(inputText, (text) =>
        {
            outputText = text;
        });
    }

    private void SwapLanguage()
    {
        var tempLang = targetLang;
        targetLang = sourceLang;
        sourceLang = tempLang;

        string tempText = outputText;
        outputText = inputText;
        inputText = tempText;
    }

    private void OnEnable()
    {
        sourceLang = (GoogleTranslate.Language)int.Parse(EditorUserSettings.GetConfigValue(nameof(GoogleTranslateWindow) + nameof(sourceLang)));
        targetLang = (GoogleTranslate.Language)int.Parse(EditorUserSettings.GetConfigValue(nameof(GoogleTranslateWindow) + nameof(targetLang)));

        translate = new GoogleTranslate();
        translate.SetLanguage(sourceLang, targetLang);
    }

    private void OnDisable()
    {
        EditorUserSettings.SetConfigValue(nameof(GoogleTranslateWindow) + nameof(sourceLang), ((int)sourceLang).ToString());
        EditorUserSettings.SetConfigValue(nameof(GoogleTranslateWindow) + nameof(targetLang), ((int)targetLang).ToString());
    }
}
```

</div></details>

<details><summary>GoogleTranslate.cs</summary><div>

``` GoogleTranslate.cs
using System.Collections.Generic;
using UnityEngine;
using System;
using UnityEngine.Networking;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;

public class GoogleTranslate
{
    const string URL = "https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}";

    public enum Language
    {
        UnKnown,
        Afrikaans,
        Albanian,
        Amharic,
        Arabic,
        Armenian,
        Azerbaijani,
        Basque,
        Belarusian,
        Bengali,
        Bosnian,
        Bulgarian,
        Catalan,
        Cebuano,
        Chinese_Simplified,
        Chinese_Traditional,
        Corsican,
        Croatian,
        Czech,
        Danish,
        Dutch,
        English,
        Esperanto,
        Estonian,
        Finnish,
        French,
        Frisian,
        Galician,
        Georgian,
        German,
        Greek,
        Gujarati,
        HaitianCreole,
        Hausa,
        Hawaiian,
        Hebrew,
        Hindi,
        Hmong,
        Hungarian,
        Icelandic,
        Igbo,
        Indonesian,
        Irish,
        Italian,
        Japanese,
        Javanese,
        Kannada,
        Kazakh,
        Khmer,
        Kinyarwanda,
        Korean,
        Kurdish,
        Kyrgyz,
        Lao,
        Latvian,
        Lithuanian,
        Luxembourgish,
        Macedonian,
        Malagasy,
        Malay,
        Malayalam,
        Maltese,
        Maori,
        Marathi,
        Mongolian,
        Myanmar,
        Nepali,
        Norwegian,
        Nyanja,
        Odia_Oriya,
        Pashto,
        Persian,
        Polish,
        Portuguese,
        Punjabi,
        Romanian,
        Russian,
        Samoan,
        Scots,
        Serbian,
        Sesotho,
        Shona,
        Sindhi,
        Sinhala,
        Slovak,
        Slovenian,
        Somali,
        Spanish,
        Sundanese,
        Swahili,
        Swedish,
        Tagalog,
        Tajik,
        Tamil,
        Tatar,
        Telugu,
        Thai,
        Turkish,
        Turkmen,
        Ukrainian,
        Urdu,
        Uyghur,
        Uzbek,
        Vietnamese,
        Welsh,
        Xhosa,
        Yiddish,
        Yoruba,
        Zulu,
    }

    public static readonly Dictionary<string, string> ISOCodes = new Dictionary<string, string>()
    {
        {"UnKnown", "auto"},
        {"Afrikaans", "af"},
        {"Albanian", "sq"},
        {"Amharic", "am"},
        {"Arabic", "ar"},
        {"Armenian", "hy"},
        {"Azerbaijani", "az"},
        {"Basque", "eu"},
        {"Belarusian", "be"},
        {"Bengali", "bn"},
        {"Bosnian", "bs"},
        {"Bulgarian", "bg"},
        {"Catalan", "ca"},
        {"Cebuano", "ceb"},
        {"Chinese_Simplified", "zh"},
        {"Chinese_Traditional", "zh-TW"},
        {"Corsican", "co"},
        {"Croatian", "hr"},
        {"Czech", "cs"},
        {"Danish", "da"},
        {"Dutch", "nl"},
        {"English", "en"},
        {"Esperanto", "eo"},
        {"Estonian", "et"},
        {"Finnish", "fi"},
        {"French", "fr"},
        {"Frisian", "fy"},
        {"Galician", "gl"},
        {"Georgian", "ka"},
        {"German", "de"},
        {"Greek", "el"},
        {"Gujarati", "gu"},
        {"HaitianCreole", "ht"},
        {"Hausa", "ha"},
        {"Hawaiian", "haw"},
        {"Hebrew", "he"},
        {"Hindi", "hi"},
        {"Hmong", "hmn"},
        {"Hungarian", "hu"},
        {"Icelandic", "is"},
        {"Igbo", "ig"},
        {"Indonesian", "id"},
        {"Irish", "ga"},
        {"Italian", "it"},
        {"Japanese", "ja"},
        {"Javanese", "jv"},
        {"Kannada", "kn"},
        {"Kazakh", "kk"},
        {"Khmer", "km"},
        {"Kinyarwanda", "rw"},
        {"Korean", "ko"},
        {"Kurdish", "ku"},
        {"Kyrgyz", "ky"},
        {"Lao", "lo"},
        {"Latvian", "lv"},
        {"Lithuanian", "lt"},
        {"Luxembourgish", "lb"},
        {"Macedonian", "mk"},
        {"Malagasy", "mg"},
        {"Malay", "ms"},
        {"Malayalam", "ml"},
        {"Maltese", "mt"},
        {"Maori", "mi"},
        {"Marathi", "mr"},
        {"Mongolian", "mn"},
        {"Myanmar", "my"},
        {"Nepali", "ne"},
        {"Norwegian", "no"},
        {"Nyanja", "ny"},
        {"Odia_Oriya", "or"},
        {"Pashto", "ps"},
        {"Persian", "fa"},
        {"Polish", "pl"},
        {"Portuguese", "pt"},
        {"Punjabi", "pa"},
        {"Romanian", "ro"},
        {"Russian", "ru"},
        {"Samoan", "sm"},
        {"Scots", "gd"},
        {"Serbian", "sr"},
        {"Sesotho", "st"},
        {"Shona", "sn"},
        {"Sindhi", "sd"},
        {"Sinhala", "si"},
        {"Slovak", "sk"},
        {"Slovenian", "sl"},
        {"Somali", "so"},
        {"Spanish", "es"},
        {"Sundanese", "su"},
        {"Swahili", "sw"},
        {"Swedish", "sv"},
        {"Tagalog", "tl"},
        {"Tajik", "tg"},
        {"Tamil", "ta"},
        {"Tatar", "tt"},
        {"Telugu", "te"},
        {"Thai", "th"},
        {"Turkish", "tr"},
        {"Turkmen", "tk"},
        {"Ukrainian", "uk"},
        {"Urdu", "ur"},
        {"Uyghur", "ug"},
        {"Uzbek", "uz"},
        {"Vietnamese", "vi"},
        {"Welsh", "cy"},
        {"Xhosa", "xh"},
        {"Yiddish", "yi"},
        {"Yoruba", "yo"},
        {"Zulu", "zu"},
    };


    public string SourceLangCode { get; private set; } = "auto";
    public string TargetLangCode { get; private set; } = "auto";

    public void SetSourceLanguage(Language lang)
    {
        ISOCodes.TryGetValue(lang.ToString(), out string tempLangCode);
        SourceLangCode = tempLangCode;
    }
    public void SetTargetLanguage(Language lang)
    {
        ISOCodes.TryGetValue(lang.ToString(), out string tempLangCode);
        TargetLangCode = tempLangCode;
    }
    public void SetLanguage(Language sourceLang, Language targetLang)
    {
        SetSourceLanguage(sourceLang);
        SetTargetLanguage(targetLang);
    }

    public async void Run(string text, Action<string> result)
    {
        WWWForm form = new WWWForm();

        UnityWebRequest request =
            UnityWebRequest.Post(
                String.Format(URL, new object[] { SourceLangCode, TargetLangCode, text }),
                form);

        await request.SendWebRequest();

        if (!string.IsNullOrEmpty(request.error)) result(null);

        // Extracts the translated text from the received string
        int index = request.downloadHandler.text.IndexOf("\",\"");
        string tempText = request.downloadHandler.text.Substring(4, index - 4);
        result(Regex.Unescape(tempText));
    }
}

#region UnityWebRequestAwaiter
public class UnityWebRequestAwaiter : INotifyCompletion
{
    private UnityWebRequestAsyncOperation asyncOperation;
    private Action continuation;

    public UnityWebRequestAwaiter(UnityWebRequestAsyncOperation asyncOp)
    {
        this.asyncOperation = asyncOp;
        asyncOp.completed += OnRequestCompleted;
    }

    public bool IsCompleted { get { return asyncOperation.isDone; } }

    public void GetResult() { }

    public void OnCompleted(Action continuation)
    {
        this.continuation = continuation;
    }

    private void OnRequestCompleted(AsyncOperation asyncOp)
    {
        continuation.Invoke();
    }
}
public static class UnityWebRequestAsyncOperationExtension
{
    public static UnityWebRequestAwaiter GetAwaiter(this UnityWebRequestAsyncOperation asyncOperation)
    {
        return new UnityWebRequestAwaiter(asyncOperation);
    }
}
#endregion
```

</div></details>