教程:编写放在收藏夹里的网页划词翻译工具

关于收藏夹工具

随着互联网技术的发展,越来越多的传统计算机应用被移植到了web上,目前流行起了一种“放在收藏夹里的工具”,点一下收藏书签,无需安装运行,便可以开始使用强大的功能。

比如搜狗云输入法(搜狗云输入法的简单分析)、人间网转帖工具等,都是应用了这种方式。

这种方式的优点是显而易见的:

· 无需安装,随点随用;

· 跨操作系统、跨平台,只要有浏览器就可以使用;

· 程序放在服务器上,可以随时更新升级;

· …

这种看似很强大的应用,其实它的原理很简单,实现也很容易,今天我们就基于这一理念,利用google翻译API,一起做一个简单的网页划词翻译工具,和大家一起学习和理解这一种创新的互联网应用模式。

demo可以看这里: http://www.oncoding.cn/demos/trans/index.html

功能描述

当你看到一篇艰涩的外文网页的时候,你会怎么办?打开谷歌金山词霸?那如果是日文呢?打开reanslate.google.cn,粘贴进去看翻译?

不用这么麻烦,有了划词翻译工具,就可以直接在网页上选中词、句、段进行翻译了。

原理及功能实现

我们使用google翻译API进行翻译,功能完全在前端实现,不需要任何后端程序,由于以下代码仅为配合本文而写,只为了向大家介绍这种应用的原理和思想,所以力求简洁,功能也不完备,仅可作为参考。

目前采用的方式是将其他语言翻译为中文,google language API很强大,还可以开发出其他各种实用的功能。

1. 收藏夹书签中保存的代码:

/**
 * 收藏夹书签中保存这段代码,
 * 作用是在页面head中建立一个<script>标签,
 * 引入远程的js文件
*/
javascript: void((function() {
    var scr = document.createElement('script');
    var url = 'http://localhost/trans/trans.js';
    scr.setAttribute('src', url);
    document.getElementsByTagName('head').item(0).appendChild(scr);
})())

这样,用户在任意一个网页上点击书签,就可以引入我们的翻译js,即将划词翻译功能应用到了网页上。

2. 页面实时划词功能实现

我们的功能设计要求能用鼠标在页面上选中词语或文段进行实时翻译,怎样取得目前页面上选中的内容呢,定义如下兼容各浏览器的函数:

/**
 * 取得页面上选中的内容
 */
function select(){
    if (window.getSelection) {
        return window.getSelection();
    }
    else if (document.getSelection) {
        return document.getSelection();
    }
    else if (document.selection) {
        return document.selection.createRange().text;
    }
    else {
        return false;
    }
}

下面我们需要判断用户的划词动作。这里用mouseup事件进行的判断——当鼠标抬起时,进行判断并处理。当然有很多的mouseup事件并不需要进行搜索,也不是每次选词都要立即进行翻译,所以加入了一个600毫秒的延时判断:

/**
 * 鼠标弹起后的处理
 */
var timer = null; // 定义计时器对象

function dealMouseUp(){
    timer ? clearTimeout(timer) : null; // 如果在600毫秒内有第二次点击,则清除计时器,重新计时
    timer = setTimeout(function(){ // 定义计时器
        var selectText = select();
        if (selectText != "") {
            goTrans(select());
        }
    }, 600);
}

bind(document, "mouseup", dealMouseUp); // 绑定document的mouseup事件

绑定事件函数定义如下:

/**
 * 绑定事件
 */
function bind(obj, type, fn){
    if (obj.attachEvent) {
        obj['e' + type + fn] = fn;
        obj[type + fn] = function(){
            obj['e' + type + fn](window.event);
        }
        obj.attachEvent('on' + type, obj[type + fn]);
    }
    else
        obj.addEventListener(type, fn, false);
}

具体分析请移步:JavaScript跨浏览器的添加删除事件绑定函数

3. 翻译功能的实现

google translate提供了一系列强大的API,让第三方应用可以轻松的调用它的搜索接口。

为方便起见,我们使用google 翻译API的“RESTful 界面”,它允许使用GET的方式传入待翻译参数,以JSON或JSONP形式输出。为保证代码简单易读,我们使用JSONP形式回调预定义的函数,进行翻译结果的显示。

请求google翻译结果:

/**
 * jsonp方式请求google翻译接口
 */
function goTrans(text){
    var googleTransUrl = "http://ajax.googleapis.com/ajax/services/language/translate?q=" + text + "&langpair=" + langFrom + "|" + langTo + "&v=1.0&callback=onTransBack";
    createScript(googleTransUrl);
}

