离线场景下任意文档的在线预览及原样格式翻译,不依赖其他厂商接口非侵入式一行js代码实现网站的翻译及国际化,可配置使用多种翻译语言

离线场景下任意文档的在线预览及原样格式翻译,不依赖其他厂商接口非侵入式一行js代码实现网站的翻译及国际化,可配置使用多种翻译语言。

在这里插入图片描述

要实现翻译需要解决以下3个主要问题:
1)from:内容本身的语言类型是什么?
2)to:需要翻译为目标语言是什么?
3)text:需要翻译的文本内容是什么?

转化为:

1)首先,如何识别文档内容的语言?一篇文章中有多种语言混合的如何识别?
2)其次,用户使用的是什么语言?如何获取目标语言?
3)在文档或者网页中,所有内容都是带有格式的,如何翻译之后进行还原保证样式不丢失?

在这里插入图片描述


在网上查了很多资料,也下载了很多 收费 的资料,结果不尽人意。

获取用户的语言:

1)通过浏览器的默认语言判断用户使用的语言:

<script>// 获取浏览器默认语言const getBrowserLang = function () {let browserLang = navigator.language ? navigator.language : navigator.browserLanguage;let defaultBrowserLang = "";if (browserLang.toLowerCase() === "us" ||browserLang.toLowerCase() === "en" ||browserLang.toLowerCase() === "en_us") {defaultBrowserLang = "en_US";} else {defaultBrowserLang = "zh_CN";}return defaultBrowserLang;};console.log(getBrowserLang());</script>

或者:

<script>var type = navigator.appName; //BOM对象获取浏览器名称if (type == "Netscape") {var lang = navigator.language.toLowerCase(); //获取浏览器配置语言,支持非IE浏览器} else {var lang = navigator.browserLanguage.toLowerCase(); //获取浏览器配置语言,支持IE5+}console.log(lang);var lang = lang.substr(0, 5); //获取浏览器配置语言前4位console.log(lang);</script>

如何通过js在html中动态导入其他的js库:

