Scrublord1336 6 年 前
コミット
c6abfd35bb

+ 15 - 0
.editorconfig

@@ -0,0 +1,15 @@
+root = true
+
+[*]
+charset                  = utf-8-bom
+insert_final_newline     = true
+trim_trailing_whitespace = true
+
+# CSharp code style settings:
+[*.cs]
+indent_size                                                        = 3
+csharp_space_between_method_call_parameter_list_parentheses        = true
+csharp_space_between_method_declaration_parameter_list_parentheses = true
+csharp_space_between_square_brackets                               = true
+csharp_space_after_keywords_in_control_flow_statements             = false
+csharp_space_between_parentheses                                   = control_flow_statements, expressions

+ 10 - 2
README.md

@@ -19,11 +19,11 @@ Installations instructions for both methods can be found below.
 Additionally it can be installed without a dependency on a plugin manager through ReiPatcher. However, this approach is not recommended if you use one of the above mentioned Plugin Managers!
 
 ## Configuration
-The default configuration file, looks as such (2.4.0+):
+The default configuration file, looks as such (2.6.0+):
 
 ```ini
 [Service]
-Endpoint=GoogleTranslate         ;Endpoint to use. Can be ["GoogleTranslate", "BaiduTranslate"]
+Endpoint=GoogleTranslate         ;Endpoint to use. Can be ["GoogleTranslate", "BaiduTranslate", "GoogleTranslateHack", "BaiduTranslate", "YandexTranslate", "WatsonTranslate"]
 
 [General]
 Language=en                      ;The language to translate into
@@ -53,6 +53,14 @@ MaxClipboardCopyCharacters=450   ;Max number of characters to hook to clipboard
 BaiduAppId=                      ;OPTIONAL, needed if BaiduTranslate is configured
 BaiduAppSecret=                  ;OPTIONAL, needed if BaiduTranslate is configured
 
+[Yandex]
+YandexAPIKey=                    ;OPTIONAL, needed if YandexTranslate is configured
+
+[Watson]
+WatsonAPIUrl=                    ;OPTIONAL, needed if WatsonTranslate is configured
+WatsonAPIUsername=               ;OPTIONAL, needed if WatsonTranslate is configured
+WatsonAPIPassword=               ;OPTIONAL, needed if WatsonTranslate is configured
+
 [Debug]
 EnablePrintHierarchy=False       ;Used for debugging
 ```

+ 5 - 0
XUnity.AutoTranslator.sln

@@ -19,6 +19,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XUnity.AutoTranslator.Setup
 		{0A2A6B66-91D4-4A4E-AC77-80C6DD748FCD} = {0A2A6B66-91D4-4A4E-AC77-80C6DD748FCD}
 	EndProjectSection
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{ACADAE2C-1642-428A-84D4-CC53E24F1348}"
+	ProjectSection(SolutionItems) = preProject
+		.editorconfig = .editorconfig
+	EndProjectSection
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU

+ 11 - 1
src/XUnity.AutoTranslator.Plugin.Core/Configuration/Settings.cs

@@ -41,6 +41,10 @@ namespace XUnity.AutoTranslator.Plugin.Core.Configuration
       public static int MinDialogueChars;
       public static string BaiduAppId;
       public static string BaiduAppSecret;
+      public static string YandexAPIKey;
+      public static string WatsonAPIUrl;
+      public static string WatsonAPIUsername;
+      public static string WatsonAPIPassword;
       public static int ForceSplitTextAfterCharacters;
 
       public static bool CopyToClipboard;
@@ -91,7 +95,13 @@ namespace XUnity.AutoTranslator.Plugin.Core.Configuration
 
          BaiduAppId = Config.Current.Preferences[ "Baidu" ][ "BaiduAppId" ].GetOrDefault( "" );
          BaiduAppSecret = Config.Current.Preferences[ "Baidu" ][ "BaiduAppSecret" ].GetOrDefault( "" );
-         
+
+         YandexAPIKey = Config.Current.Preferences["Yandex"]["YandexAPIKey"].GetOrDefault("");
+
+         WatsonAPIUrl = Config.Current.Preferences["Watson"]["WatsonAPIUrl"].GetOrDefault("");
+         WatsonAPIUsername = Config.Current.Preferences["Watson"]["WatsonAPIUsername"].GetOrDefault("");
+         WatsonAPIPassword = Config.Current.Preferences["Watson"]["WatsonAPIPassword"].GetOrDefault("");
+
          EnablePrintHierarchy = Config.Current.Preferences[ "Debug" ][ "EnablePrintHierarchy" ].GetOrDefault( false );
 
          AutoTranslationsFilePath = Path.Combine( Config.Current.DataPath, OutputFile.Replace( "{lang}", Language ) );

+ 8 - 0
src/XUnity.AutoTranslator.Plugin.Core/Constants/KnownEndpointNames.cs

@@ -9,6 +9,14 @@ namespace XUnity.AutoTranslator.Plugin.Core.Constants
    {
       public const string GoogleTranslate = "GoogleTranslate";
 
+      public const string GoogleTranslateHack = "GoogleTranslateHack";
+
       public const string BaiduTranslate = "BaiduTranslate";
+
+      public const string YandexTranslate = "YandexTranslate";
+
+      public const string WatsonTranslate = "WatsonTranslate";
+
+      public const string ExciteTranslate = "ExciteTranslate";
    }
 }

+ 38 - 0
src/XUnity.AutoTranslator.Plugin.Core/MonoHttp/Helpers.cs

@@ -0,0 +1,38 @@
+//
+// System.Web.Util.Helpers
+//
+// Authors:
+//	Marek Habersack ([email protected])
+//
+// (C) 2009 Novell, Inc (http://novell.com)
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Globalization;
+
+namespace RestSharp.Contrib
+{
+	class Helpers
+	{
+		public static readonly CultureInfo InvariantCulture = CultureInfo.InvariantCulture;
+	}
+}

+ 918 - 0
src/XUnity.AutoTranslator.Plugin.Core/MonoHttp/HtmlEncoder.cs

