diff --git a/component/pear/css/module/translate.css b/component/pear/css/module/translate.css new file mode 100644 index 0000000000000000000000000000000000000000..ed82b9560371cc1eb5283b2b908ed5848b424987 --- /dev/null +++ b/component/pear/css/module/translate.css @@ -0,0 +1,7 @@ +/* 将所有内页的切换语言都隐藏掉,只留顶部右上角一个切换语言入口 */ +#translate{ + display: none; +} +.layui-header>ul>#translate{ + display: inline; +} \ No newline at end of file diff --git a/component/pear/css/pear.css b/component/pear/css/pear.css index c43e364a3a128bf83fce217e1e03f55e1fe6ebdc..f6fb2ed9157e2dd7a48bc14edb1a0062dc6a67e2 100644 --- a/component/pear/css/pear.css +++ b/component/pear/css/pear.css @@ -27,4 +27,5 @@ @import url("module/tab.css"); @import url("module/tag.css"); @import url("module/fullscreen.css"); -@import url("module/popover.min.css"); \ No newline at end of file +@import url("module/popover.min.css"); +@import url("module/translate.css"); \ No newline at end of file diff --git a/component/pear/module/admin.js b/component/pear/module/admin.js index b8299337aefdf8bdd356c7e4a5acd26002c91632..7724dea379ab591751d6644957627a2428a59c01 100644 --- a/component/pear/module/admin.js +++ b/component/pear/module/admin.js @@ -1,4 +1,4 @@ -layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'menu', 'frame', 'theme', 'convert','fullscreen'], +layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'menu', 'frame', 'theme', 'convert','fullscreen', 'translate'], function(exports) { "use strict"; @@ -12,7 +12,8 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm pearFrame = layui.frame, pearTheme = layui.theme, message = layui.message, - fullscreen=layui.fullscreen; + fullscreen=layui.fullscreen, + translate = layui.translate; var bodyFrame; var sideMenu; @@ -413,6 +414,19 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm $(".fullScreen").eq(0).addClass("layui-icon-screen-restore"); }); } + }, + this.translate = function(option){ + if(typeof(option.translate) == 'undefined'){ + return; + } + window.pearTranslateConfig = option.translate; //暴露 pear.config.yml 中的 translate 配置出来,以便子页面在pear中获取配置信息。 + + /* + + 因为所有页面中都有 pear.js,但admin.js只有主页面中才有,但翻译能力是需要所有页面都具备的,故而放到pear.js 之中,老哥看是否合理,或怎么进行一下调整。 + + */ + } }; @@ -895,6 +909,7 @@ layui.define(['message', 'table', 'jquery', 'element', 'yaml', 'form', 'tab', 'm if (param.header.message != false) { pearAdmin.messageRender(param); } + pearAdmin.translate(param); } function getColorById(id) { diff --git a/component/pear/module/translate.js b/component/pear/module/translate.js new file mode 100644 index 0000000000000000000000000000000000000000..e08441d25f91dc7e09d3b2659c38708567b19c3e --- /dev/null +++ b/component/pear/module/translate.js @@ -0,0 +1,13 @@ +/* + * 多语言翻译,作者:管雷鸣 + */ +layui.define(['table', 'form', 'element'], function (exports) { + //下行是直接将https://gitee.com/mail_osc/translate 压缩后粘贴过来 + var translate={version:"2.1.8.20230110",useVersion:"v1",setUseVersion2:function(){translate.useVersion="v2"},translate:null,includedLanguages:"zh-CN,zh-TW,en",resourcesUrl:"//res.zvo.cn/translate",selectLanguageTag:{show:!0,languages:"zh-CN,zh-TW,en",alreadyRender:!1,render:function(){if(!translate.selectLanguageTag.alreadyRender&&(translate.selectLanguageTag.alreadyRender=!0,translate.selectLanguageTag.show)){if(null==document.getElementById("translate")){var e=document.getElementsByTagName("body")[0],t=document.createElement("div");t.id="translate",e.appendChild(t)}else if(null!=document.getElementById("translateSelectLanguage"))return;translate.request.post("https://api.translate.zvo.cn/language.json",{},function(e){if(0!=e.result){var t=function(e){var t=e.target.value;translate.changeLanguage(t)},n=document.createElement("select");n.id="translateSelectLanguage",n.className="translateSelectLanguage";for(var a=0;a0?translate.to==e.list[a].id&&l.setAttribute("selected","selected"):e.list[a].id==translate.language.local&&l.setAttribute("selected","selected"),l.appendChild(document.createTextNode(e.list[a].name)),n.appendChild(l)}window.addEventListener?n.addEventListener("change",t,!1):n.attachEvent("onchange",t),document.getElementById("translate").appendChild(n)}else console.log("load language list error : "+e.info)})}}},localLanguage:"zh-CN",googleTranslateElementInit:function(){var e="";null!=document.getElementById("translate")&&(e="translate"),translate.translate=new google.translate.TranslateElement({pageLanguage:"zh-CN",includedLanguages:translate.selectLanguageTag.languages,layout:0},e)},init:function(){var e=window.location.protocol;"file:"==window.location.protocol&&(e="http:"),-1==this.resourcesUrl.indexOf("://")&&(this.resourcesUrl=e+this.resourcesUrl)},execute_v1:function(){if(null==document.getElementById("translate")&&translate.selectLanguageTag.show){var e=document.getElementsByTagName("body")[0],t=document.createElement("div");t.id="translate",e.appendChild(t)}"zh-CN,zh-TW,en"!=translate.includedLanguages&&(translate.selectLanguageTag.languages=translate.includedLanguages,console.log("translate.js tip: translate.includedLanguages obsolete, please use the translate.selectLanguageTag.languages are set"));var n=document.getElementsByTagName("head")[0],a=document.createElement("script");a.type="text/javascript",a.src=this.resourcesUrl+"/js/element.js",n.appendChild(a)},setCookie:function(e,t){var n=e+"="+escape(t);document.cookie=n},getCookie:function(e){for(var t=document.cookie.split("; "),n=0;n0?e.substr(e.lastIndexOf("/")+1,e.length-1):translate.localLanguage},changeLanguage:function(e){if(",en,de,hi,lt,hr,lv,ht,hu,zh-CN,hy,uk,mg,id,ur,mk,ml,mn,af,mr,uz,ms,el,mt,is,it,my,es,et,eu,ar,pt-PT,ja,ne,az,fa,ro,nl,en-GB,no,be,fi,ru,bg,fr,bs,sd,se,si,sk,sl,ga,sn,so,gd,ca,sq,sr,kk,st,km,kn,sv,ko,sw,gl,zh-TW,pt-BR,co,ta,gu,ky,cs,pa,te,tg,th,la,cy,pl,da,tr,".indexOf(","+e+",")>-1){translate.check();var t="/"+translate.localLanguage+"/"+e,n=document.location.host.split(".");if(n.length>2){var a=n[n.length-2]+"."+n[n.length-1];document.cookie="googtrans=;expires="+new Date(1)+";domain="+a+";path=/",document.cookie="googtrans="+t+";domain="+a+";path=/"}return translate.setCookie("googtrans",""+t),void location.reload()}translate.setUseVersion2(),translate.to=e,translate.storage.set("to",e),location.reload()},check:function(){"file:"==window.location.protocol&&console.log("\r\n---WARNING----\r\ntranslate.js 主动翻译组件自检异常,当前协议是file协议,翻译组件要在正常的线上http、https协议下才能正常使用翻译功能\r\n------------")},to:"",autoDiscriminateLocalLanguage:!1,documents:[],ignore:{tag:["style","script","img","head","link","i","pre","code"],class:["ignore","translateSelectLanguage"]},setAutoDiscriminateLocalLanguage:function(){translate.autoDiscriminateLocalLanguage=!0},nodeQueue:{},setDocuments:function(e){null!=e&&void 0!==e&&(void 0===e.length?translate.documents[0]=e:translate.documents=e,translate.nodeQueue={},console.log("set documents , clear translate.nodeQueue"))},getDocuments:function(){return null!=translate.documents&&void 0!==translate.documents&&translate.documents.length>0?translate.documents:document.all},listener:{isExecuteFinish:!1,isStart:!1,start:function(){translate.temp_linstenerStartInterval=setInterval(function(){"complete"==document.readyState&&(clearInterval(translate.temp_linstenerStartInterval),translate.listener.addListener())},50)},addListener:function(){translate.listener.isStart=!0;const e={attributes:!0,childList:!0,subtree:!0},t=new MutationObserver(function(e,t){var n=[];for(let t of e)"childList"===t.type&&t.addedNodes.length>0&&n.push.apply(n,t.addedNodes);n.length>0&&translate.execute(n)});for(var n=translate.getDocuments(),a=0;a0&&(translate.to=n)}try{translate.selectLanguageTag.render()}catch(e){console.log(e)}if(null!=translate.to&&void 0!==translate.to&&0!=translate.to.length){var a;if(void 0!==e){if(null==e)return void cnosole.log("translate.execute(...) 中传入的要翻译的目标区域不存在。");void 0===e.length?(a=new Array)[0]=e:a=e}else a=translate.getDocuments();for(var l=0;l0)for(var g=0;g0)for(var a=0;a-1)){for(var a=!1,l=t.parentNode;t!=l&&null!=l;)null!=l.className&&translate.ignore.class.indexOf(l.className)>-1&&(a=!0),l=l.parentNode;if(!a)if("INPUT"==t.nodeName||"TEXTAREA"==t.nodeName){if(null==t.attributes||void 0===t.attributes)return;void 0!==t.attributes.placeholder&&translate.addNodeToQueue(e,t.attributes.placeholder)}else if(null!=t.nodeValue&&t.nodeValue.trim().length>0){if(!(null!=t.nodeValue&&"string"==typeof t.nodeValue&&t.nodeValue.length>0))return;translate.addNodeToQueue(e,t)}}}},addNodeToQueue:function(e,t){if(null!=t.nodeValue&&0!=t.nodeValue.length){translate.util.hash(t.nodeValue);if(!translate.util.findTag(t.nodeValue)){var n=translate.language.get(t.nodeValue);for(var a in void 0!==n[translate.to]&&delete n[translate.to],n){null!=translate.nodeQueue[e].list[a]&&void 0!==translate.nodeQueue[e].list[a]||(translate.nodeQueue[e].list[a]=new Array);for(var l=0;l]+>/g.test(e)},arrayFindMaxNumber:function(e){for(var t={},n=[],a=0,l=0,r=e.length;la&&(a=t[e[l]]);for(var s in t)t[s]===a&&n.push(s);return n},hash:function(e){if(null==e||void 0===e)return e;var t,n=0;if(0===e.length)return n;for(t=0;t0&&(o+="&"),o=o+u+"="+t[u];var i=null;try{i=new XMLHttpRequest}catch(e){i=new ActiveXObject("Microsoft.XMLHTTP")}if(i.open(a,e,l),null!=r)for(var u in r)i.setRequestHeader(u,r[u]);i.send(o),i.onreadystatechange=function(){if(4==i.readyState)if(200==i.status){var e=null;try{e=JSON.parse(i.responseText)}catch(e){console.log(e)}n(null==e?i.responseText:e)}else null!=s&&s(i)}}},storage:{set:function(e,t){localStorage.setItem(e,t)},get:function(e){return localStorage.getItem(e)}}};try{translate.init()}catch(e){console.log(e)} + + //默认就是用新的v2版本 + translate.setUseVersion2(); + window.translate = translate; + //输出 translate 接口 + exports('translate', translate); +}); \ No newline at end of file diff --git a/component/pear/pear.js b/component/pear/pear.js index 2f19802bf9d769b164dd9eb0cdac32474353585f..c7e9fee65fd2fe4262b8058705f99e81f918b62a 100644 --- a/component/pear/pear.js +++ b/component/pear/pear.js @@ -44,7 +44,71 @@ layui.config({ nprogress: "nprogress", // 进度过渡 watermark:"watermark/watermark", //水印 fullscreen:"fullscreen", //全屏组件 - popover:"popover/popover" //汽泡组件 -}).use(['layer', 'theme'], function () { + popover:"popover/popover", //汽泡组件 + translate:"translate" //多语言翻译组件 +}).use(['layer', 'theme', 'translate'], function () { layui.theme.changeTheme(window, false); + + /***** translate.js 翻译 ******/ + var template_temp_pearInterval = setInterval(function(){ + if(typeof(parent.window.pearTranslateConfig) == 'undefined'){ + //配置还没加载出来,等待加载 + return; + } + //admin.js 初始化完毕,translate配置已获取成功 + var translateConfig = parent.window.pearTranslateConfig; + //停止 + clearInterval(template_temp_pearInterval); + + /***** 配置项赋予 *****/ + if(typeof(translateConfig.autoDiscriminateLocalLanguage) != 'undefined' && (translateConfig.autoDiscriminateLocalLanguage == true || translateConfig.autoDiscriminateLocalLanguage == 'true' )){ + translate.setAutoDiscriminateLocalLanguage(); //设置用户第一次用时,自动识别其所在国家的语种进行切换 + } + if(typeof(translateConfig.currentLanguage) != 'undefined' && translateConfig.currentLanguage.length > 0){ + translate.language.setLocal(translateConfig.currentLanguage); + } + if(typeof(translateConfig.ignoreClass) != 'undefined' && translateConfig.ignoreClass.length > 0){ + var classs = translateConfig.ignoreClass.split(','); + for(var ci = 0; ci < classs.length; ci++){ + var className = classs[ci].trim(); + if(className.length > 0){ + if(translate.ignore.class.indexOf(className.toLowerCase()) > -1){ + //已经有了,忽略 + }else{ + //还没有,加入 + translate.ignore.class.push(className); + } + } + } + } + if(typeof(translateConfig.ignoreTag) != 'undefined' && translateConfig.ignoreTag.length > 0){ + var tags = translateConfig.ignoreTag.split(','); + for(var ti = 0; ti < tags.length; ti++){ + var tagName = tags[ti].trim(); + if(tagName.length > 0){ + if(translate.ignore.tag.indexOf(tagName.toLowerCase()) > -1){ + //已经有了,忽略 + }else{ + //还没有,加入 + translate.ignore.tag.push(tagName); + } + } + } + } + //开启html页面变化的监控,对变化部分会进行自动翻译。注意,这里变化部分,是指当 translate.execute(); 已经完全执行完毕之后,如果页面再有变化的部分,才会对其进行翻译。 + translate.listener.start(); + //页面加载完毕后执行翻译 + if(document.readyState == 'complete'){ + translate.execute(); + }else{ + window.onload = function(){ + translate.execute(); + } + } + //避免有遗漏,特别是表格的render渲染等,诡异的会复原 + setTimeout(translate.execute,1500); + + }, 30); + /***** translate.js 翻译 结束 ******/ + }); \ No newline at end of file diff --git a/config/pear.config.json b/config/pear.config.json index 2c1334d50842bc79dbe8555928018dd96537bbe9..580fb5ac2cc3124ad020a0e0ea5a35f63f1cd21c 100644 --- a/config/pear.config.json +++ b/config/pear.config.json @@ -66,5 +66,11 @@ }, "header": { "message": "admin/data/message.json" + }, + "translate": { + "localLanguage": "chinese_simplified", + "autoDiscriminateLocalLanguage": false, + "ignoreClass": "ignore,test1,layui-logo", + "ignoreTag": "script,pre,code" } } \ No newline at end of file diff --git a/config/pear.config.yml b/config/pear.config.yml index 4b7cd707bed7c0ec0d12def576ec00dfd93532fb..ebfa8092adee793ce945d5a70682d49de9903eb5 100644 --- a/config/pear.config.yml +++ b/config/pear.config.yml @@ -79,4 +79,14 @@ other: ## 头部配置 header: ## 站内消息,通过 false 设置关闭 - message: "admin/data/message.json" \ No newline at end of file + message: "admin/data/message.json" +## 多语言翻译配置 +translate: + ## 当前语种,有: chinese_simplified 简体中文 、chinese_traditional 繁体中文、english 英语、korean 韩语 ,默认是 chinese_simplified 简体中文 + localLanguage: "chinese_simplified" + ## 设置用户第一次用时,自动识别其所在国家的语种进行切换,true:使用。 默认为false不使用。 + autoDiscriminateLocalLanguage: false + ## 翻译时忽略指定的 class name,多个 class name 之间用逗号分割 + ignoreClass: "ignore,test1,layui-logo" + ## 翻译时忽略指定的tag标签,多个标签之间用逗号分割 + ignoreTag: "script,pre,code" \ No newline at end of file diff --git a/index.html b/index.html index dd0b314409026b82e9c2e04ef55fe904b3d4126c..06d44056da4fbc2c9bd92f54c06072e185589fcc 100644 --- a/index.html +++ b/index.html @@ -33,6 +33,7 @@
    +