diff --git a/NadekoBot/Modules/Translator/Helpers/GoogleTranslator.cs b/NadekoBot/Modules/Translator/Helpers/GoogleTranslator.cs new file mode 100644 index 00000000..beb8f38a --- /dev/null +++ b/NadekoBot/Modules/Translator/Helpers/GoogleTranslator.cs @@ -0,0 +1,330 @@ +// Copyright (c) 2015 Ravi Bhavnani +// License: Code Project Open License +// http://www.codeproject.com/info/cpol10.aspx + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Web; + +namespace NadekoBot.Modules.Translator.Helpers +{ + /// + /// Translates text using Google's online language tools. + /// + public class GoogleTranslator + { + #region Properties + + /// + /// Gets the supported languages. + /// + public static IEnumerable Languages + { + get + { + GoogleTranslator.EnsureInitialized(); + return GoogleTranslator._languageModeMap.Keys.OrderBy(p => p); + } + } + + /// + /// Gets the time taken to perform the translation. + /// + public TimeSpan TranslationTime + { + get; + private set; + } + + /// + /// Gets the url used to speak the translation. + /// + /// The url used to speak the translation. + public string TranslationSpeechUrl + { + get; + private set; + } + + /// + /// Gets the error. + /// + public Exception Error + { + get; + private set; + } + + #endregion + + #region Public methods + + /// + /// Translates the specified source text. + /// + /// The source text. + /// The source language. + /// The target language. + /// The translation. + public string Translate + (string sourceText, + string sourceLanguage, + string targetLanguage) + { + // Initialize + this.Error = null; + this.TranslationSpeechUrl = null; + this.TranslationTime = TimeSpan.Zero; + DateTime tmStart = DateTime.Now; + string translation = string.Empty; + + try + { + // Download translation + string url = string.Format("https://translate.googleapis.com/translate_a/single?client=gtx&sl={0}&tl={1}&dt=t&q={2}", + GoogleTranslator.LanguageEnumToIdentifier(sourceLanguage), + GoogleTranslator.LanguageEnumToIdentifier(targetLanguage), + HttpUtility.UrlEncode(sourceText)); + string outputFile = Path.GetTempFileName(); + using (WebClient wc = new WebClient()) + { + wc.Headers.Add("user-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"); + wc.DownloadFile(url, outputFile); + } + + // Get translated text + if (File.Exists(outputFile)) + { + + // Get phrase collection + string text = File.ReadAllText(outputFile); + int index = text.IndexOf(string.Format(",,\"{0}\"", GoogleTranslator.LanguageEnumToIdentifier(sourceLanguage))); + if (index == -1) + { + // Translation of single word + int startQuote = text.IndexOf('\"'); + if (startQuote != -1) + { + int endQuote = text.IndexOf('\"', startQuote + 1); + if (endQuote != -1) + { + translation = text.Substring(startQuote + 1, endQuote - startQuote - 1); + } + } + } + else { + // Translation of phrase + text = text.Substring(0, index); + text = text.Replace("],[", ","); + text = text.Replace("]", string.Empty); + text = text.Replace("[", string.Empty); + text = text.Replace("\",\"", "\""); + + // Get translated phrases + string[] phrases = text.Split(new[] { '\"' }, StringSplitOptions.RemoveEmptyEntries); + for (int i = 0; (i < phrases.Count()); i += 2) + { + string translatedPhrase = phrases[i]; + if (translatedPhrase.StartsWith(",,")) + { + i--; + continue; + } + translation += translatedPhrase + " "; + } + } + + // Fix up translation + translation = translation.Trim(); + translation = translation.Replace(" ?", "?"); + translation = translation.Replace(" !", "!"); + translation = translation.Replace(" ,", ","); + translation = translation.Replace(" .", "."); + translation = translation.Replace(" ;", ";"); + + // And translation speech URL + this.TranslationSpeechUrl = string.Format("https://translate.googleapis.com/translate_tts?ie=UTF-8&q={0}&tl={1}&total=1&idx=0&textlen={2}&client=gtx", + HttpUtility.UrlEncode(translation), GoogleTranslator.LanguageEnumToIdentifier(targetLanguage), translation.Length); + } + } + catch (Exception ex) + { + this.Error = ex; + } + + // Return result + this.TranslationTime = DateTime.Now - tmStart; + return translation; + } + + #endregion + + #region Private methods + + /// + /// Converts a language to its identifier. + /// + /// The language." + /// The identifier or if none. + private static string LanguageEnumToIdentifier + (string language) + { + string mode = string.Empty; + GoogleTranslator.EnsureInitialized(); + GoogleTranslator._languageModeMap.TryGetValue(language, out mode); + return mode; + } + + /// + /// Ensures the translator has been initialized. + /// + public static void EnsureInitialized() + { + if (GoogleTranslator._languageModeMap == null) + { + GoogleTranslator._languageModeMap = new Dictionary(); + GoogleTranslator._languageModeMap.Add("Afrikaans", "af"); + GoogleTranslator._languageModeMap.Add("Albanian", "sq"); + GoogleTranslator._languageModeMap.Add("Arabic", "ar"); + GoogleTranslator._languageModeMap.Add("Armenian", "hy"); + GoogleTranslator._languageModeMap.Add("Azerbaijani", "az"); + GoogleTranslator._languageModeMap.Add("Basque", "eu"); + GoogleTranslator._languageModeMap.Add("Belarusian", "be"); + GoogleTranslator._languageModeMap.Add("Bengali", "bn"); + GoogleTranslator._languageModeMap.Add("Bulgarian", "bg"); + GoogleTranslator._languageModeMap.Add("Catalan", "ca"); + GoogleTranslator._languageModeMap.Add("Chinese", "zh-CN"); + GoogleTranslator._languageModeMap.Add("Croatian", "hr"); + GoogleTranslator._languageModeMap.Add("Czech", "cs"); + GoogleTranslator._languageModeMap.Add("Danish", "da"); + GoogleTranslator._languageModeMap.Add("Dutch", "nl"); + GoogleTranslator._languageModeMap.Add("English", "en"); + GoogleTranslator._languageModeMap.Add("Esperanto", "eo"); + GoogleTranslator._languageModeMap.Add("Estonian", "et"); + GoogleTranslator._languageModeMap.Add("Filipino", "tl"); + GoogleTranslator._languageModeMap.Add("Finnish", "fi"); + GoogleTranslator._languageModeMap.Add("French", "fr"); + GoogleTranslator._languageModeMap.Add("Galician", "gl"); + GoogleTranslator._languageModeMap.Add("German", "de"); + GoogleTranslator._languageModeMap.Add("Georgian", "ka"); + GoogleTranslator._languageModeMap.Add("Greek", "el"); + GoogleTranslator._languageModeMap.Add("Haitian Creole", "ht"); + GoogleTranslator._languageModeMap.Add("Hebrew", "iw"); + GoogleTranslator._languageModeMap.Add("Hindi", "hi"); + GoogleTranslator._languageModeMap.Add("Hungarian", "hu"); + GoogleTranslator._languageModeMap.Add("Icelandic", "is"); + GoogleTranslator._languageModeMap.Add("Indonesian", "id"); + GoogleTranslator._languageModeMap.Add("Irish", "ga"); + GoogleTranslator._languageModeMap.Add("Italian", "it"); + GoogleTranslator._languageModeMap.Add("Japanese", "ja"); + GoogleTranslator._languageModeMap.Add("Korean", "ko"); + GoogleTranslator._languageModeMap.Add("Lao", "lo"); + GoogleTranslator._languageModeMap.Add("Latin", "la"); + GoogleTranslator._languageModeMap.Add("Latvian", "lv"); + GoogleTranslator._languageModeMap.Add("Lithuanian", "lt"); + GoogleTranslator._languageModeMap.Add("Macedonian", "mk"); + GoogleTranslator._languageModeMap.Add("Malay", "ms"); + GoogleTranslator._languageModeMap.Add("Maltese", "mt"); + GoogleTranslator._languageModeMap.Add("Norwegian", "no"); + GoogleTranslator._languageModeMap.Add("Persian", "fa"); + GoogleTranslator._languageModeMap.Add("Polish", "pl"); + GoogleTranslator._languageModeMap.Add("Portuguese", "pt"); + GoogleTranslator._languageModeMap.Add("Romanian", "ro"); + GoogleTranslator._languageModeMap.Add("Russian", "ru"); + GoogleTranslator._languageModeMap.Add("Serbian", "sr"); + GoogleTranslator._languageModeMap.Add("Slovak", "sk"); + GoogleTranslator._languageModeMap.Add("Slovenian", "sl"); + GoogleTranslator._languageModeMap.Add("Spanish", "es"); + GoogleTranslator._languageModeMap.Add("Swahili", "sw"); + GoogleTranslator._languageModeMap.Add("Swedish", "sv"); + GoogleTranslator._languageModeMap.Add("Tamil", "ta"); + GoogleTranslator._languageModeMap.Add("Telugu", "te"); + GoogleTranslator._languageModeMap.Add("Thai", "th"); + GoogleTranslator._languageModeMap.Add("Turkish", "tr"); + GoogleTranslator._languageModeMap.Add("Ukrainian", "uk"); + GoogleTranslator._languageModeMap.Add("Urdu", "ur"); + GoogleTranslator._languageModeMap.Add("Vietnamese", "vi"); + GoogleTranslator._languageModeMap.Add("Welsh", "cy"); + GoogleTranslator._languageModeMap.Add("Yiddish", "yi"); + + GoogleTranslator._languageModeMap.Add("af", "af"); + GoogleTranslator._languageModeMap.Add("sq", "sq"); + GoogleTranslator._languageModeMap.Add("ar", "ar"); + GoogleTranslator._languageModeMap.Add("hy", "hy"); + GoogleTranslator._languageModeMap.Add("az", "az"); + GoogleTranslator._languageModeMap.Add("eu", "eu"); + GoogleTranslator._languageModeMap.Add("be", "be"); + GoogleTranslator._languageModeMap.Add("bn", "bn"); + GoogleTranslator._languageModeMap.Add("bg", "bg"); + GoogleTranslator._languageModeMap.Add("ca", "ca"); + GoogleTranslator._languageModeMap.Add("zh-CN", "zh-CN"); + GoogleTranslator._languageModeMap.Add("hr", "hr"); + GoogleTranslator._languageModeMap.Add("cs", "cs"); + GoogleTranslator._languageModeMap.Add("da", "da"); + GoogleTranslator._languageModeMap.Add("nl", "nl"); + GoogleTranslator._languageModeMap.Add("en", "en"); + GoogleTranslator._languageModeMap.Add("eo", "eo"); + GoogleTranslator._languageModeMap.Add("et", "et"); + GoogleTranslator._languageModeMap.Add("tl", "tl"); + GoogleTranslator._languageModeMap.Add("fi", "fi"); + GoogleTranslator._languageModeMap.Add("fr", "fr"); + GoogleTranslator._languageModeMap.Add("gl", "gl"); + GoogleTranslator._languageModeMap.Add("de", "de"); + GoogleTranslator._languageModeMap.Add("ka", "ka"); + GoogleTranslator._languageModeMap.Add("el", "el"); + GoogleTranslator._languageModeMap.Add("ht", "ht"); + GoogleTranslator._languageModeMap.Add("iw", "iw"); + GoogleTranslator._languageModeMap.Add("hi", "hi"); + GoogleTranslator._languageModeMap.Add("hu", "hu"); + GoogleTranslator._languageModeMap.Add("is", "is"); + GoogleTranslator._languageModeMap.Add("id", "id"); + GoogleTranslator._languageModeMap.Add("ga", "ga"); + GoogleTranslator._languageModeMap.Add("it", "it"); + GoogleTranslator._languageModeMap.Add("ja", "ja"); + GoogleTranslator._languageModeMap.Add("ko", "ko"); + GoogleTranslator._languageModeMap.Add("lo", "lo"); + GoogleTranslator._languageModeMap.Add("la", "la"); + GoogleTranslator._languageModeMap.Add("lv", "lv"); + GoogleTranslator._languageModeMap.Add("lt", "lt"); + GoogleTranslator._languageModeMap.Add("mk", "mk"); + GoogleTranslator._languageModeMap.Add("ms", "ms"); + GoogleTranslator._languageModeMap.Add("mt", "mt"); + GoogleTranslator._languageModeMap.Add("no", "no"); + GoogleTranslator._languageModeMap.Add("fa", "fa"); + GoogleTranslator._languageModeMap.Add("pl", "pl"); + GoogleTranslator._languageModeMap.Add("pt", "pt"); + GoogleTranslator._languageModeMap.Add("ro", "ro"); + GoogleTranslator._languageModeMap.Add("ru", "ru"); + GoogleTranslator._languageModeMap.Add("sr", "sr"); + GoogleTranslator._languageModeMap.Add("sk", "sk"); + GoogleTranslator._languageModeMap.Add("sl", "sl"); + GoogleTranslator._languageModeMap.Add("es", "es"); + GoogleTranslator._languageModeMap.Add("sw", "sw"); + GoogleTranslator._languageModeMap.Add("sv", "sv"); + GoogleTranslator._languageModeMap.Add("ta", "ta"); + GoogleTranslator._languageModeMap.Add("te", "te"); + GoogleTranslator._languageModeMap.Add("th", "th"); + GoogleTranslator._languageModeMap.Add("tr", "tr"); + GoogleTranslator._languageModeMap.Add("uk", "uk"); + GoogleTranslator._languageModeMap.Add("ur", "ur"); + GoogleTranslator._languageModeMap.Add("vi", "vi"); + GoogleTranslator._languageModeMap.Add("cy", "cy"); + GoogleTranslator._languageModeMap.Add("yi", "yi"); + } + } + + #endregion + + #region Fields + + /// + /// The language to translation mode map. + /// + public static Dictionary _languageModeMap; + + #endregion + } +} diff --git a/NadekoBot/Modules/Translator/TranslateCommand.cs b/NadekoBot/Modules/Translator/TranslateCommand.cs new file mode 100644 index 00000000..09b14333 --- /dev/null +++ b/NadekoBot/Modules/Translator/TranslateCommand.cs @@ -0,0 +1,39 @@ +using Discord.Commands; +using NadekoBot.Commands; +using NadekoBot.Modules.Translator.Helpers; +using System; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Translator +{ + class TranslateCommand : DiscordCommand + { + public TranslateCommand(DiscordModule module) : base(module) { } + + internal override void Init(CommandGroupBuilder cgb) + { + cgb.CreateCommand(Module.Prefix + "trans") + .Description("Translates from>to text. From the given language to the destiation language.") + .Parameter("langs", ParameterType.Required) + .Parameter("text", ParameterType.Unparsed) + .Do(TranslateFunc()); + } + private GoogleTranslator t = new GoogleTranslator(); + private Func TranslateFunc() => async e => + { + try + { + string from = e.GetArg("langs").Split('>')[0]; + string to = e.GetArg("langs").Split('>')[1]; + + string translation = t.Translate(e.GetArg("text"), from, to); + await e.Channel.SendMessage(translation); + } + catch + { + await e.Channel.SendMessage("Bad input format, or sth went wrong..."); + } + + }; + } +} diff --git a/NadekoBot/Modules/Translator/TranslatorModule.cs b/NadekoBot/Modules/Translator/TranslatorModule.cs new file mode 100644 index 00000000..d3427daa --- /dev/null +++ b/NadekoBot/Modules/Translator/TranslatorModule.cs @@ -0,0 +1,26 @@ +using Discord.Modules; +using NadekoBot.Extensions; + +namespace NadekoBot.Modules.Translator +{ + internal class TranslatorModule : DiscordModule + { + public TranslatorModule() + { + commands.Add(new TranslateCommand(this)); + commands.Add(new ValidLanguagesCommand(this)); + } + + public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Searches; + + public override void Install(ModuleManager manager) + { + manager.CreateCommands("", cgb => + { + cgb.AddCheck(Classes.Permissions.PermissionChecker.Instance); + commands.ForEach(cmd => cmd.Init(cgb)); + }); + } + + } +} diff --git a/NadekoBot/Modules/Translator/ValidLanguagesCommand.cs b/NadekoBot/Modules/Translator/ValidLanguagesCommand.cs new file mode 100644 index 00000000..e479639a --- /dev/null +++ b/NadekoBot/Modules/Translator/ValidLanguagesCommand.cs @@ -0,0 +1,50 @@ +using Discord.Commands; +using NadekoBot.Commands; +using NadekoBot.Modules.Translator.Helpers; +using System; +using System.Threading.Tasks; + +namespace NadekoBot.Modules.Translator +{ + class ValidLanguagesCommand : DiscordCommand + { + public ValidLanguagesCommand(DiscordModule module) : base(module) { } + + internal override void Init(CommandGroupBuilder cgb) + { + cgb.CreateCommand(Module.Prefix + "translangs") + .Description("List the valid languages for translation.") + .Parameter("search", ParameterType.Optional) + .Do(ListLanguagesFunc()); + } + private Func ListLanguagesFunc() => async e => + { + try + { + GoogleTranslator.EnsureInitialized(); + string s = e.GetArg("search"); + string ret = ""; + foreach (string key in GoogleTranslator._languageModeMap.Keys) + { + if (!s.Equals("")) + { + if (key.ToLower().Contains(s)) + { + ret += " " + key + ";"; + } + } + else + { + ret += " " + key + ";"; + } + } + await e.Channel.SendMessage(ret); + } + catch + { + await e.Channel.SendMessage("Bad input format, or sth went wrong..."); + } + + }; + } +} diff --git a/NadekoBot/NadekoBot.cs b/NadekoBot/NadekoBot.cs index 4cb35898..77af4a00 100644 --- a/NadekoBot/NadekoBot.cs +++ b/NadekoBot/NadekoBot.cs @@ -6,6 +6,7 @@ using NadekoBot.Classes.JSONModels; using NadekoBot.Commands; using NadekoBot.Modules; using NadekoBot.Modules.Gambling; +using NadekoBot.Modules.Translator; using Newtonsoft.Json; using System; using System.Collections.Generic; @@ -163,6 +164,7 @@ namespace NadekoBot modules.Add(new Games(), "Games", ModuleFilter.None); modules.Add(new Music(), "Music", ModuleFilter.None); modules.Add(new Searches(), "Searches", ModuleFilter.None); + modules.Add(new TranslatorModule(), "Translator", ModuleFilter.None); modules.Add(new NSFW(), "NSFW", ModuleFilter.None); modules.Add(new ClashOfClans(), "ClashOfClans", ModuleFilter.None); if (!string.IsNullOrWhiteSpace(Creds.TrelloAppKey)) diff --git a/NadekoBot/NadekoBot.csproj b/NadekoBot/NadekoBot.csproj index 186da0d0..ce98bffa 100644 --- a/NadekoBot/NadekoBot.csproj +++ b/NadekoBot/NadekoBot.csproj @@ -187,6 +187,10 @@ + + + +