利⽤Google进⾏⽆长度限制的⽂本翻译(⽆需API,⽆需Money)
背景介绍
  前段时间在做⼀个类似于“⼀键翻译”的⼩功能,需要对长⽂本进⾏多语种的翻译,本以为很简单,不过在⽹上来去,居然发现没有⼀个完美的⽅法来解决,我只好从⽹上搜来了各种各样的翻译API,并揣摩了其使⽤⽅法,不过都不尽完美,其各⽅⾯的缺陷⼤致有:
微软API:利⽤WCF⽅式进⾏翻译,每次翻译英⽂字数最⼤为⼀万两千多个,中⽂字符的话最多为六七千个,最⼤200M字符/⽉的限制,超过限制后要付费。对HTML翻译⽀持完美,翻译结果也不错,但考虑到免费字符数限制,需做账号轮巡,账号注册的步骤那叫⼀个繁琐啊……(此⽅式可做为⾸选翻译⽅式,轮巡的翻译功能已实现,有时间了把源码贴上来。  ——qfzhang于2013-05-30更新)
YoudaoAPI:语⾔⽀持不够多,只有英⽂、⽇⽂、中⽂⼏个之间的互相翻译,且每次请求最多翻译的字符数不能超过200,还有访问频率限制。
GoogleAPI:Google翻译的API,优势明显,翻译结果⼗分准确,尤其是针对HTML,能够准确跳过HTML标签部分,只翻译⽂本,但它是付费使⽤的(v1版为免费版,但接⼝已关闭),其价格为100万字符/20美⾦,其价格⾃然不⾔⽽喻。且在使⽤过程中发现,其标称每次最⼤翻译字符数不能超过2k,但实际使⽤时超过1.5k就会报异常。
甄嬛传华妃第几集死的BaiduAPI:有访问频率限制和长度限制,且翻译结果不理想。
在这四⼤翻译巨头的各种限制之下,不得不另寻出路……
转机
  鉴于Google翻译的准确性,还是果断选择了Google作为⽬标,但其价格实在昂贵,只好从其翻译页⾯上做⽂章。
  在测试时发现,其GET请求中加上⼀些参数可以实现翻译功能,于是乎第⼀个GET版本的翻译功能出炉了,其步骤⼤约分为以下两步:
构造查询字符串,向翻译页⾯发送请求
获取返回的HTML,并从中过滤出所需要的结果。(⼩弟不才,因为这个东西,好好地把正则表达式训练了⼀把^_^)
  然⽽,GET⽅式跟API有同样的问题,超出固定长度后就会报请求异常。于是只能再想其它⽅法。
  后来⼩弟尝试了构造POST请求去访问它,没想到……居然成功了……⼀时⾼兴,代码不敢独享,在此贴出来,希望⼤家有遇到此类问题的,⼀起分享⼀下。