@@ -0,0 +1,918 @@
+//
+// Authors:
+//   Patrik Torstensson ([email protected])
+//   Wictor Wilén (decode/encode functions) ([email protected])
+//   Tim Coleman ([email protected])
+//   Gonzalo Paniagua Javier ([email protected])
+
+//   Marek Habersack <[email protected]>
+//
+// (C) 2005-2010 Novell, Inc (http://novell.com/)
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.IO;
+using System.Text;
+#if NET_4_0
+using System.Web.Configuration;
+#endif
+
+namespace RestSharp.Contrib
+{
+#if NET_4_0
+	public
+#endif
+	class HttpEncoder
+	{
+		static char[] hexChars = "0123456789abcdef".ToCharArray();
+		static object entitiesLock = new object();
+		static SortedDictionary<string, char> entities;
+#if NET_4_0
+		static Lazy <HttpEncoder> defaultEncoder;
+		static Lazy <HttpEncoder> currentEncoderLazy;
+#else
+		static HttpEncoder defaultEncoder;
+#endif
+		static HttpEncoder currentEncoder;
+
+		static IDictionary<string, char> Entities
+		{
+			get
+			{
+				lock (entitiesLock)
+				{
+					if (entities == null)
+						InitEntities();
+
+					return entities;
+				}
+			}
+		}
+
+		public static HttpEncoder Current
+		{
+			get
+			{
+#if NET_4_0
+				if (currentEncoder == null)
+					currentEncoder = currentEncoderLazy.Value;
+#endif
+				return currentEncoder;
+			}
+#if NET_4_0
+			set {
+				if (value == null)
+					throw new ArgumentNullException ("value");
+				currentEncoder = value;
+			}
+#endif
+		}
+
+		public static HttpEncoder Default
+		{
+			get
+			{
+#if NET_4_0
+				return defaultEncoder.Value;
+#else
+				return defaultEncoder;
+#endif
+			}
+		}
+
+		static HttpEncoder()
+		{
+#if NET_4_0
+			defaultEncoder = new Lazy <HttpEncoder> (() => new HttpEncoder ());
+			currentEncoderLazy = new Lazy <HttpEncoder> (new Func <HttpEncoder> (GetCustomEncoderFromConfig));
+#else
+			defaultEncoder = new HttpEncoder();
+			currentEncoder = defaultEncoder;
+#endif
+		}
+
+		public HttpEncoder()
+		{
+		}
+#if NET_4_0	
+		protected internal virtual
+#else
+		internal static
+#endif
+ void HeaderNameValueEncode(string headerName, string headerValue, out string encodedHeaderName, out string encodedHeaderValue)
+		{
+			if (String.IsNullOrEmpty(headerName))
+				encodedHeaderName = headerName;
+			else
+				encodedHeaderName = EncodeHeaderString(headerName);
+
+			if (String.IsNullOrEmpty(headerValue))
+				encodedHeaderValue = headerValue;
+			else
+				encodedHeaderValue = EncodeHeaderString(headerValue);
+		}
+
+		static void StringBuilderAppend(string s, ref StringBuilder sb)
+		{
+			if (sb == null)
+				sb = new StringBuilder(s);
+			else
+				sb.Append(s);
+		}
+
+		static string EncodeHeaderString(string input)
+		{
+			StringBuilder sb = null;
+			char ch;
+
+			for (int i = 0; i < input.Length; i++)
+			{
+				ch = input[i];
+
+				if ((ch < 32 && ch != 9) || ch == 127)
+					StringBuilderAppend(String.Format("%{0:x2}", (int)ch), ref sb);
+			}
+
+			if (sb != null)
+				return sb.ToString();
+
+			return input;
+		}
+#if NET_4_0		
+		protected internal virtual void HtmlAttributeEncode (string value, TextWriter output)
+		{
+
+			if (output == null)
+				throw new ArgumentNullException ("output");
+
+			if (String.IsNullOrEmpty (value))
+				return;
+
+			output.Write (HtmlAttributeEncode (value));
+		}
+
+		protected internal virtual void HtmlDecode (string value, TextWriter output)
+		{
+			if (output == null)
+				throw new ArgumentNullException ("output");
+
+			output.Write (HtmlDecode (value));
+		}
+
+		protected internal virtual void HtmlEncode (string value, TextWriter output)
+		{
+			if (output == null)
+				throw new ArgumentNullException ("output");
+
+			output.Write (HtmlEncode (value));
+		}
+
+		protected internal virtual byte[] UrlEncode (byte[] bytes, int offset, int count)
+		{
+			return UrlEncodeToBytes (bytes, offset, count);
+		}
+
+		static HttpEncoder GetCustomEncoderFromConfig ()
+		{
+			var cfg = WebConfigurationManager.GetSection ("system.web/httpRuntime") as HttpRuntimeSection;
+			string typeName = cfg.EncoderType;
+
+			if (String.Compare (typeName, "System.Web.Util.HttpEncoder", StringComparison.OrdinalIgnoreCase) == 0)
+				return Default;
+			
+			Type t = Type.GetType (typeName, false);
+			if (t == null)
+				throw new ConfigurationErrorsException (String.Format ("Could not load type '{0}'.", typeName));
+			
+			if (!typeof (HttpEncoder).IsAssignableFrom (t))
+				throw new ConfigurationErrorsException (
+					String.Format ("'{0}' is not allowed here because it does not extend class 'System.Web.Util.HttpEncoder'.", typeName)
+				);
+
+			return Activator.CreateInstance (t, false) as HttpEncoder;
+		}
+#endif
+#if NET_4_0
+		protected internal virtual
+#else
+		internal static
+#endif
+ string UrlPathEncode(string value)
+		{
+			if (String.IsNullOrEmpty(value))
+				return value;
+
+			MemoryStream result = new MemoryStream();
+			int length = value.Length;
+			for (int i = 0; i < length; i++)
+				UrlPathEncodeChar(value[i], result);
+
+			return Encoding.ASCII.GetString(result.ToArray());
+		}
+
+		internal static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count)
+		{
+			if (bytes == null)
+				throw new ArgumentNullException("bytes");
+
+			int blen = bytes.Length;
+			if (blen == 0)
+				return new byte[0];
+
+			if (offset < 0 || offset >= blen)
+				throw new ArgumentOutOfRangeException("offset");
+
+			if (count < 0 || count > blen - offset)
+				throw new ArgumentOutOfRangeException("count");
+
+			MemoryStream result = new MemoryStream(count);
+			int end = offset + count;
+			for (int i = offset; i < end; i++)
+				UrlEncodeChar((char)bytes[i], result, false);
+
+			return result.ToArray();
+		}
+
+		internal static string HtmlEncode(string s)
+		{
+			if (s == null)
+				return null;
+
+			if (s.Length == 0)
+				return String.Empty;
+
+			bool needEncode = false;
+			for (int i = 0; i < s.Length; i++)
+			{
+				char c = s[i];
+				if (c == '&' || c == '"' || c == '<' || c == '>' || c > 159
+#if NET_4_0
+				    || c == '\''
+#endif
+)
+				{
+					needEncode = true;
+					break;
+				}
+			}
+
+			if (!needEncode)
+				return s;
+
+			StringBuilder output = new StringBuilder();
+			char ch;
+			int len = s.Length;
+
+			for (int i = 0; i < len; i++)
+			{
+				switch (s[i])
+				{
+					case '&':
+						output.Append("&amp;");
+						break;
+					case '>':
+						output.Append("&gt;");
+						break;
+					case '<':
+						output.Append("&lt;");
+						break;
+					case '"':
+						output.Append("&quot;");
+						break;
+#if NET_4_0
+					case '\'':
+						output.Append ("&#39;");
+						break;
+#endif
+					case '\uff1c':
+						output.Append("&#65308;");
+						break;
+
+					case '\uff1e':
+						output.Append("&#65310;");
+						break;
+
+					default:
+						ch = s[i];
+						if (ch > 159 && ch < 256)
+						{
+							output.Append("&#");
+							output.Append(((int)ch).ToString(Helpers.InvariantCulture));
+							output.Append(";");
+						}
+						else
+							output.Append(ch);
+						break;
+				}
+			}
+
+			return output.ToString();
+		}
+
+		internal static string HtmlAttributeEncode(string s)
+		{
+#if NET_4_0
+			if (String.IsNullOrEmpty (s))
+				return String.Empty;
+#else
+			if (s == null)
+				return null;
+
+			if (s.Length == 0)
+				return String.Empty;
+#endif
+			bool needEncode = false;
+			for (int i = 0; i < s.Length; i++)
+			{
+				char c = s[i];
+				if (c == '&' || c == '"' || c == '<'
+#if NET_4_0
+				    || c == '\''
+#endif
+)
+				{
+					needEncode = true;
+					break;
+				}
+			}
+
+			if (!needEncode)
+				return s;
+
+			StringBuilder output = new StringBuilder();
+			int len = s.Length;
+			for (int i = 0; i < len; i++)
+				switch (s[i])
+				{
+					case '&':
+						output.Append("&amp;");
+						break;
+					case '"':
+						output.Append("&quot;");
+						break;
+					case '<':
+						output.Append("&lt;");
+						break;
+#if NET_4_0
+				case '\'':
+					output.Append ("&#39;");
+					break;
+#endif
+					default:
+						output.Append(s[i]);
+						break;
+				}
+
+			return output.ToString();
+		}
+
+		internal static string HtmlDecode(string s)
+		{
+			if (s == null)
+				return null;
+
+			if (s.Length == 0)
+				return String.Empty;
+
+			if (s.IndexOf('&') == -1)
+				return s;
+#if NET_4_0
+			StringBuilder rawEntity = new StringBuilder ();
+#endif
+			StringBuilder entity = new StringBuilder();
+			StringBuilder output = new StringBuilder();
+			int len = s.Length;
+			// 0 -> nothing,
+			// 1 -> right after '&'
+			// 2 -> between '&' and ';' but no '#'
+			// 3 -> '#' found after '&' and getting numbers
+			int state = 0;
+			int number = 0;
+			bool is_hex_value = false;
+			bool have_trailing_digits = false;
+
+			for (int i = 0; i < len; i++)
+			{
+				char c = s[i];
+				if (state == 0)
+				{
+					if (c == '&')
+					{
+						entity.Append(c);
+#if NET_4_0
+						rawEntity.Append (c);
+#endif
+						state = 1;
+					}
+					else
+					{
+						output.Append(c);
+					}
+					continue;
+				}
+
+				if (c == '&')
+				{
+					state = 1;
+					if (have_trailing_digits)
+					{
+						entity.Append(number.ToString(Helpers.InvariantCulture));
+						have_trailing_digits = false;
+					}
+
+					output.Append(entity.ToString());
+					entity.Length = 0;
+					entity.Append('&');
+					continue;
+				}
+
+				if (state == 1)
+				{
+					if (c == ';')
+					{
+						state = 0;
+						output.Append(entity.ToString());
+						output.Append(c);
+						entity.Length = 0;
+					}
+					else
+					{
+						number = 0;
+						is_hex_value = false;
+						if (c != '#')
+						{
+							state = 2;
+						}
+						else
+						{
+							state = 3;
+						}
+						entity.Append(c);
+#if NET_4_0
+						rawEntity.Append (c);
+#endif
+					}
+				}
+				else if (state == 2)
+				{
+					entity.Append(c);
+					if (c == ';')
+					{
+						string key = entity.ToString();
+						if (key.Length > 1 && Entities.ContainsKey(key.Substring(1, key.Length - 2)))
+							key = Entities[key.Substring(1, key.Length - 2)].ToString();
+
+						output.Append(key);
+						state = 0;
+						entity.Length = 0;
+#if NET_4_0
+						rawEntity.Length = 0;
+#endif
+					}
+				}
+				else if (state == 3)
+				{
+					if (c == ';')
+					{
+#if NET_4_0
+						if (number == 0)
+							output.Append (rawEntity.ToString () + ";");
+						else
+#endif
+						if (number > 65535)
+						{
+							output.Append("&#");
+							output.Append(number.ToString(Helpers.InvariantCulture));
+							output.Append(";");
+						}
+						else
+						{
+							output.Append((char)number);
+						}
+						state = 0;
+						entity.Length = 0;
+#if NET_4_0
+						rawEntity.Length = 0;
+#endif
+						have_trailing_digits = false;
+					}
+					else if (is_hex_value && Uri.IsHexDigit(c))
+					{
+						number = number * 16 + Uri.FromHex(c);
+						have_trailing_digits = true;
+#if NET_4_0
+						rawEntity.Append (c);
+#endif
+					}
+					else if (Char.IsDigit(c))
+					{
+						number = number * 10 + ((int)c - '0');
+						have_trailing_digits = true;
+#if NET_4_0
+						rawEntity.Append (c);
+#endif
+					}
+					else if (number == 0 && (c == 'x' || c == 'X'))
+					{
+						is_hex_value = true;
+#if NET_4_0
+						rawEntity.Append (c);
+#endif
+					}
+					else
+					{
+						state = 2;
+						if (have_trailing_digits)
+						{
+							entity.Append(number.ToString(Helpers.InvariantCulture));
+							have_trailing_digits = false;
+						}
+						entity.Append(c);
+					}
+				}
+			}
+
+			if (entity.Length > 0)
+			{
+				output.Append(entity.ToString());
+			}
+			else if (have_trailing_digits)
+			{
+				output.Append(number.ToString(Helpers.InvariantCulture));
+			}
+			return output.ToString();
+		}
+
+		internal static bool NotEncoded(char c)
+		{
+			return (c == '!' || c == '(' || c == ')' || c == '*' || c == '-' || c == '.' || c == '_'
+#if !NET_4_0
+ || c == '\''
+#endif
+);
+		}
+
+		internal static void UrlEncodeChar(char c, Stream result, bool isUnicode)
+		{
+			if (c > 255)
+			{
+				//FIXME: what happens when there is an internal error?
+				//if (!isUnicode)
+				//	throw new ArgumentOutOfRangeException ("c", c, "c must be less than 256");
+				int idx;
+				int i = (int)c;
+
+				result.WriteByte((byte)'%');
+				result.WriteByte((byte)'u');
+				idx = i >> 12;
+				result.WriteByte((byte)hexChars[idx]);
+				idx = (i >> 8) & 0x0F;
+				result.WriteByte((byte)hexChars[idx]);
+				idx = (i >> 4) & 0x0F;
+				result.WriteByte((byte)hexChars[idx]);
+				idx = i & 0x0F;
+				result.WriteByte((byte)hexChars[idx]);
+				return;
+			}
+
+			if (c > ' ' && NotEncoded(c))
+			{
+				result.WriteByte((byte)c);
+				return;
+			}
+			if (c == ' ')
+			{
+				result.WriteByte((byte)'+');
+				return;
+			}
+			if ((c < '0') ||
+				(c < 'A' && c > '9') ||
+				(c > 'Z' && c < 'a') ||
+				(c > 'z'))
+			{
+				if (isUnicode && c > 127)
+				{
+					result.WriteByte((byte)'%');
+					result.WriteByte((byte)'u');
+					result.WriteByte((byte)'0');
+					result.WriteByte((byte)'0');
+				}
+				else
+					result.WriteByte((byte)'%');
+
+				int idx = ((int)c) >> 4;
+				result.WriteByte((byte)hexChars[idx]);
+				idx = ((int)c) & 0x0F;
+				result.WriteByte((byte)hexChars[idx]);
+			}
+			else
+				result.WriteByte((byte)c);
+		}
+
+		internal static void UrlPathEncodeChar(char c, Stream result)
+		{
+			if (c < 33 || c > 126)
+			{
+				byte[] bIn = Encoding.UTF8.GetBytes(c.ToString());
+				for (int i = 0; i < bIn.Length; i++)
+				{
+					result.WriteByte((byte)'%');
+					int idx = ((int)bIn[i]) >> 4;
+					result.WriteByte((byte)hexChars[idx]);
+					idx = ((int)bIn[i]) & 0x0F;
+					result.WriteByte((byte)hexChars[idx]);
+				}
+			}
+			else if (c == ' ')
+			{
+				result.WriteByte((byte)'%');
+				result.WriteByte((byte)'2');
+				result.WriteByte((byte)'0');
+			}
+			else
+				result.WriteByte((byte)c);
+		}
+
+		static void InitEntities()
+		{
+			// Build the hash table of HTML entity references.  This list comes
+			// from the HTML 4.01 W3C recommendation.
+			entities = new SortedDictionary<string, char>(StringComparer.Ordinal);
+
+			entities.Add("nbsp", '\u00A0');
+			entities.Add("iexcl", '\u00A1');
+			entities.Add("cent", '\u00A2');
+			entities.Add("pound", '\u00A3');
+			entities.Add("curren", '\u00A4');
+			entities.Add("yen", '\u00A5');
+			entities.Add("brvbar", '\u00A6');
+			entities.Add("sect", '\u00A7');
+			entities.Add("uml", '\u00A8');
+			entities.Add("copy", '\u00A9');
+			entities.Add("ordf", '\u00AA');
+			entities.Add("laquo", '\u00AB');
+			entities.Add("not", '\u00AC');
+			entities.Add("shy", '\u00AD');
+			entities.Add("reg", '\u00AE');
+			entities.Add("macr", '\u00AF');
+			entities.Add("deg", '\u00B0');
+			entities.Add("plusmn", '\u00B1');
+			entities.Add("sup2", '\u00B2');
+			entities.Add("sup3", '\u00B3');
+			entities.Add("acute", '\u00B4');
+			entities.Add("micro", '\u00B5');
+			entities.Add("para", '\u00B6');
+			entities.Add("middot", '\u00B7');
+			entities.Add("cedil", '\u00B8');
+			entities.Add("sup1", '\u00B9');
+			entities.Add("ordm", '\u00BA');
+			entities.Add("raquo", '\u00BB');
+			entities.Add("frac14", '\u00BC');
+			entities.Add("frac12", '\u00BD');
+			entities.Add("frac34", '\u00BE');
+			entities.Add("iquest", '\u00BF');
+			entities.Add("Agrave", '\u00C0');
+			entities.Add("Aacute", '\u00C1');
+			entities.Add("Acirc", '\u00C2');
+			entities.Add("Atilde", '\u00C3');
+			entities.Add("Auml", '\u00C4');
+			entities.Add("Aring", '\u00C5');
+			entities.Add("AElig", '\u00C6');
+			entities.Add("Ccedil", '\u00C7');
+			entities.Add("Egrave", '\u00C8');
+			entities.Add("Eacute", '\u00C9');
+			entities.Add("Ecirc", '\u00CA');
+			entities.Add("Euml", '\u00CB');
+			entities.Add("Igrave", '\u00CC');
+			entities.Add("Iacute", '\u00CD');
+			entities.Add("Icirc", '\u00CE');
+			entities.Add("Iuml", '\u00CF');
+			entities.Add("ETH", '\u00D0');
+			entities.Add("Ntilde", '\u00D1');
+			entities.Add("Ograve", '\u00D2');
+			entities.Add("Oacute", '\u00D3');
+			entities.Add("Ocirc", '\u00D4');
+			entities.Add("Otilde", '\u00D5');
+			entities.Add("Ouml", '\u00D6');
+			entities.Add("times", '\u00D7');
+			entities.Add("Oslash", '\u00D8');
+			entities.Add("Ugrave", '\u00D9');
+			entities.Add("Uacute", '\u00DA');
+			entities.Add("Ucirc", '\u00DB');
+			entities.Add("Uuml", '\u00DC');
+			entities.Add("Yacute", '\u00DD');
+			entities.Add("THORN", '\u00DE');
+			entities.Add("szlig", '\u00DF');
+			entities.Add("agrave", '\u00E0');
+			entities.Add("aacute", '\u00E1');
+			entities.Add("acirc", '\u00E2');
+			entities.Add("atilde", '\u00E3');
+			entities.Add("auml", '\u00E4');
+			entities.Add("aring", '\u00E5');
+			entities.Add("aelig", '\u00E6');
+			entities.Add("ccedil", '\u00E7');
+			entities.Add("egrave", '\u00E8');
+			entities.Add("eacute", '\u00E9');
+			entities.Add("ecirc", '\u00EA');
+			entities.Add("euml", '\u00EB');
+			entities.Add("igrave", '\u00EC');
+			entities.Add("iacute", '\u00ED');
+			entities.Add("icirc", '\u00EE');
+			entities.Add("iuml", '\u00EF');
+			entities.Add("eth", '\u00F0');
+			entities.Add("ntilde", '\u00F1');
+			entities.Add("ograve", '\u00F2');
+			entities.Add("oacute", '\u00F3');
+			entities.Add("ocirc", '\u00F4');
+			entities.Add("otilde", '\u00F5');
+			entities.Add("ouml", '\u00F6');
+			entities.Add("divide", '\u00F7');
+			entities.Add("oslash", '\u00F8');
+			entities.Add("ugrave", '\u00F9');
+			entities.Add("uacute", '\u00FA');
+			entities.Add("ucirc", '\u00FB');
+			entities.Add("uuml", '\u00FC');
+			entities.Add("yacute", '\u00FD');
+			entities.Add("thorn", '\u00FE');
+			entities.Add("yuml", '\u00FF');
+			entities.Add("fnof", '\u0192');
+			entities.Add("Alpha", '\u0391');
+			entities.Add("Beta", '\u0392');
+			entities.Add("Gamma", '\u0393');
+			entities.Add("Delta", '\u0394');
+			entities.Add("Epsilon", '\u0395');
+			entities.Add("Zeta", '\u0396');
+			entities.Add("Eta", '\u0397');
+			entities.Add("Theta", '\u0398');
+			entities.Add("Iota", '\u0399');
+			entities.Add("Kappa", '\u039A');
+			entities.Add("Lambda", '\u039B');
+			entities.Add("Mu", '\u039C');
+			entities.Add("Nu", '\u039D');
+			entities.Add("Xi", '\u039E');
+			entities.Add("Omicron", '\u039F');
+			entities.Add("Pi", '\u03A0');
+			entities.Add("Rho", '\u03A1');
+			entities.Add("Sigma", '\u03A3');
+			entities.Add("Tau", '\u03A4');
+			entities.Add("Upsilon", '\u03A5');
+			entities.Add("Phi", '\u03A6');
+			entities.Add("Chi", '\u03A7');
+			entities.Add("Psi", '\u03A8');
+			entities.Add("Omega", '\u03A9');
+			entities.Add("alpha", '\u03B1');
+			entities.Add("beta", '\u03B2');
+			entities.Add("gamma", '\u03B3');
+			entities.Add("delta", '\u03B4');
+			entities.Add("epsilon", '\u03B5');
+			entities.Add("zeta", '\u03B6');
+			entities.Add("eta", '\u03B7');
+			entities.Add("theta", '\u03B8');
+			entities.Add("iota", '\u03B9');
+			entities.Add("kappa", '\u03BA');
+			entities.Add("lambda", '\u03BB');
+			entities.Add("mu", '\u03BC');
+			entities.Add("nu", '\u03BD');
+			entities.Add("xi", '\u03BE');
+			entities.Add("omicron", '\u03BF');
+			entities.Add("pi", '\u03C0');
+			entities.Add("rho", '\u03C1');
+			entities.Add("sigmaf", '\u03C2');
+			entities.Add("sigma", '\u03C3');
+			entities.Add("tau", '\u03C4');
+			entities.Add("upsilon", '\u03C5');
+			entities.Add("phi", '\u03C6');
+			entities.Add("chi", '\u03C7');
+			entities.Add("psi", '\u03C8');
+			entities.Add("omega", '\u03C9');
+			entities.Add("thetasym", '\u03D1');
+			entities.Add("upsih", '\u03D2');
+			entities.Add("piv", '\u03D6');
+			entities.Add("bull", '\u2022');
+			entities.Add("hellip", '\u2026');
+			entities.Add("prime", '\u2032');
+			entities.Add("Prime", '\u2033');
+			entities.Add("oline", '\u203E');
+			entities.Add("frasl", '\u2044');
+			entities.Add("weierp", '\u2118');
+			entities.Add("image", '\u2111');
+			entities.Add("real", '\u211C');
+			entities.Add("trade", '\u2122');
+			entities.Add("alefsym", '\u2135');
+			entities.Add("larr", '\u2190');
+			entities.Add("uarr", '\u2191');
+			entities.Add("rarr", '\u2192');
+			entities.Add("darr", '\u2193');
+			entities.Add("harr", '\u2194');
+			entities.Add("crarr", '\u21B5');
+			entities.Add("lArr", '\u21D0');
+			entities.Add("uArr", '\u21D1');
+			entities.Add("rArr", '\u21D2');
+			entities.Add("dArr", '\u21D3');
+			entities.Add("hArr", '\u21D4');
+			entities.Add("forall", '\u2200');
+			entities.Add("part", '\u2202');
+			entities.Add("exist", '\u2203');
+			entities.Add("empty", '\u2205');
+			entities.Add("nabla", '\u2207');
+			entities.Add("isin", '\u2208');
+			entities.Add("notin", '\u2209');
+			entities.Add("ni", '\u220B');
+			entities.Add("prod", '\u220F');
+			entities.Add("sum", '\u2211');
+			entities.Add("minus", '\u2212');
+			entities.Add("lowast", '\u2217');
+			entities.Add("radic", '\u221A');
+			entities.Add("prop", '\u221D');
+			entities.Add("infin", '\u221E');
+			entities.Add("ang", '\u2220');
+			entities.Add("and", '\u2227');
+			entities.Add("or", '\u2228');
+			entities.Add("cap", '\u2229');
+			entities.Add("cup", '\u222A');
+			entities.Add("int", '\u222B');
+			entities.Add("there4", '\u2234');
+			entities.Add("sim", '\u223C');
+			entities.Add("cong", '\u2245');
+			entities.Add("asymp", '\u2248');
+			entities.Add("ne", '\u2260');
+			entities.Add("equiv", '\u2261');
+			entities.Add("le", '\u2264');
+			entities.Add("ge", '\u2265');
+			entities.Add("sub", '\u2282');
+			entities.Add("sup", '\u2283');
+			entities.Add("nsub", '\u2284');
+			entities.Add("sube", '\u2286');
+			entities.Add("supe", '\u2287');
+			entities.Add("oplus", '\u2295');
+			entities.Add("otimes", '\u2297');
+			entities.Add("perp", '\u22A5');
+			entities.Add("sdot", '\u22C5');
+			entities.Add("lceil", '\u2308');
+			entities.Add("rceil", '\u2309');
+			entities.Add("lfloor", '\u230A');
+			entities.Add("rfloor", '\u230B');
+			entities.Add("lang", '\u2329');
+			entities.Add("rang", '\u232A');
+			entities.Add("loz", '\u25CA');
+			entities.Add("spades", '\u2660');
+			entities.Add("clubs", '\u2663');
+			entities.Add("hearts", '\u2665');
+			entities.Add("diams", '\u2666');
+			entities.Add("quot", '\u0022');
+			entities.Add("amp", '\u0026');
+			entities.Add("lt", '\u003C');
+			entities.Add("gt", '\u003E');
+			entities.Add("OElig", '\u0152');
+			entities.Add("oelig", '\u0153');
+			entities.Add("Scaron", '\u0160');
+			entities.Add("scaron", '\u0161');
+			entities.Add("Yuml", '\u0178');
+			entities.Add("circ", '\u02C6');
+			entities.Add("tilde", '\u02DC');
+			entities.Add("ensp", '\u2002');
+			entities.Add("emsp", '\u2003');
+			entities.Add("thinsp", '\u2009');
+			entities.Add("zwnj", '\u200C');
+			entities.Add("zwj", '\u200D');
+			entities.Add("lrm", '\u200E');
+			entities.Add("rlm", '\u200F');
+			entities.Add("ndash", '\u2013');
+			entities.Add("mdash", '\u2014');
+			entities.Add("lsquo", '\u2018');
+			entities.Add("rsquo", '\u2019');
+			entities.Add("sbquo", '\u201A');
+			entities.Add("ldquo", '\u201C');
+			entities.Add("rdquo", '\u201D');
+			entities.Add("bdquo", '\u201E');
+			entities.Add("dagger", '\u2020');
+			entities.Add("Dagger", '\u2021');
+			entities.Add("permil", '\u2030');
+			entities.Add("lsaquo", '\u2039');
+			entities.Add("rsaquo", '\u203A');
+			entities.Add("euro", '\u20AC');
+		}
+	}
+}

