单词翻译常见于APP中,那么在网页中对于一段中英混杂的内容怎么准确的作到单词的翻译呢?
我要渲染的内容是一段段的html,用react渲染一段html内容是没有什么难度,使用dangerouslySetInnerHTML 便可。可是能够作到将内容中的英文单词翻译出来,是怎么实现的呢?一块儿来看一下吧。html
我前端是作内容展现,后台将Html格式的内容传递到前端,前端原生元素的dangerouslySetInnerHTML 属性去解析html内容,就可使用react框架渲染html了前端
仔细看,这个属性用的是{{ }}2个括号而不是1个括号。缘由是:第一{}表明jsx语法开始,第二个是表明dangerouslySetInnerHTML接收的是一个对象键值对。它接收的内容是html的,很容易收到XSS攻击,因此这个属性有了dangerous这个单词...node
后台传给个人一段一段的内容是这样的:react
既然要提取出来作单词翻译,就得有能力去获取每个单词,因此个人打算是,把内容提取出来,是一个英文单词就放进一个span标签中。可是这一步在哪里处理比较好呢,我想了想,在页面渲染以前处理吧, 这样页面渲染的压力要减少,提升渲染速度。因此我在前端接收到后端发送的数据以后,在存入store以前就先处理好。web
case "OBT_BOOK_CONTENT_SUCCESS": var newContents = action.meta.bookcontent.map((item, index) => { item.paragraphContent = item.paragraphContent.replace(/src="/g, `src="${url}`); //处理caseContent中的单词 var div = document.createElement('div'); div.innerHTML = item.paragraphContent; var caseContent = div.querySelector('.caseContent'); if (caseContent) { var arr = caseContent.innerText.split(" "); for (var i = 0; i < arr.length; i++) { arr[i] = "<span>" + arr[i] + "</span>" } caseContent.innerHTML = arr.join(""); item.paragraphContent = div.innerHTML; } return item; }) return Object.assign({}, state, { bookcontent: newContents })
因为传给个人是一大段内容,里面的元素的类型不仅一种、类名也不止一种,有div .caseTitle .caseContent strong等等,可是我只处理面积最大的一块英文,也就是只处理caseContent中的英文单词这就好办了。我没有用string的方法,去查找这个串在什么位置,怎么截取怎么拼接。没有。我利用了DOM的原理,借助DOM原生的api帮助我获得我要的英文单词。我建立了一个div(没有DOM我就本身建立DOM咯),而后DOM查找.caseContent ,用空格把其中的全部单词提取出来,再给每个单词用span包起来,而后把.caseContent中的内容替换掉,同时div的innerHTML也就变了,最后改变paragraphContent。就这样把后端传过来的东西作了修改,再使用。后端
if(e.target.nodeName === 'SPAN'){ var s = ""; if(e.target.innerText) { var len = e.target.innerText.length; if( !/^[\u4e00-\u9fa5]{0,}$/.test(e.target.innerText) ){ if(e.target.innerText[len -1 ] === ',' || e.target.innerText[len -1 ] === '.' ){ s = e.target.innerText.substring(0, len -1 ) }else { s = e.target.innerText; } var chooseSpan = e.target; this.props.checkWords(s, chooseSpan); } } console.log( s); }
利用正则!/^[\u4e00-\u9fa5]{0,}$/
提取出来英文单词,可是有些单词末尾会带着英文状态下的逗号,句号.,因此还须要用substring
剪切一下单词,再调用方法。api
这里,提取页面中点击的内容,须要CSS的配合。app
user-select: text;
user-selct: text;可让页面中的内容被选中。而 user-select: none是让页面中的内容不被选中。框架
-ms-user-select: none; -webkit-user-select: none; user-select: none;
获取了单词s以后,还须要作一点交互,就是被选中的单词高亮起来,全部,span元素也须要被处理,为了严谨,因此须要再判断是否是单词,是的话,再对span 作处理。this
checkWords(txt, selectedSpan) { // 查单词 this.selectedSpan = selectedSpan; if (txt.toString().length > 1) { if (/^\w+$/.test(txt)) { this.props.getWord(txt); this.setState({ showWord: true }) selectedSpan.style.color="#fff"; selectedSpan.style.backgroundColor="rgb(0,153,223)"; } } }
getWord方法中调用了查单词的api,我用的是有道智云的api,须要本身注册一个帐号,而后申请一个应用。获取appKey和appSecret,设置好from 和 to 的值,也就是你要从什么语言转什么语言,准备一个随机数sale, 而后各类生成签名。。
var appSecret = 'GOPjZoiSnH592P31Qn6xoallHn3zUnSh'; var appKey = '06fc15a9c06cb290'; var salt = '' + (new Date).getTime(); // 多个query能够用\n链接 如 query='apple\norange\nbanana\npear' var from = 'en'; var to = 'zh-CHS'; var str1 = appKey + q + salt + appSecret; var data = null; var sign = md5(str1); var sendRes = res; sign = sign.toUpperCase(); q = encodeURI(q); var url = `http://openapi.youdao.com/api?q=${q}&from=${from}&to=${to}&appKey=${appKey}&salt=${salt}&sign=${sign}`
有了这个url以后,就能够请求了。返回的东西是:
播放单词的地方就是用 H5的audio 元素,src是 http://dict.youdao.com/dictvoice?audio=${this.props.word.query}
<audio id="audio" > <source src={voiceUrl} type="audio/mp3"></source> </audio>
后来发现扇贝的单词api作的也不错,没有有道用的这么麻烦,有道还须要签名,用户量大的时候也会有限制,准备之后换扇贝的。
至此,使用react框架完成移动页面的定向单词翻译已完成。其中配合了CSS,DOM,正则,使用别家api等知识,算是一次小小的综合考核吧,不知道有没有其余同窗也作过这样的事情,若是有的话,能够交流一下啊。