51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 2183|回复: 0
打印 上一主题 下一主题

[开心一刻] 五十种语言的“圣诞快乐”(上):分析与实现

[复制链接]
  • TA的每日心情
    无聊
    前天 09:38
  • 签到天数: 493 天

    连续签到: 3 天

    [LV.9]测试副司令

    跳转到指定楼层
    1#
    发表于 2018-12-26 09:53:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

    圣诞节到了,于是在某个邮件列表上收到了这样一封信,“五种语言的圣诞快乐”:

    • 汉语版:圣诞快乐!
    • 英语版:麦瑞克瑞死没死!
    • 俄语版:买个萝卜切吧切吧炖了吧!
    • 韩语版:空起哇撒起哇, 米死搭!
    • 日语版:锅你得洗哇,碗你得洗哇,盆你得洗哇,锅碗盆你都得洗了哇!

    后来有人贴了个更全的,于是有人猜测“这不是使用Google翻译做的吧?”哗,有意思的,我心想。以前也用过一个别人封装好的程序集,可以调用在线的Google Translate服务进行翻译。那么,我们现在自己来试试看吧。

    使用Google Translate

    Google Translate是一个在线工具,可以翻译五十多种语言。可惜的是,Google Translate并没有像Bing翻译那样直接提供RESTful和SOAP形式的API,不过这也给了我们一些探索的乐趣。目前Google Translate只提供一个脚本,您可以把它嵌入到网页中,这样便可以使用其翻译功能了。例如,您可以在页面上放置这样的内容:

    1. <div id="google_translate_element">圣诞快乐</div>

    2. <script>
    3.     function googleTranslateElementInit() {
    4.         new google.translate.TranslateElement({
    5.             pageLanguage: 'zh-CN'
    6.         }, 'google_translate_element');
    7.     }
    8. </script>

    9. <script src="http://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
    复制代码

    于是乎:

    以上是我选择将其翻译为英语后的结果——当然Google Translate可以让你选择五十多种目标语言。

    获取语言信息

    使用Fiddler抓包后便可以发现,在页面加载时Google Translate的脚本首先会去加载所有它支持的语言:

    1. GET /translate_a/l?client=te&hl=en&cb=_callbacks_._0g3matv3f HTTP/1.1
    2. Accept: */*
    3. Referer: http://localhost:46714/translate.html
    4. Accept-Language: en-us
    5. User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E; OfficeLiveConnector.1.3; OfficeLivePatch.0.0)
    6. Accept-Encoding: gzip, deflate
    7. Host: translate.googleapis.com
    8. Connection: Keep-Alive
    复制代码

    这样便会得到这样的结果:

    1. _callbacks_._0g3matv3f({'sl':{'auto':'Detect language','af':'Afrikaans','sq':'Albanian','ar':'Arabic','be':'Belarusian','bg':'Bulgarian','ca':'Catalan','zh-CN':'Chinese','hr':'Croatian','cs':'Czech','da':'Danish','nl':'Dutch','en':'English','et':'Estonian','tl':'Filipino','fi':'Finnish','fr':'French','gl':'Galician','de':'German','el':'Greek','iw':'Hebrew','hi':'Hindi','hu':'Hungarian','is':'Icelandic','id':'Indonesian','ga':'Irish','it':'Italian','ja':'Japanese','ko':'Korean','lv':'Latvian','lt':'Lithuanian','mk':'Macedonian','ms':'Malay','mt':'Maltese','no':'Norwegian','fa':'Persian','pl':'Polish','pt':'Portuguese','ro':'Romanian','ru':'Russian','sr':'Serbian','sk':'Slovak','sl':'Slovenian','es':'Spanish','sw':'Swahili','sv':'Swedish','th':'Thai','tr':'Turkish','uk':'Ukrainian','vi':'Vietnamese','cy':'Welsh','yi':'Yiddish'},'tl':{'af':'Afrikaans','sq':'Albanian','ar':'Arabic','be':'Belarusian','bg':'Bulgarian','ca':'Catalan','zh-CN':'Chinese (Simplified)','zh-TW':'Chinese (Traditional)','hr':'Croatian','cs':'Czech','da':'Danish','nl':'Dutch','en':'English','et':'Estonian','tl':'Filipino','fi':'Finnish','fr':'French','gl':'Galician','de':'German','el':'Greek','iw':'Hebrew','hi':'Hindi','hu':'Hungarian','is':'Icelandic','id':'Indonesian','ga':'Irish','it':'Italian','ja':'Japanese','ko':'Korean','lv':'Latvian','lt':'Lithuanian','mk':'Macedonian','ms':'Malay','mt':'Maltese','no':'Norwegian','fa':'Persian','pl':'Polish','pt':'Portuguese','ro':'Romanian','ru':'Russian','sr':'Serbian','sk':'Slovak','sl':'Slovenian','es':'Spanish','sw':'Swahili','sv':'Swedish','th':'Thai','tr':'Turkish','uk':'Ukrainian','vi':'Vietnamese','cy':'Welsh','yi':'Yiddish'}})
    复制代码

    不过,您一定发现了,这些数据为什么是英文的呢?根据经验,这是由浏览器的语言首选项决定的。因此,我将zh-CN加入语言列表中的最上方,在IE里可以在Tools – Internet Options的General标签中设置Languages:

    此时再次刷新页面,就会发现界面变成了中文,而Google Translate也会使用另外的地址来加载语言信息:

    1. GET /translate_a/l?client=te&hl=zh-CN&cb=_callbacks_._0g3mb650r HTTP/1.1
    2. Accept: */*
    3. Referer: http://localhost:46714/translate.html
    4. Accept-Language: zh-CN,en-US;q=0.5
    5. User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E; OfficeLiveConnector.1.3; OfficeLivePatch.0.0)
    6. Accept-Encoding: gzip, deflate
    7. Host: translate.googleapis.com
    8. Connection: Keep-Alive
    复制代码

    其得到的结果是:

    1. _callbacks_._0g3mb650r({'sl':{'auto':'检测语言','sq':'阿尔巴尼亚语','ar':'阿拉伯语','ga':'爱尔兰语','et':'爱沙尼亚语','be':'白俄罗斯语','bg':'保加利亚语','is':'冰岛语','pl':'波兰语','fa':'波斯语','af':'布尔文(南非荷兰语)','da':'丹麦语','de':'德语','ru':'俄语','fr':'法语','tl':'菲律宾语','fi':'芬兰语','ko':'韩语','nl':'荷兰语','gl':'加利西亚语','ca':'加泰罗尼亚语','cs':'捷克语','hr':'克罗地亚语','lv':'拉脱维亚语','lt':'立陶宛语','ro':'罗马尼亚语','mt':'马耳他语','ms':'马来语','mk':'马其顿语','no':'挪威语','pt':'葡萄牙语','ja':'日语','sv':'瑞典语','sr':'塞尔维亚语','sk':'斯洛伐克语','sl':'斯洛文尼亚语','sw':'斯瓦希里语','th':'泰语','tr':'土耳其语','cy':'威尔士语','uk':'乌克兰语','es':'西班牙语','iw':'希伯来语','el':'希腊语','hu':'匈牙利语','it':'意大利语','yi':'意第绪语','hi':'印地语','id':'印尼语','en':'英语','vi':'越南语','zh-CN':'中文'},'tl':{'sq':'阿尔巴尼亚语','ar':'阿拉伯语','ga':'爱尔兰语','et':'爱沙尼亚语','be':'白俄罗斯语','bg':'保加利亚语','is':'冰岛语','pl':'波兰语','fa':'波斯语','af':'布尔文(南非荷兰语)','da':'丹麦语','de':'德语','ru':'俄语','fr':'法语','tl':'菲律宾语','fi':'芬兰语','ko':'韩语','nl':'荷兰语','gl':'加利西亚语','ca':'加泰罗尼亚语','cs':'捷克语','hr':'克罗地亚语','lv':'拉脱维亚语','lt':'立陶宛语','ro':'罗马尼亚语','mt':'马耳他语','ms':'马来语','mk':'马其顿语','no':'挪威语','pt':'葡萄牙语','ja':'日语','sv':'瑞典语','sr':'塞尔维亚语','sk':'斯洛伐克语','sl':'斯洛文尼亚语','sw':'斯瓦希里语','th':'泰语','tr':'土耳其语','cy':'威尔士语','uk':'乌克兰语','es':'西班牙语','iw':'希伯来语','el':'希腊语','hu':'匈牙利语','it':'意大利语','yi':'意第绪语','hi':'印地语','id':'印尼语','en':'英语','vi':'越南语','zh-TW':'中文(繁体)','zh-CN':'中文(简体)'}})
    复制代码

    而其中标红的部分,便是tl(我猜测是Target Language的意思)所对应的JSON格式,我们可以使用以下代码来获取所有的语言信息:

    1. private static Dictionary<string, string> GetLanguages()
    2. {
    3.     var url =
    4.         "http://translate.googleapis.com" +
    5.         "/translate_a/l?client=te&hl=zh-CN&cb=_callbacks_._0g3mb650r";

    6.     var webClient = new WebClient();
    7.     var script = webClient.DownloadString(url);

    8.     var json = Regex.Match(script, @"'tl':({.+})}\)").Groups[1].Value;
    9.     var serializer = new JavaScriptSerializer();
    10.     return serializer.Deserialize<Dictionary<string, string>>(json);
    11. }
    复制代码
    进行翻译

    点击页面上的下拉列表可以进行翻译。例如我们选择“英语”之后,Fiddler便会捕获到一个POST请求:

    1. POST /translate_a/t?client=te&format=html&v=1.0 HTTP/1.1
    2. Accept: */*
    3. Accept-Language: zh-CN
    4. Referer: http://translate.googleapis.com/translate_static/js/element/hrs.swf
    5. x-flash-version: 10,0,32,18
    6. Content-Type: application/x-www-form-urlencoded
    7. Google-Translate-Referer: http://localhost:46714/translate.html
    8. Content-Length: 58
    9. Accept-Encoding: gzip, deflate
    10. User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; .NET4.0C; .NET4.0E; OfficeLiveConnector.1.3; OfficeLivePatch.0.0)
    11. Host: translate.googleapis.com
    12. Connection: Keep-Alive
    13. Pragma: no-cache

    14. q=%E5%9C%A3%E8%AF%9E%E5%BF%AB%E4%B9%90&sl=zh-CN&tl=en&tc=1
    复制代码

    可以看到,需要翻译的文字将作为q被传输到服务器端。这个请求会得到翻译后的结果:

    1. "Merry Christmas"
    复制代码

    于是代码也就很容易写出了:

    1. private static string Translate(string source, string sl, string tl)
    2. {
    3.     var url =
    4.         "https://translate.googleapis.com" +
    5.         "/translate_a/t?client=te&format=html&v=1.0";

    6.     var data = String.Format(
    7.         "q={0}&sl={1}&tl={2}&tc=1",
    8.         HttpUtility.UrlEncode(source), sl, tl);

    9.     var webClient = new WebClient();
    10.     webClient.Encoding = Encoding.UTF8;
    11.     webClient.Headers.Add(
    12.         HttpRequestHeader.UserAgent,
    13.         "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0;)");

    14.     var json = webClient.UploadString(url, data);
    15.     var serializer = new JavaScriptSerializer();
    16.     return serializer.Deserialize<string>(json);
    17. }
    复制代码

    在试验过程中,您可以使用Fiddler的Request Builder功能来发起一些测试请求,这样便可以得知怎么样的Header信息可以获得正确的结果。例如在这里,我发现如果不添加User Agent信息,Google Translate便会返回一些非常奇怪的内容。

    组合

    既然有了以上两个方法,输出翻译结果也再简单不过了:

    1. var languages = GetLanguages();

    2. var targetLanguages = languages.Select(
    3.     p => String.Format(
    4.         "{0}: {1}",
    5.         p.Value,
    6.         Translate("圣诞快乐", "zh-CN", p.Key)));

    7. File.WriteAllLines("output.txt", targetLanguages.ToArray());
    复制代码

    由于语言非常古怪,因此无法在Console上输出,我只能将其直接写到UTF-8的文件中去——最后的结果还是相当有趣的。


    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

    x
    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-9-22 14:29 , Processed in 0.077094 second(s), 25 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表