在google的请求url中加入参数 ” &callback=fn “,即可在返回后调用指定的回调函数,关于如何调用,本文使用最简单的jsonp实现方式——向页面中加入<script>标签来运行,createScript定义如下:

/**
 * 向页面中写入script标签
 */
function createScript(url){
    var existScr = document.getElementById('ocTransScr'); //判断存在则删除
    if (existScr) {
        existScr.parentNode.removeChild(existScr);
    }
    var scr = document.createElement('script');
    scr.setAttribute('id', 'ocTransScr');
    scr.setAttribute('type', 'text/javascript');
    scr.setAttribute('src', url);
    document.getElementsByTagName('head')[0].appendChild(scr);
}

用这种实现方式的问题还是不少,关于jsonp的更详细介绍,请自己搜索吧。。

全部代码

使用匿名函数建立闭包,然后把翻译结果显示函数注册到了window,尽力不污染网页,全部代码如下:

/**
 * 简易的网页划词翻译工具
 * @author j5726
 * @link http://www.oncoding.cn
 */
(function(){

    var timer = null;
    var langFrom = "";
    var langTo = "zh";
    /**
     * 绑定事件
     */
    function bind(obj, type, fn){
        if (obj.attachEvent) {
            obj['e' + type + fn] = fn;
            obj[type + fn] = function(){
                obj['e' + type + fn](window.event);
            }
            obj.attachEvent('on' + type, obj[type + fn]);
        }
        else
            obj.addEventListener(type, fn, false);
    }
    /**
     * 取得页面上选中的内容
     */
    function select(){
        if (window.getSelection) {
            return window.getSelection();
        }
        else if (document.getSelection) {
            return document.getSelection();
        }
        else if (document.selection) {
            return document.selection.createRange().text;
        }
        else {
            return false;
        }
    }
    /**
     * 向页面中写入script标签
     */
    function createScript(url){
        var existScr = document.getElementById('ocTransScr');
        if (existScr) {
            existScr.parentNode.removeChild(existScr);
        }
        var scr = document.createElement('script');
        scr.setAttribute('id', 'ocTransScr');
        scr.setAttribute('type', 'text/javascript');
        scr.setAttribute('src', url);
        document.getElementsByTagName('head')[0].appendChild(scr);
    }
    /**
     * 鼠标弹起后的处理
     */
    function dealMouseUp(){
        timer ? clearTimeout(timer) : null;
        timer = setTimeout(function(){
            var selectText = select();
            if (selectText != "") {
                goTrans(select());
            }
        }, 600);
    }
    /**
     * jsonp方式请求google翻译接口
     */
    function goTrans(text){
        var googleTransUrl = "http://ajax.googleapis.com/ajax/services/language/translate?q=" + text + "&langpair=" + langFrom + "|" + langTo + "&v=1.0&callback=onTransBack";
        createScript(googleTransUrl);
    }
    /**
     * 处理响应
     */
    function onTransBack(json){
        document.getElementById("ocTransBoxResult").innerHTML = json.responseData.translatedText;
    }
    function createTransbox() {
        var box = document.createElement("div");
        box.id = "ocTransBox";
        box.unselectable = "on";
        box.style.position = "fixed";
        box.style.top = "20px";
        box.style.right = "20px";
        box.style.zIndex = 1000;
        box.style.maxWidth = "280px";
        box.style.backgroundColor = "#996600";
        box.style.color = "#FFFFFF";
        box.style.padding = "6px";
        box.style.border = "3px solid #FFFFFF";
        box.style.visibility = 'visible';
        box.innerHTML = "<b>翻译:</b><br /><span style='font-size:13px' id='ocTransBoxResult'></span>";
        document.getElementsByTagName('body')[0].appendChild(box);
    }
    /**
     * 注册到window
     */
    window.onTransBack = onTransBack;
    /**
     * 绑定事件
     */
    createTransbox();
    bind(document, "mouseup", dealMouseUp);

})()

代码及demo页面文件打包下载

后记

本文主要介绍这一种互联网应用程序开发的思想和一般方法,目前这种应用方式刚刚兴起,其应用前景非常广泛,也有很多值得研究和学习的细节。由于水平和时间所限,本文使用的代码也有很多不高明的地方,欢迎批评指正。

幼学笔记原创内容,根据CC协议发布,欢迎具名转载。

2 个评论:

  1. KUN10
    Posted 2009年12月30日 at 1:00 下午 | Permalink

    select那段不错,对俺的编辑器有用~~

  2. thomson
    Posted 2010年09月10日 at 11:22 上午 | Permalink

    编码不能自动识别,还有就是样式问题。每次要拉到最后面去查看翻译的内容

发表评论

*
*

文明评论,共同进步