背景介绍
前段时间在做一个类似于“一键翻译”的小功能,需要对长文本进行多语种的翻译,本以为很简单,不过在网上找来找去,居然发现没有一个完美的方法来解决,我只好从网上搜来了各种各样的翻译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). 翻译者接口,为以后扩展使用
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 请求方式翻译者实现类
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 = "http://translate.google.com.hk/?langpair={0}&text={1}"; //google翻译URL模板:GET方式请求 private string UrlTemplate = "http://translate.google.com.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). 假模假样的工厂类……大家勿喷啊,只是一个简单工厂实现
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). 测试类:
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 slide your iPad out quickly and safely. Stain-resistant synthetic outer shell with smooth micro suede interior."); 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=""http://www.xxxx.com/images/Insert/2012/4/19/2012041905405116.JPG"" alt="""" width=""500"" height=""500"" /><br /><img src=""http://www.xxxx.com/images/Insert/2012/4/19/2012041905421548.JPG"" alt="""" width=""500"" height=""500"" /><br /><img src=""http://www.xxxx.com/images/Insert/2012/4/19/2012041905421714.JPG"" alt="""" width=""500"" height=""500"" /><br /><img src=""http://www.xxxx.com/images/Insert/2012/4/19/2012041905420649.JPG"" alt="""" width=""500"" height=""500"" /><br /><img src=""http://www.xxxx.com/images/Insert/2012/4/19/2012041905415831.JPG"" alt="""" width=""500"" height=""500"" /><br /><img src=""http://www.xxxx.com/images/Insert/2012/4/19/2012041905415058.JPG"" alt="""" width=""500"" height=""500"" /></span></span></p>"); 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). 代码
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=""d83361947aca6bed-626a88e71258e3a8-g3d7ae31013d34b9c-e""></meta>"; /// <summary> /// Google整页翻译控件,放入需要显示“选择语言”框的地方 /// </summary> public const string GoogleTranslateControl = @"<div id=""google_translate_element""></div><script type=""text/javascript"">function googleTranslateElementInit() { new google.translate.TranslateElement({pageLanguage: 'zh-CN', layout: google.translate.TranslateElement.InlineLayout.SIMPLE, autoDisplay: false}, 'google_translate_element');}</script><script type=""text/javascript"" src=""//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit""></script>"; }
2). 使用示例,只要将那两个变量分别加在HTML页面的Head中和想出现“选择语言”框的地方即可。
PS:这是小弟第一次写博,园子里很多大鸟,在各位面前献丑了,写出来只是希望大家碰到此类的问题的时候不用再去重复造轮子了,把小弟的轮子改改,或许比那些API更好用。更关键的是:无限制,免费,你懂的。^_^
如果代码对大家有用,还希望大家支持一下。另外,不知道在园子里怎么上传压缩包附件,只能发外链地址了,希望各位老鸟指点一下啊。
代码打包下载地址:http://www.kuaipan.cn/file/id_18864681775007923.htm