源代码:
1.代码部分
1). 翻译者接⼝,为以后扩展使⽤
View Code
using System;
namespace Common.Translator
{
///<summary>
///语⾔翻译者接⼝
/// ZhangQingFeng    2012-7-27    add
///</summary>
public interface ITranslator
{
///<summary>
///翻译⽂本
/// ZhangQingFeng    2012-7-27    add
///</summary>
///<param name="sourceText">源⽂本</param>
///<param name="sourceLanguageCode">源语⾔类型代码,如:en、zh-CN、zh-TW、ru等</param>
///<param name="targetLanguageCode">⽬标语⾔类型代码,如:en、zh-CN、zh-TW、ru等</param>
///<returns>翻译结果</returns>
string Translate(string sourceText, string sourceLanguageCode, string targetLanguageCode);
///<summary>
///翻译⽂本[⾃动检测源语⾔类型]
/// ZhangQingFeng    2012-7-27    add
///</summary>
///<param name="sourceText">源⽂本</param>
///<param name="targetLanguageCode">⽬标语⾔类型代码,如:en、zh-CN、zh-TW、ru等</param>
作文 成长///<returns>翻译结果</returns>
string Translate(string sourceText, string targetLanguageCode);
}
}
2). Google Post 请求⽅式翻译者实现类
View Code
using System;
using System.Web;
using System.Net;
using System.Text.RegularExpressions;
using System.Text;
namespace Common.Translator
{
///<summary>
/// google translate翻译者类[⾮API,URL访问Google的⽅式]
/
// ZhangQingFeng    2012-7-27    add
///</summary>
public class GoogleTranslator : ITranslator
{
//private string UrlTemplate = "le.hk/?langpair={0}&text={1}";    //google翻译URL模板:GET⽅式请求
private string UrlTemplate = "le.hk/";                            //google翻译URL模板:POST⽅式请求
#region常⽤语⾔编码
private string AutoDetectLanguage = "auto"; //google⾃动判断来源语系
#endregion
///<summary>
///翻译⽂本[⾃动检测源语⾔类型]
/// ZhangQingFeng    2012-7-27    add
///</summary>
///<param name="sourceText">源⽂本</param>
///<param name="targetLanguageCode">⽬标语⾔类型代码,如:en、zh-CN、zh-TW、ru等</param>
///<returns>翻译结果</returns>
public string Translate(string sourceText, string targetLanguageCode)
{
return Translate(sourceText, AutoDetectLanguage, targetLanguageCode);
}
///<summary>
///翻译⽂本
/// ZhangQingFeng    2012-7-27    add
///</summary>
///<param name="sourceText">源⽂本</param>
///<param name="sourceLanguageCode">源语⾔类型代码,如:en、zh-CN、zh-TW、ru等</param>
///<param name="targetLanguageCode">⽬标语⾔类型代码,如:en、zh-CN、zh-TW、ru等</param>
///<returns>翻译结果</returns>
public string Translate(string sourceText, string sourceLanguageCode, string targetLanguageCode)
{
if (string.IsNullOrEmpty(sourceText) || Regex.IsMatch(sourceText, @"^\s*$"))
{
return sourceText;
}
string strReturn = string.Empty;
#region POST⽅式实现,⽆长度限制
string url = UrlTemplate;
//组织请求的数据
string postData = string.Format("langpair={0}&text={1}", HttpUtility.UrlEncode(sourceLanguageCode + "|" + targetLanguageCode), HttpUtility.UrlEncode(sourceText));
byte[] bytes = Encoding.UTF8.GetBytes(postData);
WebClient client = new WebClient();
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
client.Headers.Add("ContentLength", postData.Length.ToString());
byte[] responseData = client.UploadData(url, "POST", bytes);
string strResult = Encoding.UTF8.GetString(responseData);    //响应结果
#endregion
#region GET⽅式实现,有长度限制
//string url = string.Format(UrlTemplate, HttpUtility.UrlEncode(sourceLanguageCode + "|" + targetLanguageCode), HttpUtility.UrlEncode(sourceText));
//WebClient wc = new WebClient();
//wc.Encoding = Encoding.UTF8;
//string strResult = wc.DownloadString(url);                //响应结果
#endregion
/
/使⽤的正则表达式:    \s+id="?result_box"?\s+[^>]*>(.+)</span>\s*</div>\s*</div>\s*<div id=spell-place-holder\s+
string strReg = @"\s+id=""?result_box""?\s+[^>]*>(.+)</span>\s*</div>\s*</div>\s*<div id=spell-place-holder\s+";
Match match = Regex.Match(strResult, strReg, RegexOptions.IgnoreCase | RegexOptions.Singleline);
if (match.Success)
{
strReturn = match.Groups[1].Value;
//<br/>替换为换⾏,如为HTML翻译选项则可去除下⾏代码
strReturn = Regex.Replace(strReturn, @"<br\s*/?>", "\n", RegexOptions.Singleline | RegexOptions.IgnoreCase);
strReturn = Regex.Replace(strReturn, @"<[^>]*>", "", RegexOptions.Singleline | RegexOptions.IgnoreCase);
strReturn = HttpUtility.HtmlDecode(strReturn);
}
return strReturn;
}
}
}
3). 假模假样的⼯⼚类……⼤家勿喷啊,只是⼀个简单⼯⼚实现
View Code
using System;
namespace Common.Translator
雷声大雨点小{
///<summary>
///翻译者⼯⼚类
///</summary>
public class TranslatorFactory
{
///<summary>
///翻译者
///</summary>
///<param name="type">翻译者类型,⽬前只有提供Google翻译</param>
///<returns>翻译者对象</returns>
public static ITranslator CreateTranslator(string type)
{
ITranslator translator = null;
switch (type)
刘仁娜 我们结婚了{
case"Microsoft":
break;
case"Youdao":
break;
default:
translator = new GoogleTranslator();
break;
}
return translator;
}
}
}
4). 测试类:
View Code
using System;
using System.Collections.Generic;
using Common.Translator;
namespace ConsoleTest
{
class Program
{
static void Main(string[] args)
{
ITranslator translator = TranslatorFactory.CreateTranslator("Google");
List<string> lst = new List<string>();
lst.Add("Soft Leather Case for Apple iPad 1 /2/3  With Ploybag Package");
lst.Add("Soft Leather Case,Case for Apple iPad ,ipad case ,PU case");
lst.Add("1X ipad leather case");
lst.Add("Slim enough to slip into a backpack, bag or briefcase, tough enough to protect your iPad from whatever it may find in there. Slip your iPad into Elan Sleeve then flip the tab closure down to secure it. Then gently pull the tab to sli
lst.Add(@"<p><span><span><span><span>Fit for apple iPad 1/2 /3 leather case</span></span></span></span></p>
<p><span><span><span><span>PU leather material with top quality</span></span></span></span></p>
<p><span><span><span><span>Three bright colors to meet your demand</span></span></span></span></p>
<p><span><span>Durable and waterproof,practical and favorable</span></span></p>
<p><span><span>Protect your tablet from scratches, damage and dirt</span></span></p>
高晓松为什么退出奇葩说<p><span><span>Unique design allows easy to controls &ports</span><span> <br /><img src=""/images/Insert/2012/4/19/2012041905405116.JPG"" alt="""" width=""500"" height=""500"" /><br /><img src=""http string strSource=string.Join("\n",lst.ToArray());
string str = translator.Translate(strSource, "zh-CN");
Console.WriteLine(str);
Console.WriteLine("完成");
}
}
}
5). 最后献上运⾏结果:
PS:此⽅式的翻译结果来源于Google翻译页⾯,与那个基本⼀致,但是其对HTML的判断⼒远远⽐不上GoogleAPI,所以⼤家不要见怪,或许以后⼩弟有时间了可以把它完善
下,各位⼤侠有需求的也可以⾃⼰拿到源代码改下,嘿嘿。
2. 附赠⼤家Google⽹站翻译器的使⽤⽅法:
1). 代码
View Code
using System;
///<summary>
///⽹站翻译器[Google提供,整页翻译器]
///    ZhangQingFeng    2012-7-27    add
///说明:
///如果需要在页⾯上使⽤google语⾔翻译,需要做以下两步:
///        1.将本类中的GoogleTranslateMeta内容放⼊Head中,如:Response.Write(SiteTranslator.GoogleTranslateMeta);
///        2.将本类中的GoogleTranslateControl内容放⼊页⾯中需要显⽰“选择语⾔”的地⽅
///</summary>
public class SiteTranslator
{
public SiteTranslator()
{
}
///<summary>
/// Google整页翻译Meta标签,放⼊Head部位
///</summary>
public const string GoogleTranslateMeta = @"<meta name=""google-translate-customization"" content=""d8*******aca6bed-626a88e71258e3a8-g3d7ae31013d34b9c-e""></meta>";
///<summary>
/// Google整页翻译控件,放⼊需要显⽰“选择语⾔”框的地⽅
///</summary>
public const string GoogleTranslateControl = @"<div id=""google_translate_element""></div><script type=""text/javascript"">function googleTranslateElementInit() { anslate.TranslateElement({pageLanguage: 'zh-CN', layout: goog }
2). 使⽤⽰例,只要将那两个变量分别加在HTML页⾯的Head中和想出现“选择语⾔”框的地⽅即可。
PS:这是⼩弟第⼀次写博,园⼦⾥很多⼤鸟,在各位⾯前献丑了,写出来只是希望⼤家碰到此类的问题的时候不⽤再去重复造轮⼦了,把⼩弟的轮⼦改改,或许⽐那些API更好
⽤。更关键的是:⽆限制,免费,你懂的。^_^男孩取名字
如果代码对⼤家有⽤,还希望⼤家⽀持⼀下。另外,不知道在园⼦⾥怎么上传压缩包附件,只能发外链地址了,希望各位⽼鸟指点⼀下啊。