<script>var head = document.getElementsByTagName("head")[0];var script = document.createElement("script");script.type = "text/javascript";script.src = "http://localhost:8060/static/translate.min.js";script.onload = script.onreadystatechange = function () {translate.storage.set("to", "");//设置使用v2.x 版本translate.setUseVersion2();//SELECT 修改 onchange 事件translate.selectLanguageTag.selectOnChange = function (event) {//判断是否是第一次翻译,如果是,那就不用刷新页面了。 true则是需要刷新,不是第一次翻译var isReload = translate.to != null && translate.to.length > 0;if (isReload) {//如果要刷新页面的话,弹出友好提示alert("您好,快速体验暂时只能切换其中一种语言进行体验,只是提供效果展示,您可参考接入文档来接入您的项目中进行完整体验及使用。",);} else {var language = event.target.value;console.log(language);// translate.changeLanguage(language);}};};</script>

如何获取文档或者网页的需要翻译的内容?找了一个网页翻译助手实现的js插件代码进行参考,完整代码如下:

// ==UserScript==
// @name         网页翻译助手
// @version      1.3.3
// @namespace    https://github.com/zyufstudio/TM/tree/master/webTranslate
// @description  支持划词翻译,输入文本翻译,谷歌整页翻译。可以自行选择谷歌翻译,有道字典翻译和百度翻译。
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAENklEQVRoQ+2ZTVITQRTH/28qyNIJFxCqnGwNJzCcwHACcelkIZxAPAG4IFkaTyCegHgC4jZjVfACzLBEUvOs7jCx57unZ6JSRZZJ9+v3e+/1++gQHviHHrj+eAT41x4s9YA99F5qK3nb+h4c7QTa6xtYmAuwNfLeg3Fc5QxmBGy1doO3O1dV9tVZmwmwdeYdg/DeTDB/vnY7B2Z7q+/KBhh6XF3UcgeDr3y3s2O6v+q+FIB9NutaRJdVBanrQ+bdYNCZ1pGhuzcNMPJ6FuNCV0DWuhA4ClzntI4M3b1rARBhRERjXSWK1oUhfy3y5loAmlBclcHAue86+1lyHwTAfXb4cD1wUmm9EgAzfhLoPLT4fGUNRpeAPgH6Bc/ARcw89Qed3eRWLQAGbhg4LrqY9sjrUYgxEZ7FDmH6GAPWUZ7JJvBh0ijXrpPStxRAKs/c00mLAiKewcyLmn0yt63Nha/yGgGEoP3Afb4KGSEYT+5eWxbZQniUJUT9INAFEeT3RXGr4wSxpj30JqoXKgMw8M13nV50oH02OyDQSUxJWX55zKB+8vu8uP1rAKr17dF8m8LFZUr5Em1Cau2ozZ09/NEn8Dum1puypq+2B1SXbQ1nY4Be61rvTxjxOPy1cRS12e2z2SURdcHITIuq/FoA4vL6rrOK56QwBn/n241eXv/fHs6mBHpRFViEHVsb+8I79QAYgT9w2pECSWFlFlxZuiqBSAz3YVcLQJxbFEJyeGEcwMJyAmO+UVPtltKSJzOZyiTuhAX+woyv/sDpNxZCMkUqKVReYl5MCXiaZdSQ+U0w6MgGLt2S59eD9tC7IKCn7s/zukkanfiusxdLo0SnaYi4gnkTXXLYiQqfLJa3re3kfaodQkkvSOuKQra5OLB4WbBCC5PgrTNZQZ7MbXqymKdqAnAjwZXsU5aRGgGQsQ7e02olpPJ3FzJNJj4ixonwSkIz71qgvpi7RYPoD5ztrLBsBCASHDIfBoPOx7yksmwl8ClLeXnHgW/ENAXxO2GUyENF42ejAEsl+Eq204DSTnOXiHqipS7LmOFtq02bi/OovykbPRsHKFNQ4/dTkXoj68ui9WtjL78Y1mzmNBQyWiKqOETPT3hWBPE/egBRwRLZjDbvJqLdyIP4LwFCwl6UdssgzAAaeNgqjKtEFxqDAGKF0whAHK72MUZBXrApOSRFxXGZnfhKfVc1B6j1uFuGrD8nGwNIL6wBIq/nyUOuBbDqbUbeaiYus230uxWil/U8X9RWZ7cSszmBVm2GVjeqq2TZuqwRtAqAeECwiD6p5/xVgGhQSTd1PAVRyd9QvK1a/r6Xio24kdzS/8jKLF30e3voBXkDUFW5WRObkLFWAOOXjASdvPzU6mY9w6wVYFmk/nSfla0O3IAxYat1mPeGtFaAqgqbrH8EMLFak3sePdCkNU1k/QadtchPhjx3/AAAAABJRU5ErkJggg==
// @author       Johnny Li
// @license      MIT
// @match        *://*/*
// @grant        GM_info
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @connect      cdn.jsdelivr.net
// @connect      cdn.bootcss.com
// @connect      translate.google.com.hk
// @connect      fanyi.youdao.com
// @connect      dict.youdao.com
// @connect      fanyi.baidu.com
// @connect      shared.ydstatic.com
// @require      https://cdn.jsdelivr.net/npm/jquery@2.2.3/dist/jquery.min.js
// @require      https://cdn.jsdelivr.net/npm/jquery.md5@1.0.2/index.min.js
// @require      https://cdn.jsdelivr.net/gh/zyufstudio/jQuery@3a09ff54b33fc2ae489b5083174698b3fa83f4a7/jPopBox/dist/jPopBox.min.js
// ==/UserScript==//文件使用Rollup+Gulp编译而成,如需查看源码请转到GitHub项目。(function () {'use strict';/*** 字符串模板格式化* @param {string} formatStr - 字符串模板* @returns {string} 格式化后的字符串* @example* StringFormat("ab{0}c{1}ed",1,"q")  output "ab1cqed"*/function StringFormat(formatStr) {var args = arguments;return formatStr.replace(/\{(\d+)\}/g, function (m, i) {i = parseInt(i);return args[i + 1];});}/*** 日期格式化* @param {Date} date - 日期* @param {string} formatStr - 格式化模板* @returns {string} 格式化日期后的字符串* @example* DateFormat(new Date(),"yyyy-MM-dd")  output "2020-03-23"* @example* DateFormat(new Date(),"yyyy/MM/dd hh:mm:ss")  output "2020/03/23 10:30:05"*/function DateFormat(date, formatStr) {var o = {"M+": date.getMonth() + 1, //月份"d+": date.getDate(), //日"h+": date.getHours(), //小时"m+": date.getMinutes(), //分"s+": date.getSeconds(), //秒"q+": Math.floor((date.getMonth() + 3) / 3), //季度"S": date.getMilliseconds() //毫秒};if (/(y+)/.test(formatStr)) {formatStr = formatStr.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));}for (var k in o) {if (new RegExp("(" + k + ")").test(formatStr)) {formatStr = formatStr.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));}}return formatStr;}/*** 生成Guid* @param {boolean} hasLine - guid字符串是否包含短横线* @returns {string} guid* @example * Guid(false)  output "b72f78a6cb88362c0784cb82afae450b"* @example* Guid(true) output "67b25d43-4cfa-3edb-40d7-89961ce7f388"*/function Guid(hasLine){var guid="";function S4() {return (((1+Math.random())*0x10000)|0).toString(16).substring(1);}if(hasLine){guid=(S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());}else {guid=(S4()+S4()+S4()+S4()+S4()+S4()+S4()+S4());}return guid;}/*** 清除dom元素默认事件* @param {object} e - dom元素*/function ClearBubble(e) {if (e.stopPropagation) {e.stopPropagation();} else {e.cancelBubble = true;}if (e.preventDefault) {e.preventDefault();} else {e.returnValue = false;}}function ObjectToQueryString(object){var querystring=Object.keys(object).map(function(key) { return encodeURIComponent(key) + '=' + encodeURIComponent(object[key]) }).join('&');return querystring;}/*** 配置参数*/var options={//默认翻译引擎defaulttransengine:"yd"};/*** 获取配置参数*/function GetSettingOptions(){var optionsJson=GM_getValue("webtranslate-options")||"";if(optionsJson!=""){var optionsData=JSON.parse(optionsJson);for (var key in options) {if (options.hasOwnProperty(key) && optionsData.hasOwnProperty(key)) {options[key]= optionsData[key];   }}}return options;}/*** 设置配置参数*/function SetSettingOptions(){var optionsJson=JSON.stringify(options);GM_setValue("webtranslate-options", optionsJson);}//谷歌翻译var googleTrans = {code: "ge",codeText: "谷歌",defaultOrigLang: "auto", //默认源语言defaultTargetLang: "zh-CN", //默认目标语言langList: {"auto": "自动检测","zh-CN": "中文简体","zh-TW": "中文繁体","en": "英文","ja": "日文","ko": "韩文","fr": "法文","es": "西班牙文","pt": "葡萄牙文","it": "意大利文","ru": "俄文","vi": "越南文","de": "德文","ar": "阿拉伯文","id": "印尼文"},Execute: function (h_onloadfn) {GM_xmlhttpRequest({method: "POST",url: "https://translate.google.com.hk/_/TranslateWebserverUi/data/batchexecute",headers: {"Referer": `https://translate.google.com.hk/`,"Cache-Control": "max-age=0","Content-Type": "application/x-www-form-urlencoded;charset=utf-8",},data: "f.req=" + encodeURIComponent(JSON.stringify([[["MkEWBc", JSON.stringify([[Trans.transText, Trans.transOrigLang, Trans.transTargetLang, true],[null]]), null, "generic"]]])),onload: function (r) {setTimeout(function () {var resData=r.responseText;var transData=JSON.parse(JSON.parse(resData.match(/\[{2}.*\]{2}/g)[0])[0][2]);var transList=transData[1][0][0][5];var transTexts=[];for (let index = 0; index < transList.length; index++) {var transItem = transList[index];transTexts.push(transItem[0]);}Trans.transResult.trans = transTexts;Trans.transResult.orig = transData[1][4][0].split("\n");Trans.transResult.origLang = transData[2];h_onloadfn();}, 300);},onerror: function (e) {console.error(e);}});},};//获取signfunction getSign() {GM_xmlhttpRequest({method: "GET",url: "http://fanyi.youdao.com/",timeout: 5000,onload: function (ydRes) {var fanyijsUrlMatch = /<script\s+type="text\/javascript"\s+src="([http|https]*?:\/\/shared.ydstatic.com\/fanyi\/newweb\/v[\d.]+\/scripts\/newweb\/fanyi.min.js)"><\/script>/g.exec(ydRes.responseText);if (!fanyijsUrlMatch) {console.log("获取fanyi.min.js失败!!!");} else {var fanyijsUrl = fanyijsUrlMatch[1];if (typeof fanyijsUrl !== 'undefined') {GM_xmlhttpRequest({method: "GET",url: fanyijsUrl,timeout: 5000,onload: function (r) {var signMatch = /sign:[a-z]{1}\.md5\("fanyideskweb"\+[a-z]{1}\+[a-z]{1}\+"(.*)"\)}};/g.exec(r.responseText);if (!signMatch) {console.log("获取sign失败!!!");} else {var newSign = signMatch[1];if (typeof newSign !== 'undefined') {youdaoTrans.sign = newSign;}}},onerror: function (e) {console.error(e);}});}}},onerror: function (e) {console.error(e);}});}/*** 获取有道翻译音标* @param {String} transText * @param {Function} callback */function getYDSymbol(transText, callback) {var url = StringFormat("http://dict.youdao.com/fsearch?client=fanyideskweb&keyfrom=fanyi.web&q={0}&doctype=xml&xmlVersion=3.2&dogVersion=1.0&appVer=3.1.17.4208", encodeURIComponent(transText));GM_xmlhttpRequest({method: "GET",url: url,timeout: 5000,onload: function (ydRes) {var xmlnode=ydRes.responseXML;var symbol = {uk:"",us: ""};var root = xmlnode.getElementsByTagName("yodaodict")[0];if ("" + root.getElementsByTagName("uk-phonetic-symbol")[0] != "undefined" && "" + root.getElementsByTagName("uk-phonetic-symbol")[0].childNodes[0] != "undefined") {symbol.uk = root.getElementsByTagName("uk-phonetic-symbol")[0].childNodes[0].nodeValue;}if ("" + root.getElementsByTagName("us-phonetic-symbol")[0] != "undefined" && "" + root.getElementsByTagName("us-phonetic-symbol")[0].childNodes[0] != "undefined") {symbol.us = root.getElementsByTagName("us-phonetic-symbol")[0].childNodes[0].nodeValue;}callback(symbol);},onerror: function (e) {console.error(e);}});}//有道翻译var youdaoTrans = {code: "yd",codeText: "有道",sign: "",defaultOrigLang: "AUTO", //默认源语言defaultTargetLang: "ZH-CHS", //默认目标语言langList: {"AUTO": "自动检测","zh-CHS": "中文","en": "英文","ja": "日文","ko": "韩文","fr": "法文","es": "西班牙文","pt": "葡萄牙文","it": "意大利文","ru": "俄文","vi": "越南文","de": "德文","ar": "阿拉伯文","id": "印尼文"},Execute: function (h_onloadfn) {var h_url = "",h_headers = {},h_data = "";var youdaoTransApi = "http://fanyi.youdao.com/translate_o?client=fanyideskweb&keyfrom=fanyi.web&smartresult=dict&version=2.1&doctype=json";var userAgent=$.md5(navigator.userAgent);var currentTs="" + (new Date).getTime();var salt=currentTs + parseInt(10 * Math.random(), 10);var sign = this.sign != "" ? this.sign : "]BjuETDhU)zqSxf-=B#7m";var signStr = $.md5("fanyideskweb" + Trans.transText + salt + sign);h_url = youdaoTransApi;h_headers = {"Content-Type": "application/x-www-form-urlencoded","Referer": "http://fanyi.youdao.com/"};h_data = StringFormat("from={0}&to={1}&salt={2}&sign={3}&i={4}&lts={5}&bv={6}", Trans.transOrigLang, Trans.transTargetLang, salt, signStr, encodeURIComponent(Trans.transText),currentTs,userAgent);GM_xmlhttpRequest({method: "POST",url: h_url,headers: h_headers,data: h_data,onload: function (r) {setTimeout(function () {var data = JSON.parse(r.responseText);var trans = [],origs = [],src = "";if (data.errorCode == 0) {for (var j = 0; j < data.translateResult.length; j++) {var ydTransCont = data.translateResult[j];var ydtgt = "";var ydsrc = "";for (var k = 0; k < ydTransCont.length; k++) {var ydcont = ydTransCont[k];ydtgt += ydcont.tgt;ydsrc += ydcont.src;}trans.push(ydtgt);origs.push(ydsrc);}src = data.type;Trans.transResult.trans = trans;Trans.transResult.orig = origs;Trans.transResult.origLang = src.split("2")[0];var smartResult = data.smartResult;if (smartResult && smartResult.entries.length > 0) {getYDSymbol(Trans.transText, function (symbol) {Trans.transResult.symbols.en = symbol.uk;Trans.transResult.symbols.am = symbol.us;h_onloadfn();});}else {h_onloadfn();}}}, 300);},onerror: function (e) {console.error(e);}});},init: function () {getSign();}};function a(r) {if (Array.isArray(r)) {for (var o = 0, t = Array(r.length); o < r.length; o++)t[o] = r[o];return t}return Array.from(r)}function n(r, o) {for (var t = 0; t < o.length - 2; t += 3) {var a = o.charAt(t + 2);a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a),a = "+" === o.charAt(t + 1) ? r >>> a : r << a,r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a;}return r}function e(r,gtk) {var i = null;var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);if (null === o) {var t = r.length;t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr(-10, 10));} else {for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C = 0, h = e.length, f = []; h > C; C++)"" !== e[C] && f.push.apply(f, a(e[C].split(""))),C !== h - 1 && f.push(o[C]);var g = f.length;g > 30 && (r = f.slice(0, 10).join("") + f.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice(-10).join(""));}var u = void 0;u = null !== i ? i : (i = gtk || "") || "";for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d[1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) {var A = r.charCodeAt(v);128 > A ? S[c++] = A : (2048 > A ? S[c++] = A >> 6 | 192 : (55296 === (64512 & A) && v + 1 < r.length && 56320 === (64512 & r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)),S[c++] = A >> 18 | 240,S[c++] = A >> 12 & 63 | 128) : S[c++] = A >> 12 | 224,S[c++] = A >> 6 & 63 | 128),S[c++] = 63 & A | 128);}for (var p = m, F = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(97) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(54)), D = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(51) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(98)) + ("" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(102)), b = 0; b < S.length; b++)p += S[b],p = n(p, F);return p = n(p, D),p ^= s,0 > p && (p = (2147483647 & p) + 2147483648),p %= 1e6,p.toString() + "." + (p ^ m)}/*** @param  {string} word* @param  {string} gtk* @return {string}*/var calcSign =function(word,gtk){return e(word,gtk);};//获取gtk和tokenfunction GetToken(){GM_xmlhttpRequest({method: "GET",url: "https://fanyi.baidu.com/",timeout:5000,onload: function (r) {var gtkMatch = /window\.gtk = '(.*?)'/.exec(r.responseText);var commonTokenMatch = /token: '(.*?)',/.exec(r.responseText);if (!gtkMatch) {console.log("获取gtk失败!!!");}if (!commonTokenMatch) {console.log("获取token失败!!!");}var newGtk = gtkMatch[1];var newCommonToken = commonTokenMatch[1];if (typeof newGtk !== 'undefined') {baiduTrans.gtk=newGtk;}if (typeof newCommonToken !== 'undefined') {baiduTrans.token=newCommonToken;}},onerror: function (e) {console.error(e);}});}//百度翻译var baiduTrans = {code:"bd",codeText:"百度",gtk:"",token:"",defaultOrigLang:"auto",         //默认源语言defaultTargetLang:"zh",         //默认目标语言langList: {"auto": "自动检测","zh": "中文","cht": "繁体中文","en": "英语","jp": "日语","kor": "韩语","fra": "法语","spa": "西班牙语","pt": "葡萄牙语","it": "意大利语","ru": "俄语","vie": "越南语","de": "德语","ara": "阿拉伯语"},Execute: function (h_onloadfn) {if(Trans.transOrigLang=="auto")this.AutoTrans(h_onloadfn);elsethis.ExecTrans(h_onloadfn);},AutoTrans:function(h_onloadfn){var self=this;var datas={query:Trans.transText};GM_xmlhttpRequest({method: "POST",headers:{"referer": 'https://fanyi.baidu.com',"Content-Type": 'application/x-www-form-urlencoded; charset=UTF-8',},url: "https://fanyi.baidu.com/langdetect",data: ObjectToQueryString(datas),onload: function (r) {var data = JSON.parse(r.responseText);if(data.error===0){Trans.transOrigLang=data.lan;self.ExecTrans(h_onloadfn);}},onerror: function (e) {console.error(e);}});},ExecTrans:function(h_onloadfn){var tempSign=calcSign(Trans.transText,this.gtk);var datas={from:Trans.transOrigLang,to:Trans.transTargetLang,query:Trans.transText,transtype:"translang",simple_means_flag:3,sign:tempSign,token:this.token};GM_xmlhttpRequest({method: "POST",headers:{"referer": 'https://fanyi.baidu.com',"Content-Type": 'application/x-www-form-urlencoded; charset=UTF-8',//"User-Agent": window.navigator.userAgent,},url: "https://fanyi.baidu.com/v2transapi",data: ObjectToQueryString(datas),onload: function (r) {setTimeout(function () {var result= JSON.parse(r.responseText);var trans_result=result.trans_result;var dict_result=result.dict_result || null;var transDatas = trans_result.data;var trans = [],origs = [],src = "";for (var i = 0; i < transDatas.length; i++) {var getransCont = transDatas[i];trans.push(getransCont.dst);origs.push(getransCont.src);}src = trans_result.from;Trans.transResult.trans = trans;Trans.transResult.orig = origs;Trans.transResult.origLang = src;if(dict_result){var symbols=dict_result.simple_means.symbols;Trans.transResult.symbols.en=symbols[0].ph_en || "";Trans.transResult.symbols.am=symbols[0].ph_am || "";}h_onloadfn();}, 300);},onerror: function (e) {console.error(e);}});},init:function(){GetToken();}};var Trans={transEngineList:{},         //翻译引擎实例列表transEngine:"",             //当前翻译引擎。ge(谷歌)/yd(有道)transEngineObj:{},          //当前翻译引擎实例transTargetLang:"",         //目标语言。transOrigLang:"",           //源语言transType:"word",           //翻译类型。word(划词翻译)/text(输入文本翻译)/page(整页翻译)transText:"",               //被翻译内容transResult:{               //当前翻译内容//译文trans:[],//原文orig:[],//原文语言origLang:"",//音标symbols:{//英标en:"",//美标am:"",}},Execute:function(h_onloadfn){resetTransResult(this);this.transEngineObj.Execute(h_onloadfn);},GetLangList:function(){var langList={};langList=this.transEngineObj.langList;return langList;},Update:function(){resetTransResult(this);this.transEngineObj=this.transEngineList[this.transEngine];this.transTargetLang=this.transEngineObj.defaultTargetLang;this.transOrigLang=this.transEngineObj.defaultOrigLang;},Clear:function(){this.transEngine="";                //当前翻译引擎。ge(谷歌)/yd(有道)this.transTargetLang="";            //目标语言。this.transOrigLang="";             //源语言this.transText="";                   //被翻译内容this.transResult.trans=[];this.transResult.orig=[];this.transResult.origLang="";},//注册翻译引擎接口并执行翻译引擎的初始化接口RegisterEngine:function(){/*** 翻译引擎必须提供以下接口code:"",                    //代号codeText:"",                //代号描述defaultOrigLang:"",         //默认源语言defaultTargetLang:"",       //默认目标语言langList: {},               //支持翻译语言列表Execute: function (h_onloadfn) {},     //执行翻译init:function(){},          //可选,初始化接口,在脚本创建时立即执行*/var transEngineListObj={};transEngineListObj[googleTrans.code]=googleTrans;transEngineListObj[youdaoTrans.code]=youdaoTrans;transEngineListObj[baiduTrans.code]=baiduTrans;this.transEngineList=transEngineListObj;for (var key in this.transEngineList) {if (this.transEngineList.hasOwnProperty(key) && this.transEngineList[key].hasOwnProperty("init")) {this.transEngineList[key].init();}}}};function resetTransResult(that){that.transResult.trans=[];that.transResult.orig=[];that.transResult.origLang="";that.transResult.symbols.en="";that.transResult.symbols.am="";}//面板var Panel={popBoxEl:{},randomCode:"",Create:function(title,placement,isShowArrow,content,shownFn){var self=this;$(self.popBoxEl).jPopBox({title: title,className: 'JPopBox-tip-white',placement: placement,trigger: 'none',isTipHover: true,isShowArrow: isShowArrow,content: function(){return StringFormat('<div id="panelBody{0}">{1}</div>',self.randomCode,content);}});$(self.popBoxEl).on("shown.jPopBox",function(){var $panel=$("div.JPopBox-tip-white");typeof shownFn === 'function' && shownFn($panel);});$(self.popBoxEl).jPopBox('show');},Update:function(Fn){var $panel=$("div.JPopBox-tip-white");Fn($panel);    },Destroy:function(){//$(this.popBoxEl).jPopBox("hideDelayed");$(this.popBoxEl).jPopBox("destroy");},CreateStyle:function(){var s="";s+=StringFormat("#panelBody{0}>div input,#panelBody{0}>div select{padding: 3px; margin: 0; background: #fff; font-size: 14px; border: 1px solid #a9a9a9; color:black;width: auto;min-height: auto; }",this.randomCode);s+=StringFormat("#panelBody{0}>div:first-child{padding-bottom: 5px;height:30px}",this.randomCode);s+=StringFormat("#panelBody{0}>div:last-child hr{border: 1px inset #eeeeee;background: none;height: 0px;margin: 0px;}",this.randomCode);return s;}};//文本翻译面板var TextTransPanel={Create:function(popBoxEl,randomCode){var self=this;var html=this.GetHtml();var transEngineOptionsHtml="";//翻译引擎for (var k in Trans.transEngineList) {if (Trans.transEngineList.hasOwnProperty(k)) {var v = Trans.transEngineList[k].codeText;var selectOption="";if(Trans.transEngine==k){selectOption='selected="selected"';}transEngineOptionsHtml+=StringFormat('<option value="{0}" {2}>{1}</option>',k,v,selectOption);}}var TextTransPanelHtml=StringFormat('<div style="padding-bottom: 5px;">'+'翻译引擎:<select>{2}</select>&nbsp;&nbsp;&nbsp;&nbsp;'+'翻译语言:<select>{4}</select> &#x21E8; '+'<select>{3}</select> '+'<button style="width:46px; height:26px; cursor: pointer;overflow: visible;color: inherit;margin: 0;padding: 1px 7px;background-color: #dddddd;border: 2px outset #dddddd;text-align: center;display: inline-block;font-size: 14px; font-weight: 400; ">翻译</button></div>'+'<div style="word-wrap:break-word">'+'<div style="padding-bottom: 5px;"><textarea placeholder="请输入你要翻译的文字" style="word-wrap: break-word;word-break: keep-all;overflow-y: auto;width:450px;height:85px;padding: 3px;line-height: 18px;font-size: 14px;font-family: arial,simsun;border: 1px solid #999;border-color: #999 #d8d8d8 #d8d8d8 #999;outline: 0;resize: none;">{5}</textarea></div><hr/>'+'<div style="padding-top: 5px;">{6}</div>'+'</div>',randomCode,"",transEngineOptionsHtml,html.targetLangListHtml,html.origLangListHtml,"","");Panel.popBoxEl=popBoxEl;Panel.randomCode=randomCode;Panel.Create("文本翻译","auto bottom",false,TextTransPanelHtml,function($panel){$panel.css({position: "fixed",top:"20px"});//翻译引擎$panel.find(StringFormat("#panelBody{0} div:eq(0) select:eq(0)",randomCode)).change(function(e){Trans.transEngine=$(this).find("option:selected").val();Trans.Update();Panel.Update(function($panel){var html=self.GetHtml();//翻译内容$panel.find(StringFormat("#panelBody{0} div:eq(1) div:eq(1)",randomCode)).html("");$panel.find(StringFormat("#panelBody{0} div:eq(0) select:eq(1)",randomCode)).html(html.origLangListHtml);$panel.find(StringFormat("#panelBody{0} div:eq(0) select:eq(2)",randomCode)).html(html.targetLangListHtml);});});//源语言$panel.find(StringFormat("#panelBody{0} div:eq(0) select:eq(1)",randomCode)).change(function(e){Trans.transOrigLang=$(this).find("option:selected").val();Panel.Update(function($panel){var html=self.GetHtml();$panel.find(StringFormat("#panelBody{0} div:eq(0) select:eq(2)",randomCode)).html(html.targetLangListHtml);});});//目标语言$panel.find(StringFormat("#panelBody{0} div:eq(0) select:eq(2)",randomCode)).change(function(e){Trans.transTargetLang=$(this).find("option:selected").val();});//翻译$panel.find(StringFormat("#panelBody{0} div:eq(0)  button:eq(0)",randomCode)).click(function(e){var refTransText=$.trim($panel.find(StringFormat("#panelBody{0} div:eq(1) div:eq(0) textarea:eq(0)",randomCode)).val());if(refTransText==""){alert("请输入翻译文字!");return;}Trans.transText=refTransText;Trans.Execute(function(){Panel.Update(function($panel){var html=self.GetHtml();//源语言$panel.find(StringFormat("#panelBody{0} div:eq(0) select:eq(1)",randomCode)).html(html.origLangListHtml);//翻译内容$panel.find(StringFormat("#panelBody{0} div:eq(1) div:eq(1)",randomCode)).html(html.transHtml);});});});});},GetHtml:function(){var origLangListHtml=[];var targetLangListHtml=[];var returnHtml={};var transHtml=[];var langList=Trans.GetLangList();var origLang=Trans.transResult.origLang;if(Trans.transResult.trans.length>0 && Trans.transResult.orig.length>0){transHtml.push('<span>');for (var i = 0; i < Trans.transResult.trans.length; i++) {var transtxt = Trans.transResult.trans[i];transHtml.push(transtxt);}transHtml.push("</span>");Trans.transOrigLang=origLang;}else {var txt="该翻译引擎不支持 "+langList[Trans.transOrigLang]+" 翻译成 "+langList[Trans.transTargetLang];transHtml.push(StringFormat("<span>{0}</span>",txt));}//源语言for (var origKey in langList) {if (langList.hasOwnProperty(origKey)) {var origVal = langList[origKey]; var origSelectOption="";if(Trans.transOrigLang.toUpperCase()==origKey.toUpperCase()){origSelectOption='selected="selected"';}origLangListHtml.push(StringFormat('<option value="{0}" {2}>{1}</option>',origKey,origVal,origSelectOption));}}//目标语言for (var targetKey in langList) {if (langList.hasOwnProperty(targetKey) && targetKey!=Trans.transOrigLang && targetKey.toUpperCase()!="AUTO") {var targetVal = langList[targetKey];var targetSelectOption="";targetLangListHtml.push(StringFormat('<option value="{0}" {2}>{1}</option>',targetKey,targetVal,targetSelectOption));}}returnHtml.origLangListHtml=origLangListHtml.join("");returnHtml.targetLangListHtml=targetLangListHtml.join("");returnHtml.transHtml=transHtml.join("");return returnHtml;}};//划词翻译面板var WordTransPanel = {Create: function (popBoxEl, randomCode) {var self = this;var html = this.GetTransContHtml();var transEngineOptionsHtml = "";for (var k in Trans.transEngineList) {if (Trans.transEngineList.hasOwnProperty(k)) {var v = Trans.transEngineList[k].codeText;var selectOption = "";if (Trans.transEngine == k) {selectOption = 'selected="selected"';}transEngineOptionsHtml += StringFormat('<option value="{0}" {2}>{1}</option>', k, v, selectOption);}}var wordTransPanelHtml = StringFormat('<div>翻译引擎:<select>{2}</select>    翻译语言:<input type="text" value="{4}" readonly style="width:80px"/> &#x21E8; <select>{3}</select></div>' +'<div style="word-wrap:break-word">{1}</div>', randomCode, html.transHtml, transEngineOptionsHtml, html.langListHtml, html.origLangName);Panel.popBoxEl = popBoxEl;Panel.randomCode = randomCode;Panel.Create("", "auto bottom", false, wordTransPanelHtml, function ($panel) {+//目标语言$panel.find(StringFormat("#panelBody{0} div:eq(0) select:eq(1)", randomCode)).change(function (e) {Trans.transTargetLang = $(this).find("option:selected").val();Trans.Execute(function () {self.Update(randomCode);});});//翻译引擎$panel.find(StringFormat("#panelBody{0} div:eq(0) select:eq(0)", randomCode)).change(function (e) {Trans.transEngine = $(this).find("option:selected").val();Trans.Update();Trans.Execute(function () {self.Update(randomCode);});});});},Update: function (randomCode) {var self = this;Panel.Update(function ($panel) {var html = self.GetTransContHtml();$panel.find(StringFormat("#panelBody{0} div:eq(0) input:eq(0)", randomCode)).val("").val(html.origLangName);$panel.find(StringFormat("#panelBody{0} div:eq(0) select:eq(1)", randomCode)).html("").html(html.langListHtml);$panel.find(StringFormat("#panelBody{0} div:eq(1)", randomCode)).html("").html(html.transHtml);});},GetTransContHtml: function () {var transObj = {};var langListHtml = [];var langList = Trans.GetLangList();var origLang = Trans.transResult.origLang;var transContHtml = "";if (Trans.transResult.trans.length > 0 && Trans.transResult.orig.length > 0) {//译文var transHtml = [];transHtml.push('<div style="padding-top: 5px;"><ul style="list-style: none;margin: 0;padding: 0;">');for (var i = 0; i < Trans.transResult.trans.length; i++) {var transtxt = Trans.transResult.trans[i];transHtml.push(StringFormat('<li style="list-style: none;"><span>{0}</span></li>', transtxt));}transHtml.push("</ul></div>");//原文var origHtml = [];//原文内容origHtml.push('<div style="padding-bottom: 5px;"><ul style="list-style: none;margin: 0;padding: 0;">');for (var j = 0; j < Trans.transResult.orig.length; j++) {var origtxt = Trans.transResult.orig[j];origHtml.push(StringFormat('<li style="list-style: none;"><span>{0}</span></li>', origtxt));}origHtml.push("</ul>");//原文音标if (Trans.transResult.symbols.en!="" || Trans.transResult.symbols.am!="") {origHtml.push('<div>');if(Trans.transResult.symbols.en!="")origHtml.push(StringFormat('<span style="padding-right: 10px;">英 [{0}]</span>',Trans.transResult.symbols.en));if(Trans.transResult.symbols.am!="")origHtml.push(StringFormat('<span>美 [{0}]</span>',Trans.transResult.symbols.am));origHtml.push('</div>');}origHtml.push("</div>");transContHtml = origHtml.join("") + "<hr/>" + transHtml.join("");Trans.transOrigLang = origLang;} else {var txt = "该翻译引擎不支持 " + langList[Trans.transOrigLang] + " 翻译成 " + langList[Trans.transTargetLang];transContHtml = StringFormat("<div><span>{0}</span></div>", txt);}for (var k in langList) {if (langList.hasOwnProperty(k) && k != Trans.transOrigLang && k.toUpperCase() != "AUTO") {var v = langList[k];var selectOption = "";if (Trans.transTargetLang == k) {selectOption = 'selected="selected"';}langListHtml.push(StringFormat('<option value="{0}" {2}>{1}</option>', k, v, selectOption));}}transObj.origLangName = langList[Trans.transOrigLang];transObj.transHtml = transContHtml;transObj.langListHtml = langListHtml.join("");return transObj;}};//设置面板var SettingPanel={config:[{title:"",item:[{code:"",text:""}]}],Create:function(popBoxEl,randomCode){var self=this;var settingHtml=[];this.InitConfig();settingHtml.push('<div style="padding-left: 15px;display: inline-block;">');/*settingHtml.push('<div style="padding-bottom: 30px; max-width: 600px;">');settingHtml.push('<div style="font-size: 14px; padding-bottom: 3px;">默认翻译引擎:</div>');settingHtml.push(StringFormat('<div style="padding-bottom: 3px; margin-left: 10px;"><label style="font-size: 14px; cursor: pointer;"><input type="radio" name="transEngine{0}" style="cursor: pointer;" value="yd">有道</label></div>',randomCode));settingHtml.push(StringFormat('<div style="padding-bottom: 0px; margin-left: 10px;"><label style="font-size: 14px; cursor: pointer;"><input type="radio" name="transEngine{0}" style="cursor: pointer;" value="ge">谷歌</label></div>',randomCode));settingHtml.push('</div>');*/for (var index = 0; index < this.config.length; index++) {var configItem = this.config[index];settingHtml.push('<div style="padding-bottom: 30px; max-width: 600px;">');settingHtml.push(StringFormat('<div style="font-size: 14px; padding-bottom: 3px;">{0}</div>',configItem.title));for (var itemIndex = 0; itemIndex < configItem.item.length; itemIndex++) {var itemObj = configItem.item[itemIndex];settingHtml.push(StringFormat('<div style="padding-bottom: 0px; margin-left: 10px;"><label style="font-size: 14px; cursor: pointer;"><input type="radio" name="transEngine{0}" style="cursor: pointer;" value="{1}">{2}</label></div>',randomCode,itemObj.code,itemObj.text));}   settingHtml.push('</div>');}settingHtml.push('<div>');settingHtml.push(StringFormat('<button id="saveBtn{0}">保存</button>',randomCode));settingHtml.push(StringFormat('<span id="saveStatus{0}" style="display:none;margin-left:10px;background-color: #fff1a8;padding: 3px;">设置已保存。</span>',randomCode));settingHtml.push('</div>');settingHtml.push('</div>');var settingHtmlStr=settingHtml.join("");Panel.popBoxEl=popBoxEl;Panel.randomCode=randomCode;Panel.Create("网页翻译助手设置","auto bottom",false,settingHtmlStr,function($panel){$panel.css({position: "fixed",top:"20px"});self.Update(randomCode);//保存设置$panel.find(StringFormat("#panelBody{0} #saveBtn{0}",randomCode)).click(function(e){var defaultTransEngine=$panel.find(StringFormat("#panelBody{0} input[name='transEngine{0}']:checked",randomCode)).val();options.defaulttransengine=defaultTransEngine;SetSettingOptions();$panel.find(StringFormat("#panelBody{0} #saveStatus{0}",randomCode)).fadeIn(function(){setTimeout(function(){$panel.find(StringFormat("#panelBody{0} #saveStatus{0}",randomCode)).fadeOut();},1500);});});});},Update:function(randomCode){GetSettingOptions();Panel.Update(function($panel){$panel.find(StringFormat("#panelBody{0} input[name='transEngine{0}'][value='{1}']",randomCode,options.defaulttransengine)).prop("checked",true);});},InitConfig:function(){this.config=[];var configObj={title:"",item:[{code:"",text:""}]};configObj.title="默认翻译引擎:";configObj.item=[];for (var k in Trans.transEngineList) {if (Trans.transEngineList.hasOwnProperty(k)) {var v = Trans.transEngineList[k].codeText;configObj.item.push({code:k,text:v});}}this.config.push(configObj);}};//主程序var WebTranslate=function(){var transIconBase64="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAENklEQVRoQ+2ZTVITQRTH/28qyNIJFxCqnGwNJzCcwHACcelkIZxAPAG4IFkaTyCegHgC4jZjVfACzLBEUvOs7jCx57unZ6JSRZZJ9+v3e+/1++gQHviHHrj+eAT41x4s9YA99F5qK3nb+h4c7QTa6xtYmAuwNfLeg3Fc5QxmBGy1doO3O1dV9tVZmwmwdeYdg/DeTDB/vnY7B2Z7q+/KBhh6XF3UcgeDr3y3s2O6v+q+FIB9NutaRJdVBanrQ+bdYNCZ1pGhuzcNMPJ6FuNCV0DWuhA4ClzntI4M3b1rARBhRERjXSWK1oUhfy3y5loAmlBclcHAue86+1lyHwTAfXb4cD1wUmm9EgAzfhLoPLT4fGUNRpeAPgH6Bc/ARcw89Qed3eRWLQAGbhg4LrqY9sjrUYgxEZ7FDmH6GAPWUZ7JJvBh0ijXrpPStxRAKs/c00mLAiKewcyLmn0yt63Nha/yGgGEoP3Afb4KGSEYT+5eWxbZQniUJUT9INAFEeT3RXGr4wSxpj30JqoXKgMw8M13nV50oH02OyDQSUxJWX55zKB+8vu8uP1rAKr17dF8m8LFZUr5Em1Cau2ozZ09/NEn8Dum1puypq+2B1SXbQ1nY4Be61rvTxjxOPy1cRS12e2z2SURdcHITIuq/FoA4vL6rrOK56QwBn/n241eXv/fHs6mBHpRFViEHVsb+8I79QAYgT9w2pECSWFlFlxZuiqBSAz3YVcLQJxbFEJyeGEcwMJyAmO+UVPtltKSJzOZyiTuhAX+woyv/sDpNxZCMkUqKVReYl5MCXiaZdSQ+U0w6MgGLt2S59eD9tC7IKCn7s/zukkanfiusxdLo0SnaYi4gnkTXXLYiQqfLJa3re3kfaodQkkvSOuKQra5OLB4WbBCC5PgrTNZQZ7MbXqymKdqAnAjwZXsU5aRGgGQsQ7e02olpPJ3FzJNJj4ixonwSkIz71qgvpi7RYPoD5ztrLBsBCASHDIfBoPOx7yksmwl8ClLeXnHgW/ENAXxO2GUyENF42ejAEsl+Eq204DSTnOXiHqipS7LmOFtq02bi/OovykbPRsHKFNQ4/dTkXoj68ui9WtjL78Y1mzmNBQyWiKqOETPT3hWBPE/egBRwRLZjDbvJqLdyIP4LwFCwl6UdssgzAAaeNgqjKtEFxqDAGKF0whAHK72MUZBXrApOSRFxXGZnfhKfVc1B6j1uFuGrD8nGwNIL6wBIq/nyUOuBbDqbUbeaiYus230uxWil/U8X9RWZ7cSszmBVm2GVjeqq2TZuqwRtAqAeECwiD6p5/xVgGhQSTd1PAVRyd9QvK1a/r6Xio24kdzS/8jKLF30e3voBXkDUFW5WRObkLFWAOOXjASdvPzU6mY9w6wVYFmk/nSfla0O3IAxYat1mPeGtFaAqgqbrH8EMLFak3sePdCkNU1k/QadtchPhjx3/AAAAABJRU5ErkJggg==";var $doc=$(document);var $body=$("html body");var $head=$("html head");var randomCode="yyMM000000";    //属性随机码,年月加六位随机码。用于元素属性后缀,以防止属性名称重复。var createHtml=function(){var wordTransIconHtml=StringFormat('<div id="wordTrans{0}" class="wordTrans{0}"><div class="wordTransIcon{0}"></div></div>',randomCode,transIconBase64);$body.append(StringFormat('<div id="webTrans{0}">',randomCode)+wordTransIconHtml+'</div>');};var createStyle=function(){//尽可能避开csp认证GM_xmlhttpRequest({method:"get",url:"https://cdn.jsdelivr.net/gh/zyufstudio/jQuery@master/jPopBox/dist/jPopBox.min.css",onload:function(r){GM_addStyle(r.responseText+".JPopBox-tip-white{width: 482px;max-width: 550px;min-width: 450px;}");}});var s="";s+=StringFormat(".wordTrans{0}{background-color: rgb(245, 245, 245);box-sizing: content-box;cursor: pointer;z-index: 2147483647;border-width: 1px;border-style: solid;border-color: rgb(220, 220, 220);border-image: initial;border-radius: 5px;padding: 0.5px;position: absolute;display: none}",randomCode);s+=StringFormat(".wordTransIcon{0}{background-image: url({1});background-size: 25px;height: 25px;width: 25px;}",randomCode,transIconBase64);s+=Panel.CreateStyle();GM_addStyle(s);};var ShowWordTransIcon=function(){var $wordTransIcon=$("div#wordTrans"+randomCode);var isSelect=false;var isPanel=false;var isWordTransIcon=false;$doc.on({"selectionchange":function(e){isSelect=true;},"mousedown":function(e){var $targetEl=$(e.target);isPanel=$targetEl.parents().is("div.JPopBox-tip-white");isWordTransIcon=$targetEl.parents().is(StringFormat("div#wordTrans{0}",randomCode));//点击翻译图标外域和翻译面板外域时,隐藏图标和翻译面板if(!isWordTransIcon && !isPanel){$wordTransIcon.hide();Trans.Clear();Panel.Destroy();}else {//点击翻译图标,取消鼠标默认事件,防止选中的文本消失if(isWordTransIcon){ClearBubble(e);}}},"mouseup":function(e){var selectText = window.getSelection().toString().trim();if(!isPanel&&isSelect&&selectText){$wordTransIcon.show().css({left: e.pageX + 'px',top : e.pageY + 12 + 'px'});isSelect=false;}}});$wordTransIcon.click(function(e){Trans.Clear();Panel.Destroy();var selecter=window.getSelection();var selectText = selecter.toString().trim();GetSettingOptions();Trans.transText=selectText;Trans.transType="word";Trans.transEngine=options.defaulttransengine;//defaultTransEngine;Trans.Update();Trans.Execute(function(){WordTransPanel.Create($wordTransIcon,randomCode);$wordTransIcon.hide();});});};var guid="";var RegMenu=function(){GM_registerMenuCommand("文本翻译",function(){var $body=$("html body");$("div#wordTrans"+randomCode).hide();Trans.Clear();Panel.Destroy();GetSettingOptions();Trans.transEngine=options.defaulttransengine;//defaultTransEngine;Trans.Update();TextTransPanel.Create($body,randomCode);});GM_registerMenuCommand("Google整页翻译",function(){if(guid=="") guid=Guid();var cbscript=StringFormat('!function(){!function(){function e(){window.setTimeout(function(){window[t].showBanner(!0)},10)}function n(){return new google.translate.TranslateElement({autoDisplay:!1,floatPosition:0,multilanguagePage:!0,includedLanguages:"zh-CN,zh-TW,en",pageLanguage:"auto"})}var t=(document.documentElement.lang,"TE_{0}"),o="TECB_{0}";if(window[t])e();else if(!window.google||!google.translate||!google.translate.TranslateElement){window[o]||(window[o]=function(){window[t]=n(),e()});var a=document.createElement("script");a.src="https://translate.google.com.hk/translate_a/element.js?cb="+encodeURIComponent(o)+"&client=tee",document.getElementsByTagName("head")[0].appendChild(a)}}()}();',guid);$head.append(StringFormat('<script>{0}</script>',cbscript));});GM_registerMenuCommand("设置",function(){$("div#wordTrans"+randomCode).hide();Trans.Clear();Panel.Destroy();SettingPanel.Create($body,randomCode);});};this.init=function(){randomCode=DateFormat(new Date(),"yyMM").toString()+(Math.floor(Math.random() * (999999 - 100000 + 1) ) + 100000).toString();Trans.RegisterEngine();createStyle();createHtml();ShowWordTransIcon();RegMenu();};};var webTrans=new WebTranslate();webTrans.init();})();

如何判断文本内容的语言语种?

遍历所有字符,统计频率最高的语种为文档或者网页的语种,核心代码如下:

function isChinese(temp) 
{ var re = /[^\u4e00-\u9fa5]/; if(re.test(temp)) return false; return true; 
}function isJapanese(temp) 
{ var re = /[^\u0800-\u4e00]/; if(re.test(temp)) return false; return true; 
}function isKoera(chr) {if(((chr > 0x3130 && chr < 0x318F) || (chr >= 0xAC00 && chr <= 0xD7A3))) {return true;}return false;
}function isContainKoera(temp)
{var cnt = 0;for(var i=0;i < temp.length ; i++){if(isKoera(temp.charAt(i)))cnt++;}if (cnt > 0) return true;return false;
}function isContainChinese(temp)
{var cnt = 0;for(var i=0;i < temp.length ; i++){if(isChinese(temp.charAt(i)))cnt++;}if (cnt > 5) return true;return false;
}function isContainChinese2(temp)
{var cnt = 0;for(var i=0;i < temp.length ; i++){if(isChinese(temp.charAt(i)))cnt++;}if (cnt > 0 && temp.length<=3) return true;return false;
}function isContainJapanese(temp)
{var cnt = 0;for(var i=0;i < temp.length ; i++){if(isJapanese(temp.charAt(i)))cnt++;}if (cnt > 2) return true;return false;
}

当然也可以 截取 一段文本内容发送给 语言 模型 进行识别,但是对于混合文档还是不准确,还不如放在前端做节省计算资源。

看下谷歌翻译之前的实现方式:

<script type="text/javascript" src="http://www.google.com/jsapi"></script ><script type="text/javascript">google.load("language", "1");function initialize(){var text = document.getElementById("text").innerHTML;google.language.detect(text, function(result){if(!result.error && result.language){google.language.translate(text, result.language, "en", function(result){var translated = document.getElementById("translation");if(result.translation){translated.innerHTML = result.translation;}});}});}google.setOnLoadCallback(initialize);</script> 

或者:

<script src="https://translate.google.cn/translate_a/element.js?cb=googleTranslateElementInit"></script>

还有网友改进后的一种方式:

<script src="./el_main.js"></script>
<script src="./el_main.css"></script>
<script>
function googleTranslateElementInit() {new google.translate.TranslateElement({//这个参数不起作用,看文章底部更新,翻译面板的语言//pageLanguage: 'zh-CN',//这个是你需要翻译的语言,比如你只需要翻译成越南和英语,这里就只写en,viincludedLanguages: 'en,zh-CN,hr,cs,da,nl,fr,de,el,iw,hu,ga,it,ja,ko,pt,ro,ru,sr,es,th,vi',//选择语言的样式,这个是面板,还有下拉框的样式,具体的记不到了,找不到api~~layout: google.translate.TranslateElement.InlineLayout.SIMPLE,//自动显示翻译横幅,就是翻译后顶部出现的那个,有点丑,这个属性没有用的话,请看文章底部的其他方法autoDisplay: true, //还有些其他参数,由于原插件不再维护,找不到详细api了,将就了,实在不行直接上dom操作}, 'google_translate_element'//触发按钮的id);}
</script> 

还用另一个 js 库 去实现的:

<script src="./franc.js">// import {franc, francAll} from './franc.js'var ll=franc('Alle menneske er fødde til fridom') //=> 'nno'console.log(ll);</script>

依赖的 js 库太大了,不贴出来了,有需要可以留言。

查资料看到还有这种用法的:

<script>
javascript: void((function () {var script = document.createElement('script');script.src = '//translate.google.cn/translate_a/element.js?cb=googleTranslateElementInit';document.getElementsByTagName('head')[0].appendChild(script);var google_translate_element = document.createElement('div');google_translate_element.id = 'google_translate_element';google_translate_element.style = 'position:fixed; bottom:10px; right:10px; cursor:pointer;';document.documentElement.appendChild(google_translate_element);script = document.createElement('script');script.innerHTML = "function googleTranslateElementInit() {" +"new google.translate.TranslateElement({" +"layout: google.translate.TranslateElement.InlineLayout.SIMPLE," +"multilanguagePage: true," +"pageLanguage: 'auto'," +"includedLanguages: 'zh-CN,zh-TW,en'" +"}, 'google_translate_element');}";document.getElementsByTagName('head')[0].appendChild(script);
})());</script>

获取网页内容的所有标签的文本内容,过滤非文本标签,实现如下:

<script>function listen(callback) {// 获取 HTML 文档中的所有元素,但不包括 下列 选择器的元素var exclude = ['head', 'pre', 'script', 'textarea']//排除名单var selectors = []exclude.forEach((item, index) => {selectors.push(item)//排除该元素selectors.push(item + ' *')//排除该元素后代})get(document.querySelectorAll('*:not(' + selectors.join(',') + ')'))//*:not(pre,pre *)// 创建 MutationObserver 对象let observer = new MutationObserver(function (mutations) {mutations.forEach(function (mutation) {// 遍历新添加的节点for (let i = 0; i < mutation.addedNodes.length; i++) {let node = mutation.addedNodes[i];// 如果节点是元素节点,就调用 get 函数if (node.nodeType === 1) {callMyFunction(node)function callMyFunction(param1) {setTimeout(function () {get([...param1.querySelectorAll('*'), param1])}, 300);}}}});});// 设置 MutationObserver 的参数,表示监听所有元素的变化let config = {childList: true,subtree: true};// 启动 MutationObserverobserver.observe(document, config);function get(elements) {// 遍历所有元素for (let i = 0; i < elements.length; i++) {let element = elements[i];// 遍历元素的 childNodesfor (let j = 0; j < element.childNodes.length; j++) {let node = element.childNodes[j];// 如果当前节点是一个文本节点(nodeType 为 3)且不包含子节点(nodeName 为 '#text'),就将文本添加到数组中if (node.nodeType === 3 && node.nodeName.toLowerCase() === '#text') {// 过滤掉文本中的换行符let text = node.nodeValuevar v = { a: false, b: false }text.slice(0, 1) == " " ? v.a = true : v.a = falsetext.slice(-1) == " " ? v.b = true : v.b = falsetext = text.replace(/[\n\t\r]/g, '').trim();// 如果文本不仅包含空白字符,就将它添加到数组中if (/\S/.test(text)) {//不处理只有数字和符号的文本if (!/^[0-9\+\-\*\/\=><&\!@#\$%\^\*\\(\)\[\]\{\}_,.;',。、;’、]{1,}$/.test(text)) {//---------------处理//翻译text//text = "$" + text//---------------处理结束--显示v.a == true ? text = " " + text : textv.b == true ? text = text + " " : textif (!element.matches('script,textarea')) {//单元素阻断,白名单node.nodeValue = textcallback.call({ text: text, node: node, element: element })} else {//console.log("位于排除标签列表", element);}} else {//console.log("只有数字和符号的文本", text);}}}}}}}let time = null;var data = []listen(function () {if (time !== null) {clearTimeout(time);}time = setTimeout(async () => {console.log(data);//抖动结束,开始翻译var sl = []data.forEach((item, index) => {//取textsl.push(item['text'])});// var tl = await translation_arr(sl) //返回一个数组[[翻译结果,源语言类型],...*]//使用的谷歌批量翻译API,这里就不提供了var tl = []sl.forEach((item, index) => {tl.push('[ 编辑:' + item + ',' + index + '] ')});tl.forEach((item, index) => {data[index]['node'].origText = data[index]['node'].nodeValuedata[index]['node'].nodeValue = item//更改文本});//这里的this指向的是input}, 500)data.push(this)})/* 监听文本节点被点击document.onselectstart = function (e) {console.log(e.target,e.target.origText);}*/</script> 

在网页中自动插入一个 下拉框 用于展示支持的翻译语种,并根据网页内容识别的语种自动选中语种类型:


<script>// 获取浏览器默认语言const getBrowserLang = function() {let browserLang = navigator.language? navigator.language: navigator.browserLanguage;let defaultBrowserLang = "";if (browserLang.toLowerCase() === "us" ||browserLang.toLowerCase() === "en" ||browserLang.toLowerCase() === "en_us") {defaultBrowserLang = "en_US";} else {defaultBrowserLang = "zh_CN";}return defaultBrowserLang;
};console.log(getBrowserLang());
</script><script>var type = navigator.appName; //BOM对象获取浏览器名称if (type == "Netscape") {var lang = navigator.language.toLowerCase(); //获取浏览器配置语言,支持非IE浏览器} else {var lang = navigator.browserLanguage.toLowerCase(); //获取浏览器配置语言,支持IE5+};console.log(lang);var lang = lang.substr(0, 5); //获取浏览器配置语言前4位console.log(lang);/*极速测试体验,用于审查元素时直接执行的1. 随便打开一个网页2. 右键-审查元素3. 粘贴入一下代码:var head= document.getElementsByTagName('head')[0];  var script= document.createElement('script');  script.type= 'text/javascript';  script.src= 'http://localhost:8060/static/inspector.js';  head.appendChild(script); 4. Enter 回车键 , 执行5. 在当前网页的左上角,就出现了一个大大的切换语言了	使用的是 v2.x 版本进行的翻译*/var head= document.getElementsByTagName('head')[0]; 
var script= document.createElement('script'); 
script.type= 'text/javascript'; 
script.src= 'http://localhost:8060/static/translate.js'; 
script.onload = script.onreadystatechange = function() {translate.storage.set('to','');//设置使用v2.x 版本translate.setUseVersion2(); //SELECT 修改 onchange 事件translate.selectLanguageTag.selectOnChange = function(event){//判断是否是第一次翻译,如果是,那就不用刷新页面了。 true则是需要刷新,不是第一次翻译var isReload = translate.to != null && translate.to.length > 0;if(isReload){//如果要刷新页面的话,弹出友好提示alert('您好,快速体验暂时只能切换其中一种语言进行体验,只是提供效果展示,您可参考接入文档来接入您的项目中进行完整体验及使用。');}else{var language = event.target.value;translate.changeLanguage(language);console.log("ttttt");console.log(language);}			}translate.listener.start();	//开启html页面变化的监控,对变化部分会进行自动翻译。注意,这里变化区域,是指使用 translate.setDocuments(...) 设置的区域。如果未设置,那么为监控整个网页的变化translate.execute();document.getElementById('translate').style.position = 'fixed';document.getElementById('translate').style.color = 'red';document.getElementById('translate').style.left = '10px';document.getElementById('translate').style.top = '10px';document.getElementById('translate').style.zIndex = '9999999999999';setInterval(function() {try{if(document.getElementById('translateSelectLanguage') == null){return;}document.getElementById('translateSelectLanguage').style.fontSize = '2rem';document.getElementById('translateSelectLanguage').style.borderWidth = '0.5rem';document.getElementById('translateSelectLanguage').style.borderColor = 'red';}catch(e){//select数据是通过接口返回的}},1000);}
head.appendChild(script); </script>

不同页面或者不同 js 之间传递数据,粗暴简单一点可以通过如下方式:

window.localStorage.setItem('local_language',translate.language.local);



通过对前端js和后端翻译服务进行了长时间的研究和测试,最终实现的效果可以达到:

1)如果是自己的网站
在网页最末尾, 之前,加入以下代码,一般在页面的最底部就出现了选择语言的 select 切换标签。 其实就这么简单:

<script src="http://localhost:8060/static/translate.min.js"></script>
<script>// translate.language.setLocal('chinese_simplified');translate.request.api.host='http://localhost:8060/';translate.execute();
</script>

或者:

<script src="http://localhost:8060/static/i18n.js"></script>

2)如果是第三方的网站
随便打开一个网页
右键 - 检查(审查元素)〉控制台:
粘贴入以下代码:

var head= document.getElementsByTagName('head')[0]; var script= document.createElement('script'); script.type= 'text/javascript'; script.src= 'http://localhost:8060/static/inspector.js'; head.appendChild(script);

或者:

var head= document.getElementsByTagName('head')[0]; var script= document.createElement('script'); script.type= 'text/javascript'; script.src= 'http://localhost:8060/static/inspector.js'; head.appendChild(script);

Enter 回车键 , 执行
在当前网页的左上角,就出现了一个大大的切换语言,切换试试看。


效果参考:

点击查看

https://blog.csdn.net/u014374009/article/details/135401003

源码及后端翻译服务支持docker一键部署:

点击查看

https://blog.csdn.net/u014374009/article/details/135370222


有任何定制化的需求可以联系作者完成开发。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/672084.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

别人还在集五福,星河社区开发者已经奖品拿到手软了!

AI新年新玩法你是否曾为AI应用的神奇而惊叹&#xff1f;你是否想过用AI为你定制新年写真&#xff1f;无需编程&#xff01;&#xff01; 飞桨星河社区帮你实现&#xff0c;还可赢取新年礼包&#xff01; 先速来看看攻略吧&#xff01;页面底部见活动详情。 玩法1攻略&#xff…

什么是UI设计?

用户界面&#xff08;UI&#xff09;它是人与机器互动的载体&#xff0c;也是用户体验&#xff08;UX&#xff09;一个组成部分。用户界面由视觉设计 (即传达产品的外观和感觉) 和交互设计 (即元素的功能和逻辑组织) 两部分组成。用户界面设计的目标是创建一个用户界面&#xf…

9.0 Zookeeper 节点特性

本章节介绍一下 zookeeper 的节点特性和简单使用场景&#xff0c;正是由于这些节点特性的存在使 zookeeper 开发出不同的场景应用。 1、同一级节点 key 名称是唯一的 实例&#xff1a; $ ls / $ create /runoob 2 已存在 /runoob 节点&#xff0c;再次创建会提示已经存在。 …

MySQL:从基础到实践(简单操作实例)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 下载前言一、MySQL是什么&#xff1f;二、使用步骤1.引入库2.读入数据 提交事务查询数据获取查询结果总结 下载 点击下载提取码888999 前言 在现代信息技术的世界…

Java基于微信小程序的医院挂号系统

文章目录 1 简介2 技术栈3 系统目标3.2 系统功能需求分析3.2.1 功能需求分析 4 系统模块设计4.1 数据库模块设计 5 系统的实现5.1 微信小程序个人中心5.2 科**室内容查看的实现**5.3 预约挂号的实现5.4 后台管理界面实现5.5 医生预约管理5.6 医生信息管理 参考文献7 推荐阅读8 …

【Git教程】(一)基本概念 ——工作流、分布式版本控制、版本库 ~

Git教程 基本概念 1️⃣ 为什么要用 Git2️⃣ 为什么要用工作流3️⃣ 分布式版本控制4️⃣ 版本库5️⃣ 简单的分支创建与合并&#x1f33e; 总结 在本章中&#xff0c;将介绍一个分布式版本控制系统的设计思路&#xff0c;以及它与集中式版本控制系统的不同之处。除此之外&am…

区块链大解码:深入了解Web3的核心技术

随着技术的迅速发展&#xff0c;Web3正逐渐崭露头角&#xff0c;成为数字时代的引领者。其中&#xff0c;区块链技术作为Web3的核心&#xff0c;扮演着至关重要的角色。本文将深入解码区块链技术&#xff0c;探讨其在Web3时代的关键作用以及未来发展趋势。 1. 区块链基础原理 …

Windows 10 配置 FFmpeg 使用环境

Windows 10 配置 FFmpeg 使用环境 1.下载FFmpeg 的windows办2. 配置环境变量:3.查看是否配置正确 cmd 或者 PowerShell 执行以下命令 1.下载FFmpeg 的windows办 GitHub 地址 :https://github.com/BtbN/FFmpeg-Builds/releases 解压后得到如图: 2. 配置环境变量: 复制路径:…

java SpringBoot2.7整合Elasticsearch(ES)7 进行文档增删查改

首先 我们在 ES中加一个 books 索引 且带有IK分词器的索引 首先 pom.xml导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>applicatio…

基于A-Star搜索算法的迷宫小游戏的设计

这篇文章是作者人工智能导论课的大作业&#xff0c;发出来供大家学习参考&#xff08;有完整代码&#xff09;。想要论文WORD文件的可以在本文资源处下载&#xff08;可能还在审核&#xff09;。 摘要&#xff1a; 本文章聚焦于基于A-Star搜索算法的迷宫小游戏设计&#xff0c;…

AR特效自研AI算法技术解决方案

在当今这个高速发展的数字化时代&#xff0c;增强现实&#xff08;AR&#xff09;技术已经成为企业创新和市场竞争的重要手段。美摄科技凭借对AI技术的深厚积累&#xff0c;为企业提供了一套创新的AR特效自研AI算法技术解决方案&#xff0c;旨在满足企业在AR领域的多元化需求。…

选择大语言模型:2024 年开源 LLM 入门指南

作者&#xff1a;来自 Elastic Aditya Tripathi 如果说人工智能在 2023 年起飞&#xff0c;这绝对是轻描淡写的说法。数千种新的人工智能工具被推出&#xff0c;人工智能功能被添加到现有的应用程序中&#xff0c;好莱坞因对这项技术的担忧而戛然而止。 甚至还有一个人工智能工…

代码随想录 Leetcode46. 全排列

题目&#xff1a; 代码&#xff08;首刷自解 2024年2月6日&#xff09;&#xff1a; class Solution { private:vector<vector<int>> res;vector<int> path; public:void backtracking(vector<int>& nums, int depth, vector<bool>& us…

数据结构第十天(排序算法总结)

目录 前言 常数时间复杂度&#xff1a;O(1) 线性时间复杂度&#xff1a;O(n) 线性对数时间复杂度&#xff1a;O(n log n) 平方时间复杂度&#xff1a;O(n^2) 对数时间复杂度&#xff1a;O(log n) 前言 排序算法的学习可以告一段落了。但算法的学习永不停止。 今天&…

redis:七、集群方案(主从复制、哨兵模式、分片集群)和面试模板

redis集群方案 在Redis中提供的集群方案总共有三种&#xff08;一般一个redis节点不超过10G内存&#xff09; 主从复制哨兵模式分片集群 主从复制&#xff08;主从数据同步&#xff09; replid和offset Replication Id&#xff1a;简称replid&#xff0c;是数据集的标记&a…

C++集群聊天服务器 数据模块+业务模块+CMake构建项目 笔记 (上)

跟着施磊老师做C项目&#xff0c;施磊老师_腾讯课堂 (qq.com) 本文在此篇博客的基础上继续实现数据模块和业务模块代码&#xff1a; C集群聊天服务器 网络模块业务模块CMake构建项目 笔记 &#xff08;上&#xff09;-CSDN博客https://blog.csdn.net/weixin_41987016/article…

显示器校准软件:BetterDisplay Pro for Mac v2.0.11激活版下载

BetterDisplay Pro是一款由waydabber开发的Mac平台上的显示器校准软件&#xff0c;可以帮助用户调整显示器的颜色和亮度&#xff0c;以获得更加真实、清晰和舒适的视觉体验。 软件下载&#xff1a; BetterDisplay Pro for Mac v2.0.11激活版下载 以下是BetterDisplay Pro的主要…

【Linux取经路】探寻shell的实现原理

文章目录 一、打印命令行提示符二、读取键盘输入的指令三、指令切割四、普通命令的执行五、内建指令执行5.1 cd指令5.2 export指令5.3 echo指令 六、结语 一、打印命令行提示符 const char* getusername() // 获取用户名 {return getenv("USER"); }const char* geth…

LeetCode-第171题-Excel表的序列号

1.题目描述 给你一个字符串 columnTitle &#xff0c;表示 Excel 表格中的列名称。返回 该列名称对应的列序号 。 例如&#xff1a; A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ... 2.样例描述 3.思路描述 遍历时将每个字母与 A 做减法&…

抖音创作服务平台的自适应,从2560到1024,做的真是棒呀。

不得不服&#xff0c;抖音创作服务平台的电脑页面&#xff0c;自适应效果做的非常好&#xff0c;从2560到1024这个跨度的分辨率都做了很好地处理。 2560 4K屏 1920 2K屏幕 1600 宽屏 1440 中宽屏 1366 笔记本屏 1280 窄屏 1024 超窄屏 768 pad端 这个出现横向滚动条了。 算是用…