离线场景下任意文档的在线预览及原样格式翻译,不依赖其他厂商接口非侵入式一行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.rhkb.cn/news/254452.html

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

相关文章

PCIE 参考时钟架构

一、PCIe架构组件 首先先看下PCIE架构组件&#xff0c;下图中主要包括&#xff1a; ROOT COMPLEX (RC) (CPU); PCIE PCI/PCI-X Bridge; PCIE SWITCH; PCIE ENDPOINT (EP) (pcie设备); BUFFER; 各个器件的时钟来源都是由100MHz经过Buffer后提供。一个PCIE树上最多可以有256…

【Docker】了解Docker Desktop桌面应用程序,TA是如何管理和运行Docker容器(2)

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《Docker容器》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对…

python智慧养老系统—养老信息服务平台vue

本论文中实现的智慧养老系统-养老信息服务平台将以管理员和用户的日常信息维护工作为主&#xff0c;主要涵盖了系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;养老资讯管理&#xff0c;养生有道管理&#xff0c;养老机构管理&#xff0c;系统管理等功能&#x…

Qt QML学习(一):Qt Quick 与 QML 简介

参考引用 QML和Qt Quick快速入门全面认识 Qt Widgets、QML、Qt Quick 1. Qt Widgets、QML、Qt Quick 区别 1.1 QML 和 Qt Quick 是什么关系&#xff1f; 1.1.1 从概念上区分 QML 是一种用户界面规范和标记语言&#xff0c;它允许开发人员创建高性能、流畅的动画和具有视觉吸引…

docker proxy 【docker 代理】

第一种 创建代理配置文件 mkdir -p /etc/systemd/system/docker.service.d/ cat <<EOF > /etc/systemd/system/docker.service.d/http-proxy.conf Environment"HTTP_PROXYhttp://192.168.21.101:7890" Environment"HTTPS_PROXYhttp://192.168.21.1…

【原创 附源码】Flutter海外登录--Google登录最详细流程

最近接触了几个海外登录的平台&#xff0c;踩了很多坑&#xff0c;也总结了很多东西&#xff0c;决定记录下来给路过的兄弟坐个参考&#xff0c;也留着以后留着回顾。更新时间为2024年2月8日&#xff0c;后续集成方式可能会有变动&#xff0c;所以目前的集成流程仅供参考&#…

相机图像质量研究(9)常见问题总结:光学结构对成像的影响--工厂镜头组装

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

Cilium CNI深度指南

Cilium是基于eBPF的功能强大的CNI插件&#xff0c;为云原生环境提供了强大的网络和安全支持。原文: Cilium CNI: A Comprehensive Deep Dive Guide for Networking and Security Enthusiasts! &#x1f313;简介 欢迎阅读为网络和安全爱好者提供的全面深入的指南&#xff01; 本…

Mac电脑如何通过终端隐藏应用程序?

在我们使用Mac电脑的时候难免会遇到想要不想看到某个应用程序又不想卸载它们。值得庆幸的是&#xff0c;macOS具有一些强大的文件管理功能&#xff0c;允许用户轻松隐藏&#xff08;以及稍后显示&#xff09;文件甚至应用程序。 那么&#xff0c;Mac电脑如何通过终端隐藏应用程…

Unity3d Shader篇(五)— Phong片元高光反射着色器

文章目录 前言一、Phong片元高光反射着色器是什么&#xff1f;1. Phong片元高光反射着色器的工作原理2. Phong片元高光反射着色器的优缺点优点缺点 二、使用步骤1. Shader 属性定义2. SubShader 设置3. 渲染 Pass4. 定义结构体和顶点着色器函数5. 片元着色器函数 三、效果四、总…

Maven私服部署与JAR文件本地安装

Nexus3 是一个仓库管理器&#xff0c;它极大地简化了本地内部仓库的维护和外部仓库的访问。 平常我们在获取 maven 仓库资源的时候&#xff0c;都是从 maven 的官方&#xff08;或者国内的镜像&#xff09;获取。团队的多人员同样的依赖都要从远程获取一遍&#xff0c;从网络方…

基于CNN卷积网络的MNIST手写数字识别matlab仿真,CNN编程实现不使用matlab工具箱

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 卷积神经网络&#xff08;CNN&#xff09; 4.2 损失函数和优化 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ......................…

Linux学习笔记(centOS)—— 文件系统

目录 一、Linux中的文件 打开方式 二、目录结构​ 三、相关命令 切换目录命令 列出当前目录下的文件和目录命令 一、Linux中的文件 “万物皆文件。” 图1.1 所有文件 打开方式 图形化界面左上角的位置→计算机&#xff0c;打开以后就可以看到Linux全部的文件了&#xf…

Unity3d Shader篇(三)— 片元半兰伯特着色器解析

文章目录 前言一、片元半兰伯特着色器是什么&#xff1f;1. 片元漫反射着色器的工作原理2. 片元半兰伯特着色器的优缺点优点&#xff1a;缺点&#xff1a; 3. 公式 二、使用步骤1. Shader 属性定义2. SubShader 设置3. 渲染 Pass4. 定义结构体和顶点着色器函数5. 片元着色器函数…

浏览器F12调试

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…

微信小程序(三十八)滚动容器

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.滚动触底事件 2.下拉刷新事件 源码&#xff1a; index.wxml <view class"Area"> <!-- scroll-y 垂直滚动refresher-enabled 允许刷新bindrefresherrefresh 绑定刷新作用函数bindscrollto…

百家cms代审

环境搭建 源码链接如下所示 https://gitee.com/openbaijia/baijiacms 安装至本地后 直接解压到phpstudy的www目录下即可 接下来去创建一个数据库用于存储CMS信息。&#xff08;在Mysql命令行中执行&#xff09; 接下来访问CMS&#xff0c;会默认跳转至安装界面 数据库名称和…

C++算法之双指针、BFS和图论

一、双指针 1.AcWing 1238.日志统计 分析思路 前一区间和后一区间有大部分是存在重复的 我们要做的就是利用这部分 来缩短我们查询的时间 并且在使用双指针时要注意对所有的博客记录按时间从小到大先排好顺序 因为在有序的区间内才能使用双指针记录两个区间相差 相当于把一个…

FPGA_工程_按键控制的基于Rom数码管显示

一 信号 框图&#xff1a; 其中 key_filter seg_595_dynamic均为已有模块&#xff0c;直接例化即可使用&#xff0c;rom_8*256模块&#xff0c;调用rom ip实现。Rom_ctrl模块需要重新编写。 波形图&#xff1a; 二 代码 module key_fliter #(parameter CNT_MAX 24d9_999_99…

大数据分析|大数据分析的十大应用领域

有许多技术可用于分析大数据。这项工作介绍了BDA适用的各种分析技术领域如下。 &#xff08;1&#xff09;社会分析 社交分析是实时数据分析中一个重要且不断发展的分析方法。它分为社交网络(例如&#xff0c;Facebook和LinkedIn)&#xff0c;博客(例如&#xff0c;Blogger和W…