+ 766 - 0
src/XUnity.AutoTranslator.Plugin.Core/MonoHttp/HttpUtility.cs

@@ -0,0 +1,766 @@
+// 
+// System.Web.HttpUtility
+//
+// Authors:
+//   Patrik Torstensson ([email protected])
+//   Wictor Wilén (decode/encode functions) ([email protected])
+//   Tim Coleman ([email protected])
+//   Gonzalo Paniagua Javier ([email protected])
+//
+// Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Globalization;
+using System.IO;
+using System.Security.Permissions;
+using System.Text;
+
+namespace RestSharp.Contrib
+{
+
+//#if !MONOTOUCH
+//    // CAS - no InheritanceDemand here as the class is sealed
+//    [AspNetHostingPermission(SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
+//#endif
+	public sealed class HttpUtility
+	{
+		sealed class HttpQSCollection : NameValueCollection
+		{
+			public override string ToString()
+			{
+				int count = Count;
+				if (count == 0)
+					return "";
+				StringBuilder sb = new StringBuilder();
+				string[] keys = AllKeys;
+				for (int i = 0; i < count; i++)
+				{
+					sb.AppendFormat("{0}={1}&", keys[i], this[keys[i]]);
+				}
+				if (sb.Length > 0)
+					sb.Length--;
+				return sb.ToString();
+			}
+		}
+
+		#region Constructors
+
+		public HttpUtility()
+		{
+		}
+
+		#endregion // Constructors
+
+		#region Methods
+
+		public static void HtmlAttributeEncode(string s, TextWriter output)
+		{
+			if (output == null)
+			{
+#if NET_4_0
+				throw new ArgumentNullException ("output");
+#else
+				throw new NullReferenceException(".NET emulation");
+#endif
+			}
+#if NET_4_0
+			HttpEncoder.Current.HtmlAttributeEncode (s, output);
+#else
+			output.Write(HttpEncoder.HtmlAttributeEncode(s));
+#endif
+		}
+
+		public static string HtmlAttributeEncode(string s)
+		{
+#if NET_4_0
+			if (s == null)
+				return null;
+			
+			using (var sw = new StringWriter ()) {
+				HttpEncoder.Current.HtmlAttributeEncode (s, sw);
+				return sw.ToString ();
+			}
+#else
+			return HttpEncoder.HtmlAttributeEncode(s);
+#endif
+		}
+
+		public static string UrlDecode(string str)
+		{
+			return UrlDecode(str, Encoding.UTF8);
+		}
+
+		static char[] GetChars(MemoryStream b, Encoding e)
+		{
+			return e.GetChars(b.GetBuffer(), 0, (int)b.Length);
+		}
+
+		static void WriteCharBytes(IList buf, char ch, Encoding e)
+		{
+			if (ch > 255)
+			{
+				foreach (byte b in e.GetBytes(new char[] { ch }))
+					buf.Add(b);
+			}
+			else
+				buf.Add((byte)ch);
+		}
+
+		public static string UrlDecode(string s, Encoding e)
+		{
+			if (null == s)
+				return null;
+
+			if (s.IndexOf('%') == -1 && s.IndexOf('+') == -1)
+				return s;
+
+			if (e == null)
+				e = Encoding.UTF8;
+
+			long len = s.Length;
+			var bytes = new List<byte>();
+			int xchar;
+			char ch;
+
+			for (int i = 0; i < len; i++)
+			{
+				ch = s[i];
+				if (ch == '%' && i + 2 < len && s[i + 1] != '%')
+				{
+					if (s[i + 1] == 'u' && i + 5 < len)
+					{
+						// unicode hex sequence
+						xchar = GetChar(s, i + 2, 4);
+						if (xchar != -1)
+						{
+							WriteCharBytes(bytes, (char)xchar, e);
+							i += 5;
+						}
+						else
+							WriteCharBytes(bytes, '%', e);
+					}
+					else if ((xchar = GetChar(s, i + 1, 2)) != -1)
+					{
+						WriteCharBytes(bytes, (char)xchar, e);
+						i += 2;
+					}
+					else
+					{
+						WriteCharBytes(bytes, '%', e);
+					}
+					continue;
+				}
+
+				if (ch == '+')
+					WriteCharBytes(bytes, ' ', e);
+				else
+					WriteCharBytes(bytes, ch, e);
+			}
+
+			byte[] buf = bytes.ToArray();
+			bytes = null;
+			return e.GetString(buf);
+
+		}
+
+		public static string UrlDecode(byte[] bytes, Encoding e)
+		{
+			if (bytes == null)
+				return null;
+
+			return UrlDecode(bytes, 0, bytes.Length, e);
+		}
+
+		static int GetInt(byte b)
+		{
+			char c = (char)b;
+			if (c >= '0' && c <= '9')
+				return c - '0';
+
+			if (c >= 'a' && c <= 'f')
+				return c - 'a' + 10;
+
+			if (c >= 'A' && c <= 'F')
+				return c - 'A' + 10;
+
+			return -1;
+		}
+
+		static int GetChar(byte[] bytes, int offset, int length)
+		{
+			int value = 0;
+			int end = length + offset;
+			for (int i = offset; i < end; i++)
+			{
+				int current = GetInt(bytes[i]);
+				if (current == -1)
+					return -1;
+				value = (value << 4) + current;
+			}
+
+			return value;
+		}
+
+		static int GetChar(string str, int offset, int length)
+		{
+			int val = 0;
+			int end = length + offset;
+			for (int i = offset; i < end; i++)
+			{
+				char c = str[i];
+				if (c > 127)
+					return -1;
+
+				int current = GetInt((byte)c);
+				if (current == -1)
+					return -1;
+				val = (val << 4) + current;
+			}
+
+			return val;
+		}
+
+		public static string UrlDecode(byte[] bytes, int offset, int count, Encoding e)
+		{
+			if (bytes == null)
+				return null;
+			if (count == 0)
+				return String.Empty;
+
+			if (bytes == null)
+				throw new ArgumentNullException("bytes");
+
+			if (offset < 0 || offset > bytes.Length)
+				throw new ArgumentOutOfRangeException("offset");
+
+			if (count < 0 || offset + count > bytes.Length)
+				throw new ArgumentOutOfRangeException("count");
+
+			StringBuilder output = new StringBuilder();
+			MemoryStream acc = new MemoryStream();
+
+			int end = count + offset;
+			int xchar;
+			for (int i = offset; i < end; i++)
+			{
+				if (bytes[i] == '%' && i + 2 < count && bytes[i + 1] != '%')
+				{
+					if (bytes[i + 1] == (byte)'u' && i + 5 < end)
+					{
+						if (acc.Length > 0)
+						{
+							output.Append(GetChars(acc, e));
+							acc.SetLength(0);
+						}
+						xchar = GetChar(bytes, i + 2, 4);
+						if (xchar != -1)
+						{
+							output.Append((char)xchar);
+							i += 5;
+							continue;
+						}
+					}
+					else if ((xchar = GetChar(bytes, i + 1, 2)) != -1)
+					{
+						acc.WriteByte((byte)xchar);
+						i += 2;
+						continue;
+					}
+				}
+
+				if (acc.Length > 0)
+				{
+					output.Append(GetChars(acc, e));
+					acc.SetLength(0);
+				}
+
+				if (bytes[i] == '+')
+				{
+					output.Append(' ');
+				}
+				else
+				{
+					output.Append((char)bytes[i]);
+				}
+			}
+
+			if (acc.Length > 0)
+			{
+				output.Append(GetChars(acc, e));
+			}
+
+			acc = null;
+			return output.ToString();
+		}
+
+		public static byte[] UrlDecodeToBytes(byte[] bytes)
+		{
+			if (bytes == null)
+				return null;
+
+			return UrlDecodeToBytes(bytes, 0, bytes.Length);
+		}
+
+		public static byte[] UrlDecodeToBytes(string str)
+		{
+			return UrlDecodeToBytes(str, Encoding.UTF8);
+		}
+
+		public static byte[] UrlDecodeToBytes(string str, Encoding e)
+		{
+			if (str == null)
+				return null;
+
+			if (e == null)
+				throw new ArgumentNullException("e");
+
+			return UrlDecodeToBytes(e.GetBytes(str));
+		}
+
+		public static byte[] UrlDecodeToBytes(byte[] bytes, int offset, int count)
+		{
+			if (bytes == null)
+				return null;
+			if (count == 0)
+				return new byte[0];
+
+			int len = bytes.Length;
+			if (offset < 0 || offset >= len)
+				throw new ArgumentOutOfRangeException("offset");
+
+			if (count < 0 || offset > len - count)
+				throw new ArgumentOutOfRangeException("count");
+
+			MemoryStream result = new MemoryStream();
+			int end = offset + count;
+			for (int i = offset; i < end; i++)
+			{
+				char c = (char)bytes[i];
+				if (c == '+')
+				{
+					c = ' ';
+				}
+				else if (c == '%' && i < end - 2)
+				{
+					int xchar = GetChar(bytes, i + 1, 2);
+					if (xchar != -1)
+					{
+						c = (char)xchar;
+						i += 2;
+					}
+				}
+				result.WriteByte((byte)c);
+			}
+
+			return result.ToArray();
+		}
+
+		public static string UrlEncode(string str)
+		{
+			return UrlEncode(str, Encoding.UTF8);
+		}
+
+		public static string UrlEncode(string s, Encoding Enc)
+		{
+			if (s == null)
+				return null;
+
+			if (s == String.Empty)
+				return String.Empty;
+
+			bool needEncode = false;
+			int len = s.Length;
+			for (int i = 0; i < len; i++)
+			{
+				char c = s[i];
+				if ((c < '0') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a') || (c > 'z'))
+				{
+					if (HttpEncoder.NotEncoded(c))
+						continue;
+
+					needEncode = true;
+					break;
+				}
+			}
+
+			if (!needEncode)
+				return s;
+
+			// avoided GetByteCount call
+			byte[] bytes = new byte[Enc.GetMaxByteCount(s.Length)];
+			int realLen = Enc.GetBytes(s, 0, s.Length, bytes, 0);
+			return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, realLen));
+		}
+
+		public static string UrlEncode(byte[] bytes)
+		{
+			if (bytes == null)
+				return null;
+
+			if (bytes.Length == 0)
+				return String.Empty;
+
+			return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, 0, bytes.Length));
+		}
+
+		public static string UrlEncode(byte[] bytes, int offset, int count)
+		{
+			if (bytes == null)
+				return null;
+
+			if (bytes.Length == 0)
+				return String.Empty;
+
+			return Encoding.ASCII.GetString(UrlEncodeToBytes(bytes, offset, count));
+		}
+
+		public static byte[] UrlEncodeToBytes(string str)
+		{
+			return UrlEncodeToBytes(str, Encoding.UTF8);
+		}
+
+		public static byte[] UrlEncodeToBytes(string str, Encoding e)
+		{
+			if (str == null)
+				return null;
+
+			if (str.Length == 0)
+				return new byte[0];
+
+			byte[] bytes = e.GetBytes(str);
+			return UrlEncodeToBytes(bytes, 0, bytes.Length);
+		}
+
+		public static byte[] UrlEncodeToBytes(byte[] bytes)
+		{
+			if (bytes == null)
+				return null;
+
+			if (bytes.Length == 0)
+				return new byte[0];
+
+			return UrlEncodeToBytes(bytes, 0, bytes.Length);
+		}
+
+		public static byte[] UrlEncodeToBytes(byte[] bytes, int offset, int count)
+		{
+			if (bytes == null)
+				return null;
+#if NET_4_0
+			return HttpEncoder.Current.UrlEncode (bytes, offset, count);
+#else
+			return HttpEncoder.UrlEncodeToBytes(bytes, offset, count);
+#endif
+		}
+
+		public static string UrlEncodeUnicode(string str)
+		{
+			if (str == null)
+				return null;
+
+			return Encoding.ASCII.GetString(UrlEncodeUnicodeToBytes(str));
+		}
+
+		public static byte[] UrlEncodeUnicodeToBytes(string str)
+		{
+			if (str == null)
+				return null;
+
+			if (str.Length == 0)
+				return new byte[0];
+
+			MemoryStream result = new MemoryStream(str.Length);
+			foreach (char c in str)
+			{
+				HttpEncoder.UrlEncodeChar(c, result, true);
+			}
+			return result.ToArray();
+		}
+
+		/// <summary>
+		/// Decodes an HTML-encoded string and returns the decoded string.
+		/// </summary>
+		/// <param name="s">The HTML string to decode. </param>
+		/// <returns>The decoded text.</returns>
+		public static string HtmlDecode(string s)
+		{
+#if NET_4_0
+			if (s == null)
+				return null;
+			
+			using (var sw = new StringWriter ()) {
+				HttpEncoder.Current.HtmlDecode (s, sw);
+				return sw.ToString ();
+			}
+#else
+			return HttpEncoder.HtmlDecode(s);
+#endif
+		}
+
+		/// <summary>
+		/// Decodes an HTML-encoded string and sends the resulting output to a TextWriter output stream.
+		/// </summary>
+		/// <param name="s">The HTML string to decode</param>
+		/// <param name="output">The TextWriter output stream containing the decoded string. </param>
+		public static void HtmlDecode(string s, TextWriter output)
+		{
+			if (output == null)
+			{
+#if NET_4_0
+				throw new ArgumentNullException ("output");
+#else
+				throw new NullReferenceException(".NET emulation");
+#endif
+			}
+
+			if (!String.IsNullOrEmpty(s))
+			{
+#if NET_4_0
+				HttpEncoder.Current.HtmlDecode (s, output);
+#else
+				output.Write(HttpEncoder.HtmlDecode(s));
+#endif
+			}
+		}
+
+		public static string HtmlEncode(string s)
+		{
+#if NET_4_0
+			if (s == null)
+				return null;
+			
+			using (var sw = new StringWriter ()) {
+				HttpEncoder.Current.HtmlEncode (s, sw);
+				return sw.ToString ();
+			}
+#else
+			return HttpEncoder.HtmlEncode(s);
+#endif
+		}
+
+		/// <summary>
+		/// HTML-encodes a string and sends the resulting output to a TextWriter output stream.
+		/// </summary>
+		/// <param name="s">The string to encode. </param>
+		/// <param name="output">The TextWriter output stream containing the encoded string. </param>
+		public static void HtmlEncode(string s, TextWriter output)
+		{
+			if (output == null)
+			{
+#if NET_4_0
+				throw new ArgumentNullException ("output");
+#else
+				throw new NullReferenceException(".NET emulation");
+#endif
+			}
+
+			if (!String.IsNullOrEmpty(s))
+			{
+#if NET_4_0
+				HttpEncoder.Current.HtmlEncode (s, output);
+#else
+				output.Write(HttpEncoder.HtmlEncode(s));
+#endif
+			}
+		}
+#if NET_4_0
+		public static string HtmlEncode (object value)
+		{
+			if (value == null)
+				return null;
+
+			IHtmlString htmlString = value as IHtmlString;
+			if (htmlString != null)
+				return htmlString.ToHtmlString ();
+			
+			return HtmlEncode (value.ToString ());
+		}
+
+		public static string JavaScriptStringEncode (string value)
+		{
+			return JavaScriptStringEncode (value, false);
+		}
+
+		public static string JavaScriptStringEncode (string value, bool addDoubleQuotes)
+		{
+			if (String.IsNullOrEmpty (value))
+				return addDoubleQuotes ? "\"\"" : String.Empty;
+
+			int len = value.Length;
+			bool needEncode = false;
+			char c;
+			for (int i = 0; i < len; i++) {
+				c = value [i];
+
+				if (c >= 0 && c <= 31 || c == 34 || c == 39 || c == 60 || c == 62 || c == 92) {
+					needEncode = true;
+					break;
+				}
+			}
+
+			if (!needEncode)
+				return addDoubleQuotes ? "\"" + value + "\"" : value;
+
+			var sb = new StringBuilder ();
+			if (addDoubleQuotes)
+				sb.Append ('"');
+
+			for (int i = 0; i < len; i++) {
+				c = value [i];
+				if (c >= 0 && c <= 7 || c == 11 || c >= 14 && c <= 31 || c == 39 || c == 60 || c == 62)
+					sb.AppendFormat ("\\u{0:x4}", (int)c);
+				else switch ((int)c) {
+						case 8:
+							sb.Append ("\\b");
+							break;
+
+						case 9:
+							sb.Append ("\\t");
+							break;
+
+						case 10:
+							sb.Append ("\\n");
+							break;
+
+						case 12:
+							sb.Append ("\\f");
+							break;
+
+						case 13:
+							sb.Append ("\\r");
+							break;
+
+						case 34:
+							sb.Append ("\\\"");
+							break;
+
+						case 92:
+							sb.Append ("\\\\");
+							break;
+
+						default:
+							sb.Append (c);
+							break;
+					}
+			}
+
+			if (addDoubleQuotes)
+				sb.Append ('"');
+
+			return sb.ToString ();
+		}
+#endif
+		public static string UrlPathEncode(string s)
+		{
+#if NET_4_0
+			return HttpEncoder.Current.UrlPathEncode (s);
+#else
+			return HttpEncoder.UrlPathEncode(s);
+#endif
+		}
+
+		public static NameValueCollection ParseQueryString(string query)
+		{
+			return ParseQueryString(query, Encoding.UTF8);
+		}
+
+		public static NameValueCollection ParseQueryString(string query, Encoding encoding)
+		{
+			if (query == null)
+				throw new ArgumentNullException("query");
+			if (encoding == null)
+				throw new ArgumentNullException("encoding");
+			if (query.Length == 0 || (query.Length == 1 && query[0] == '?'))
+				return new NameValueCollection();
+			if (query[0] == '?')
+				query = query.Substring(1);
+
+			NameValueCollection result = new HttpQSCollection();
+			ParseQueryString(query, encoding, result);
+			return result;
+		}
+
+		internal static void ParseQueryString(string query, Encoding encoding, NameValueCollection result)
+		{
+			if (query.Length == 0)
+				return;
+
+			string decoded = HtmlDecode(query);
+			int decodedLength = decoded.Length;
+			int namePos = 0;
+			bool first = true;
+			while (namePos <= decodedLength)
+			{
+				int valuePos = -1, valueEnd = -1;
+				for (int q = namePos; q < decodedLength; q++)
+				{
+					if (valuePos == -1 && decoded[q] == '=')
+					{
+						valuePos = q + 1;
+					}
+					else if (decoded[q] == '&')
+					{
+						valueEnd = q;
+						break;
+					}
+				}
+
+				if (first)
+				{
+					first = false;
+					if (decoded[namePos] == '?')
+						namePos++;
+				}
+
+				string name, value;
+				if (valuePos == -1)
+				{
+					name = null;
+					valuePos = namePos;
+				}
+				else
+				{
+					name = UrlDecode(decoded.Substring(namePos, valuePos - namePos - 1), encoding);
+				}
+				if (valueEnd < 0)
+				{
+					namePos = -1;
+					valueEnd = decoded.Length;
+				}
+				else
+				{
+					namePos = valueEnd + 1;
+				}
+				value = UrlDecode(decoded.Substring(valuePos, valueEnd - valuePos), encoding);
+
+				result.Add(name, value);
+				if (namePos == -1)
+					break;
+			}
+		}
+		#endregion // Methods
+	}
+}

+ 69 - 0
src/XUnity.AutoTranslator.Plugin.Core/Web/ExciteTranslateEndpoint.cs

@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Text;
+using SimpleJSON;
+using UnityEngine;
+using XUnity.AutoTranslator.Plugin.Core.Configuration;
+using XUnity.AutoTranslator.Plugin.Core.Constants;
+using XUnity.AutoTranslator.Plugin.Core.Extensions;
+
+namespace XUnity.AutoTranslator.Plugin.Core.Web
+{
+    public class ExciteTranslateEndpoint : KnownHttpEndpoint
+    {
+        private static readonly string HttpsServicePointTemplateUrl = "https://www.excite.co.jp/world/?wb_lp={0}{1}&before={2}";
+
+        // Author: Johnny Cee (https://stackoverflow.com/questions/10709821/find-text-in-string-with-c-sharp)
+        private static string getBetween(string strSource, string strStart, string strEnd)
+        {
+            const int kNotFound = -1;
+
+            var startIdx = strSource.IndexOf(strStart);
+            if (startIdx != kNotFound)
+            {
+                startIdx += strStart.Length;
+                var endIdx = strSource.IndexOf(strEnd, startIdx);
+                if (endIdx > startIdx)
+                {
+                    return strSource.Substring(startIdx, endIdx - startIdx);
+                }
+            }
+            return String.Empty;
+        }
+
+        public ExciteTranslateEndpoint()
+        {
+            ServicePointManager.ServerCertificateValidationCallback += Security.AlwaysAllowByHosts( "www.excite.co.jp", "excite.co.jp" );
+        }
+
+      public override void ApplyHeaders( WebHeaderCollection headers )
+      {
+         headers[ HttpRequestHeader.UserAgent ] = "Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53";
+         headers[ HttpRequestHeader.Accept ] = "text/html";
+         headers[ HttpRequestHeader.AcceptCharset ] = "UTF-8";
+         headers[ "DNT" ] = "1";
+      }
+
+        public override bool TryExtractTranslated(string result, out string translated)
+        {
+            try
+            {                
+                String extracted = getBetween(result, "class=\"inputText\">", "</p>");
+                translated = RestSharp.Contrib.HttpUtility.HtmlDecode( extracted ?? string.Empty );
+                return true;
+            }
+            catch
+            {
+                translated = null;
+                return false;
+            }
+        }
+
+        public override string GetServiceUrl(string untranslatedText, string from, string to)
+        {
+            return string.Format(HttpsServicePointTemplateUrl, from.ToUpper(), to.ToUpper(), WWW.EscapeURL(untranslatedText));
+        }
+    }
+}

+ 69 - 0
src/XUnity.AutoTranslator.Plugin.Core/Web/GoogleTranslateHackEndpoint.cs

@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Text;
+using SimpleJSON;
+using UnityEngine;
+using XUnity.AutoTranslator.Plugin.Core.Configuration;
+using XUnity.AutoTranslator.Plugin.Core.Constants;
+using XUnity.AutoTranslator.Plugin.Core.Extensions;
+
+namespace XUnity.AutoTranslator.Plugin.Core.Web
+{
+    public class GoogleTranslateHackEndpoint : KnownHttpEndpoint
+    {
+        private static readonly string HttpsServicePointTemplateUrl = "https://translate.google.com/m?hl=pl&sl={0}&tl={1}&ie=UTF-8&q={2}";
+
+        // Author: Johnny Cee (https://stackoverflow.com/questions/10709821/find-text-in-string-with-c-sharp)
+        private static string getBetween(string strSource, string strStart, string strEnd)
+        {
+            const int kNotFound = -1;
+
+            var startIdx = strSource.IndexOf(strStart);
+            if (startIdx != kNotFound)
+            {
+                startIdx += strStart.Length;
+                var endIdx = strSource.IndexOf(strEnd, startIdx);
+                if (endIdx > startIdx)
+                {
+                    return strSource.Substring(startIdx, endIdx - startIdx);
+                }
+            }
+            return String.Empty;
+        }
+
+        public GoogleTranslateHackEndpoint()
+        {
+            ServicePointManager.ServerCertificateValidationCallback += Security.AlwaysAllowByHosts( "translate.google.com" );
+        }
+
+      public override void ApplyHeaders( WebHeaderCollection headers )
+      {
+         headers[ HttpRequestHeader.UserAgent ] = "Opera/9.80 (J2ME/MIDP; Opera Mini/5.1.21214/28.2725; U; en) Presto/2.8.119 Version/11.10";
+         headers[ HttpRequestHeader.Accept ] = "*/*";
+         headers[ HttpRequestHeader.AcceptCharset ] = "UTF-8";
+      }
+
+        public override bool TryExtractTranslated(string result, out string translated)
+        {
+            try
+            {
+
+                String extracted = getBetween(result, "class=\"t0\">", "</div>");
+                translated = RestSharp.Contrib.HttpUtility.HtmlDecode( extracted ?? string.Empty );
+                return true;
+            }
+            catch
+            {
+                translated = null;
+                return false;
+            }
+        }
+
+        public override string GetServiceUrl(string untranslatedText, string from, string to)
+        {
+            return string.Format(HttpsServicePointTemplateUrl, from, to, WWW.EscapeURL(untranslatedText));
+        }
+    }
+}

+ 10 - 5
src/XUnity.AutoTranslator.Plugin.Core/Web/KnownEndpoints.cs

@@ -8,9 +8,6 @@ namespace XUnity.AutoTranslator.Plugin.Core.Web
 {
    public static class KnownEndpoints
    {
-      public static readonly KnownHttpEndpoint GoogleTranslate = new GoogleTranslateEndpoint();
-      public static readonly KnownHttpEndpoint BaiduTranslate = new BaiduTranslateEndpoint();
-
       public static KnownHttpEndpoint FindEndpoint( string identifier )
       {
          if( string.IsNullOrEmpty( identifier ) ) return null;
@@ -18,9 +15,17 @@ namespace XUnity.AutoTranslator.Plugin.Core.Web
          switch( identifier )
          {
             case KnownEndpointNames.GoogleTranslate:
-               return GoogleTranslate;
+               return new GoogleTranslateEndpoint();
+            case KnownEndpointNames.GoogleTranslateHack:
+               return new GoogleTranslateHackEndpoint();
             case KnownEndpointNames.BaiduTranslate:
-               return BaiduTranslate;
+               return new BaiduTranslateEndpoint();
+            case KnownEndpointNames.YandexTranslate:
+               return new YandexTranslateEndpoint();
+            case KnownEndpointNames.WatsonTranslate:
+               return new WatsonTranslateEndpoint();
+            case KnownEndpointNames.ExciteTranslate:
+               return new ExciteTranslateEndpoint();
             default:
                return new DefaultEndpoint( identifier );
          }

+ 61 - 0
src/XUnity.AutoTranslator.Plugin.Core/Web/WatsonTranslateEndpoint.cs

@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Text;
+using SimpleJSON;
+using UnityEngine;
+using XUnity.AutoTranslator.Plugin.Core.Configuration;
+using XUnity.AutoTranslator.Plugin.Core.Constants;
+using XUnity.AutoTranslator.Plugin.Core.Extensions;
+
+namespace XUnity.AutoTranslator.Plugin.Core.Web
+{
+    public class WatsonTranslateEndpoint : KnownHttpEndpoint
+    {
+        private static readonly string HttpsServicePointTemplateUrl = Settings.WatsonAPIUrl.TrimEnd('/')+ "/v2/translate?model_id={0}-{1}&text={2}";
+
+        public WatsonTranslateEndpoint()
+        {
+            ServicePointManager.ServerCertificateValidationCallback += Security.AlwaysAllowByHosts( new Uri( Settings.WatsonAPIUrl ).Host );
+        }
+
+      public override void ApplyHeaders( WebHeaderCollection headers )
+      {
+         headers[ HttpRequestHeader.UserAgent ] = "curl/7.55.1";
+         headers[ HttpRequestHeader.Accept ] = "application/json";
+         headers[ HttpRequestHeader.AcceptCharset ] = "UTF-8";
+         headers[ HttpRequestHeader.Authorization ] = "Basic " + System.Convert.ToBase64String( System.Text.Encoding.ASCII.GetBytes( Settings.WatsonAPIUsername + ":" + Settings.WatsonAPIPassword ) );
+      }
+
+        public override bool TryExtractTranslated(string result, out string translated)
+        {
+            try
+            {
+                var obj = JSON.Parse(result);
+                var lineBuilder = new StringBuilder(result.Length);
+                
+                foreach (JSONNode entry in obj.AsObject["translations"].AsArray) {
+                    var token = entry.AsObject["translation"].ToString();
+                    token = token.Substring(1, token.Length - 2).UnescapeJson();
+
+                    if (!lineBuilder.EndsWithWhitespaceOrNewline()) lineBuilder.Append("\n");
+
+                    lineBuilder.Append(token);
+                }
+                translated = lineBuilder.ToString();               
+                return true;
+            }
+            catch (Exception)
+            {
+                translated = null;
+                return false;
+            }
+        }
+
+        public override string GetServiceUrl(string untranslatedText, string from, string to)
+        {            
+            return string.Format(HttpsServicePointTemplateUrl, from, to, WWW.EscapeURL(untranslatedText));
+        }
+    }
+}

+ 72 - 0
src/XUnity.AutoTranslator.Plugin.Core/Web/YandexTranslateEndpoint.cs

@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Text;
+using SimpleJSON;
+using UnityEngine;
+using XUnity.AutoTranslator.Plugin.Core.Configuration;
+using XUnity.AutoTranslator.Plugin.Core.Constants;
+using XUnity.AutoTranslator.Plugin.Core.Extensions;
+
+namespace XUnity.AutoTranslator.Plugin.Core.Web
+{
+    public class YandexTranslateEndpoint : KnownHttpEndpoint
+    {
+        private static readonly string HttpsServicePointTemplateUrl = "https://translate.yandex.net/api/v1.5/tr.json/translate?key={3}&text={2}&lang={0}-{1}&format=plain";
+        public YandexTranslateEndpoint()
+        {
+            ServicePointManager.ServerCertificateValidationCallback += Security.AlwaysAllowByHosts( "translate.yandex.net" );
+        }
+
+      public override void ApplyHeaders( WebHeaderCollection headers )
+      {
+         headers[ HttpRequestHeader.UserAgent ] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.183 Safari/537.36 Vivaldi/1.96.1147.55";
+         headers[ HttpRequestHeader.Accept ] = "*/*";
+         headers[ HttpRequestHeader.AcceptCharset ] = "UTF-8";
+      }
+
+        public override bool TryExtractTranslated(string result, out string translated)
+        {
+            try
+            {
+
+                var obj = JSON.Parse(result);
+                var lineBuilder = new StringBuilder(result.Length);
+
+                var code = obj.AsObject["code"].ToString();
+
+                if (code == "200")
+                {
+                    var token = obj.AsObject["text"].ToString();
+                    token = token.Substring(2, token.Length - 4).UnescapeJson();
+                    if (String.IsNullOrEmpty(token))
+                    {
+                        translated = null;
+                        return false;
+                    }
+
+                    if (!lineBuilder.EndsWithWhitespaceOrNewline()) lineBuilder.Append("\n");
+                    lineBuilder.Append(token);
+
+                    translated = lineBuilder.ToString();
+                    return true;
+                } else
+                {
+                    translated = null;
+                    return false;
+                }                
+            }
+            catch (Exception)
+            {
+                translated = null;
+                return false;
+            }
+        }
+
+        public override string GetServiceUrl(string untranslatedText, string from, string to)
+        {
+            return string.Format(HttpsServicePointTemplateUrl, from, to, WWW.EscapeURL(untranslatedText), Settings.YandexAPIKey);
+        }
+    }
+}

+ 4 - 0
src/XUnity.AutoTranslator.Plugin.Core/XUnity.AutoTranslator.Plugin.Core.csproj

@@ -24,4 +24,8 @@
     </Reference>
   </ItemGroup>
 
+  <ItemGroup>
+    <Folder Include="MonoHttp\" />
+  </ItemGroup>
+
 </Project>