i18n-jsautotranslate 3.13.6 → 3.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -106
- package/index.js +482 -35
- package/package.json +1 -1
    
        package/README.md
    CHANGED
    
    | @@ -3,40 +3,69 @@ | |
| 3 3 | 
             
                translate.js
         | 
| 4 4 | 
             
            </h1>
         | 
| 5 5 | 
             
            <h4 align="center">
         | 
| 6 | 
            -
                 | 
| 7 | 
            -
                 | 
| 6 | 
            +
                AI i18n,两行js实现html全自动翻译。 <br/>
         | 
| 7 | 
            +
                交给AI,无需改动页面、无语言配置文件、无API Key、对SEO友好!
         | 
| 8 8 | 
             
            </h4> 
         | 
| 9 9 | 
             
            <h4 align="center">
         | 
| 10 10 | 
             
                简体中文 | 
         | 
| 11 | 
            -
                <a href="http://translate.zvo.cn/ | 
| 12 | 
            -
                <a href="http://translate.zvo.cn/ | 
| 13 | 
            -
                <a href="http://translate.zvo.cn/ | 
| 14 | 
            -
                <a href="http://translate.zvo.cn/ | 
| 15 | 
            -
                <a href="http://translate.zvo.cn/ | 
| 16 | 
            -
                <a href="http://translate.zvo.cn/ | 
| 11 | 
            +
                <a href="http://translate.zvo.cn/index.html?language=chinese_traditional">繁體中文</a> | 
         | 
| 12 | 
            +
                <a href="http://translate.zvo.cn/index.html?language=english">English</a> | 
         | 
| 13 | 
            +
                <a href="http://translate.zvo.cn/index.html?language=japanese">しろうと</a> | 
         | 
| 14 | 
            +
                <a href="http://translate.zvo.cn/index.html?language=russian">Русский язык</a> | 
         | 
| 15 | 
            +
                <a href="http://translate.zvo.cn/index.html?language=german">deutsch</a> | 
         | 
| 16 | 
            +
                <a href="http://translate.zvo.cn/index.html?language=french">Français</a> 
         | 
| 17 17 | 
             
            </h4> 
         | 
| 18 18 |  | 
| 19 | 
            -
            # 寻找合作
         | 
| 20 | 
            -
            寻找合作伙伴探讨盈利方式 - 以下全自有技术研发
         | 
| 21 | 
            -
             | 
| 22 | 
            -
            1. html源码翻译开放API http://doc.zvo.cn/tcdn/api/doc.html
         | 
| 23 | 
            -
            2. 企业级翻译通道代理 http://translate.zvo.cn/43262.html
         | 
| 24 | 
            -
            3. TCDN全自动网站源码级翻译,适合翻译后语种的SEO优化 http://translate.zvo.cn/236896.html
         | 
| 25 | 
            -
             | 
| 26 | 
            -
            联系:17076012262(微信同号) 我们是纯技术团队,欢迎联系,希望能跟你探讨合作盈利商机,我们专心技术,您来拓展商务销售
         | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 19 | 
             
            # 特性说明
         | 
| 30 | 
            -
            * **使用极其简单。**  | 
| 31 | 
            -
            * **不增加工作量。**  | 
| 32 | 
            -
            * **极其灵活扩展。** 您可指定它[ | 
| 33 | 
            -
            * [ | 
| 34 | 
            -
            * [ | 
| 35 | 
            -
            * [ | 
| 36 | 
            -
            * **搜索引擎友好。** 完全不影响你本身网站搜索引擎的收录。爬虫所爬取的网页源代码,它不会对其进行任何改动,你可完全放心。
         | 
| 37 | 
            -
            *  | 
| 38 | 
            -
            *  | 
| 39 | 
            -
             | 
| 20 | 
            +
            * **使用极其简单。** 直接加入几行 JavaScript 代码即可让其拥有上百种语言切换能力。
         | 
| 21 | 
            +
            * **不增加工作量。** 无需改造页面本身植入大量垃圾代码变得臃肿,也不需要配置各种语种的语言文件,因为它会直接扫描你的DOM自动识别并翻译显示,它不需要你到某某网站登录去申请什么key,它是开源开放的,拿来就能用。
         | 
| 22 | 
            +
            * **极其灵活扩展。** 您可指定它[只翻译某些指定区域的元素](http://translate.zvo.cn/4063.html)、[自定义切换语言方式及美化](http://translate.zvo.cn/4056.html)、[某些id、class、tag不被翻译](https://translate.zvo.cn/4061.html)、[自定义翻译术语](https://translate.zvo.cn/4070.html) ...... 只要你想的,它都能做到。做不到的,你找我我来让它做到!
         | 
| 23 | 
            +
            * **自动切换语种。** [自动根据用户的语言喜好及所在的国家切换到这个语种进行浏览](http://translate.zvo.cn/4065.html)
         | 
| 24 | 
            +
            * **极速翻译能力。** [内置三层缓存、预加载机制,毫秒级瞬间翻译的能力。它并不是你理解的大模型蜗牛似的逐个字往外出的那样](http://translate.zvo.cn/4026.html)
         | 
| 25 | 
            +
            * [**永久开源免费。** 采用Apache-2.0开源协议,您可永久免费使用](https://github.com/xnx3/translate/blob/master/LICENSE)。[另外你可以用它来做某些系统的三方插件直接售卖盈利](http://translate.zvo.cn/4036.html)、或者你是建站公司用它来做为一项高级功能盈利,我们都是完全认可并支持的,并不需要给我们任何费用!
         | 
| 26 | 
            +
            * **搜索引擎友好。** 完全不影响你本身网站搜索引擎的收录。爬虫所爬取的网页源代码,它不会对其进行任何改动,你可完全放心。[另外我们还有高级版本让你翻译之后的页面也能被搜索引擎收录](http://translate.zvo.cn/236896.html)
         | 
| 27 | 
            +
            * **支持私有部署。** [在某些政府机关及大集团内部项目中,对数据隐私及安全保密有强要求场景、或者完全不通外网的场景,可以自行私有部署翻译API服务](http://translate.zvo.cn/4052.html) 
         | 
| 28 | 
            +
            * **全球网络节点**。美洲、亚洲、欧洲 ... 都有网络节点,它能自动适配最快节点,每间隔1分钟自动获取一次延迟最小的节点进行接入使用,使全球范围使用都可高效稳定。
         | 
| 29 | 
            +
            * **HTML整体翻译**。[提供开放API接口,传入html文件(html源代码)及要翻译为的语言即可拿到翻译后的html源码。完美支持识别各种复杂及不规范html代码,
         | 
| 30 | 
            +
            支持翻译前的微调,比如不翻译某个区域、图片翻译、js语法操作html文件中的元素进行增删改等。](https://translate.zvo.cn/4022.html)
         | 
| 31 | 
            +
            * **源站翻译及域名分发**。[将您现有的网站,翻译成全新的小语种网站,小语种网站可以分别绑定域名并支持搜索引擎收录和排名。而您的源站无需任何改动。也就是你可以将你朋友的网站,翻译为小语种网站,绑定上自己的域名,提供对外访问。而你无需向你朋友取得任何的如账号等相关权限](https://translate.zvo.cn/236896.html)
         | 
| 32 | 
            +
            * **浏览器翻译插件**。[提供整体的浏览器翻译插件的全套方案,您如果是开发者,完全可以拿去将界面美化包装一下,而后直接提交应用市场进行售卖盈利](https://translate.zvo.cn/4037.html)
         | 
| 33 | 
            +
             | 
| 34 | 
            +
             | 
| 35 | 
            +
             | 
| 36 | 
            +
            # 微调指令
         | 
| 37 | 
            +
            * **[设置默认翻译为的语种](http://translate.zvo.cn/4071.html)**,用户第一次打开时,默认以什么语种显示。
         | 
| 38 | 
            +
            * **[自定义翻译术语](http://translate.zvo.cn/41555.html)**,如果你感觉某些翻译不太符合你的预期,可进行针对性的定义某些词或句子的翻译结果,进行自定义术语库
         | 
| 39 | 
            +
            * **[翻译完后自动触发执行](http://translate.zvo.cn/4069.html)**,当翻译完成后会自动触发执行您的某个方法,以便您来做自定义扩展。
         | 
| 40 | 
            +
            * **[指定翻译服务接口](http://translate.zvo.cn/4068.html)**,如果你不想用我们开源免费的翻译服务接口,使用您自己私有部署的、或者您自己二次开发对接的某个翻译服务,可通过此来指定自己的翻译接口。
         | 
| 41 | 
            +
            * **[监控页面动态渲染的文本进行自动翻译](http://translate.zvo.cn/4067.html)**,如果页面用 JavaScript 的地方比较多,内容都是随时用JS来控制显示的,比如 VUE、React 等框架做的应用,它可以实时监控DOM中文字的变动,当发生变动后立即识别并进行翻译。
         | 
| 42 | 
            +
            * **[设置本地语种(当前网页的语种)](http://translate.zvo.cn/4066.html)**,手动指定当前页面的语言。如果不设置,它会自动识别当前网页的文本,取当前网页文本中,出现频率最高的语种为默认语种。
         | 
| 43 | 
            +
            * **[自动切换为用户所使用的语种](http://translate.zvo.cn/4065.html)**,用户第一次打开网页时,自动判断当前用户所使用的语种、以及所在的国家,来自动进行切换为这个语种。
         | 
| 44 | 
            +
            * **[主动进行语言切换](http://translate.zvo.cn/4064.html)**,开放一个方法提供程序调用,只需传入翻译的目标语言,即可快速切换到指定语种
         | 
| 45 | 
            +
            * **[只翻译指定的元素](http://translate.zvo.cn/4063.html)**,指定要翻译的元素的集合,可传入一个或多个元素。如果不设置此,默认翻译整个网页。
         | 
| 46 | 
            +
            * **[翻译时忽略指定的id](http://translate.zvo.cn/4062.html)**,翻译时追加上自己想忽略不进行翻译的id的值,凡是在这里面的,都不进行翻译,也就是当前元素以及其子元素都不会被翻译。
         | 
| 47 | 
            +
            * **[翻译时忽略指定的class属性](http://translate.zvo.cn/4061.html)**,翻译时追加上自己想忽略不进行翻译的class标签,凡是在这里面的,都不进行翻译,也就是当前元素以及其子元素都不会被翻译。
         | 
| 48 | 
            +
            * **[翻译时忽略指定的tag标签](http://translate.zvo.cn/4060.html)**,翻译时追加上自己想忽略不进行翻译的tag标签,凡是在这里面的,都不进行翻译,也就是当前元素以及其子元素都不会被翻译。
         | 
| 49 | 
            +
            * **[翻译时忽略指定的文字不翻译](http://translate.zvo.cn/283381.html)**,翻译时追加上自己想忽略不进行翻译的文字,凡是在这里面的,都不进行翻译。
         | 
| 50 | 
            +
            * **[对网页中图片进行翻译](http://translate.zvo.cn/4055.html)**,在进行翻译时,对其中的图片也会一起进行翻译。
         | 
| 51 | 
            +
            * **[鼠标划词翻译](http://translate.zvo.cn/4072.html)**,鼠标在网页中选中一段文字,会自动出现对应翻译后的文本
         | 
| 52 | 
            +
            * **[获取当前显示的是什么语种](http://translate.zvo.cn/4074.html)**,如果用户切换为英语进行浏览,那么这个方法将返回翻译的目标语种。
         | 
| 53 | 
            +
            * **[根据URL传参控制以何种语种显示](http://translate.zvo.cn/41929.html)**,设置可以根据当前访问url的某个get参数来控制使用哪种语言显示。
         | 
| 54 | 
            +
            * **[离线翻译及自动生成配置](http://translate.zvo.cn/4076.html)**,其实它也就是传统 i18n 的能力,有语言配置文件提供翻译结果。
         | 
| 55 | 
            +
            * **[手动调用接口进行翻译操作](http://translate.zvo.cn/4077.html)**,通过JavaScript调用一个方法,传入翻译文本进行翻译,并获得翻译结果
         | 
| 56 | 
            +
            * **[元素的内容整体翻译能力配置](http://translate.zvo.cn/4078.html)**,对node节点的文本拿来进行整体翻译处理,而不再拆分具体语种,提高翻译语句阅读通顺程度
         | 
| 57 | 
            +
            * **[翻译接口响应捕获处理](http://translate.zvo.cn/4079.html)**,对翻译API接口的响应进行捕获,进行一些自定义扩展
         | 
| 58 | 
            +
            * **[清除历史翻译语种的缓存](http://translate.zvo.cn/4080.html)**,清除掉你上个页面所记忆的翻译语种,从而达到切换页面时不会按照上个页面翻译语种自动进行翻译的目的。
         | 
| 59 | 
            +
            * **[网页ajax请求触发自动翻译](http://translate.zvo.cn/4086.html)**,监听当前网页中所有的ajax请求,当请求结束后,自动触发翻译
         | 
| 60 | 
            +
            * **[设置只对指定语种进行翻译](http://translate.zvo.cn/4085.html)**,翻译时只会翻译在这里设置的语种,未在里面的语种将不会被翻译。
         | 
| 61 | 
            +
            * **[识别字符串语种及分析](http://translate.zvo.cn/43128.html)**,对字符串进行分析,识别出都有哪些语种,每个语种的字符是什么、每个语种包含的字符数是多少
         | 
| 62 | 
            +
            * **[重写一级缓存(浏览器缓存)](http://translate.zvo.cn/4082.html)**,你如果不想使用默认的 localStorage 的缓存,您完全可以对其重写,设置自己想使用的缓存方式
         | 
| 63 | 
            +
            * **[设置使用的翻译服务 translate.service.use](http://translate.zvo.cn/4081.html)**,目前有自有的服务器提供翻译API方式、无自己服务器API的方式两种。
         | 
| 64 | 
            +
            * **[启用企业级稳定翻译](http://translate.zvo.cn/4087.html)**,独立于开源版本的翻译通道之外,仅对少数用户开放,提供企业级的稳定、高速、以及更多网络分发节点。
         | 
| 65 | 
            +
            * **[增加对指定标签的属性进行翻译](http://translate.zvo.cn/231504.html)**,可以增加对指定html标签的某个或某些属性进行翻译。比如element、vue 等框架,有些自定义的标签属性,想让其也正常翻译
         | 
| 66 | 
            +
            * **[本地语种也进行强制翻译](http://translate.zvo.cn/289574.html)**,切换为中文时,即使本地语种设置的是中文,网页中只要不是中文的元素,都会被翻译为要显示的语种
         | 
| 67 | 
            +
            * **[自定义通过翻译API进行时的监听事件](http://translate.zvo.cn/379207.html)**,当通过翻译API进行文本翻译时的整个过程进行监听,做一些自定义处理,比如翻译API请求前要做些什么、请求翻译API完成并在DOM渲染完毕后触发些什么。
         | 
| 68 | 
            +
            * **[启用翻译中的遮罩层](http://translate.zvo.cn/407105.html)**,在进行通过翻译API进行翻译时,相关元素上面显示一层加载中的动画效果,让用户知道这段文本正在进行处理中
         | 
| 40 69 |  | 
| 41 70 | 
             
            # 在线体验
         | 
| 42 71 | 
             
            http://res.zvo.cn/translate/demo.html
         | 
| @@ -65,42 +94,6 @@ translate.execute();//进行翻译 | |
| 65 94 | 
             
            </script>
         | 
| 66 95 | 
             
            ````
         | 
| 67 96 |  | 
| 68 | 
            -
            # 详细使用
         | 
| 69 | 
            -
            * [设置默认翻译为的语种](http://translate.zvo.cn/41556.html)
         | 
| 70 | 
            -
            * [自定义翻译术语](http://translate.zvo.cn/41555.html)
         | 
| 71 | 
            -
            * [翻译完后自动执行](http://translate.zvo.cn/41554.html)
         | 
| 72 | 
            -
            * [指定翻译服务接口](http://translate.zvo.cn/41553.html)
         | 
| 73 | 
            -
            * [监控页面动态渲染的文本进行自动翻译](http://translate.zvo.cn/41552.html)
         | 
| 74 | 
            -
            * [设置本地语种(当前网页的语种)](http://translate.zvo.cn/41551.html)
         | 
| 75 | 
            -
            * [自动根据用户所在的国家切换其语种](http://translate.zvo.cn/41550.html)
         | 
| 76 | 
            -
            * [主动进行语言切换](http://translate.zvo.cn/41549.html)
         | 
| 77 | 
            -
            * [只翻译指定的元素](http://translate.zvo.cn/41548.html)
         | 
| 78 | 
            -
            * [翻译时忽略指定的id](http://translate.zvo.cn/41547.html)
         | 
| 79 | 
            -
            * [翻译时忽略指定的class属性](http://translate.zvo.cn/41546.html)
         | 
| 80 | 
            -
            * [翻译时忽略指定的tag标签](http://translate.zvo.cn/41545.html)
         | 
| 81 | 
            -
            * [翻译时忽略指定的文字不翻译](http://translate.zvo.cn/283381.html)
         | 
| 82 | 
            -
            * [对网页中图片进行翻译](http://translate.zvo.cn/41538.html)
         | 
| 83 | 
            -
            * [设定切换语言所支持的语种](http://translate.zvo.cn/41544.html)
         | 
| 84 | 
            -
            * [设定是否自动出现 select 切换语言](http://translate.zvo.cn/41543.html)
         | 
| 85 | 
            -
            * [CSS美化切换语言按钮](http://translate.zvo.cn/41542.html)
         | 
| 86 | 
            -
            * [指定切换语言选择框在代码中的位置](http://translate.zvo.cn/41541.html)
         | 
| 87 | 
            -
            * [对网页中图片进行翻译](http://translate.zvo.cn/41538.html)
         | 
| 88 | 
            -
            * [鼠标划词翻译](http://translate.zvo.cn/41557.html)
         | 
| 89 | 
            -
            * [获取当前显示的是什么语种](http://translate.zvo.cn/41761.html)
         | 
| 90 | 
            -
            * [根据URL传参控制以何种语种显示](http://translate.zvo.cn/41929.html)
         | 
| 91 | 
            -
            * [离线翻译及自动生成配置](http://translate.zvo.cn/41936.html)
         | 
| 92 | 
            -
            * [手动调用接口进行翻译操作](http://translate.zvo.cn/41961.html)
         | 
| 93 | 
            -
            * [元素的内容整体翻译能力配置](http://translate.zvo.cn/42563.html)
         | 
| 94 | 
            -
            * [翻译接口响应捕获处理](http://translate.zvo.cn/42678.html)
         | 
| 95 | 
            -
            * [清除历史翻译语种的缓存](http://translate.zvo.cn/43070.html)
         | 
| 96 | 
            -
            * [网页ajax请求触发自动翻译](http://translate.zvo.cn/43170.html)
         | 
| 97 | 
            -
            * [设置只对指定语种进行翻译](http://translate.zvo.cn/43133.html)
         | 
| 98 | 
            -
            * [重新绘制 select 语种下拉选择](http://translate.zvo.cn/43129.html)
         | 
| 99 | 
            -
            * [识别字符串语种及分析](http://translate.zvo.cn/43128.html)
         | 
| 100 | 
            -
            * [重写一级缓存(浏览器缓存)](http://translate.zvo.cn/43114.html)
         | 
| 101 | 
            -
            * [设置使用的翻译服务 translate.service.use](http://translate.zvo.cn/43086.html)
         | 
| 102 | 
            -
            * [启用企业级稳定翻译](http://translate.zvo.cn/43262.html)
         | 
| 103 | 
            -
            * [增加对指定标签的属性进行翻译](http://translate.zvo.cn/231504.html)
         | 
| 104 97 |  | 
| 105 98 |  | 
| 106 99 | 
             
            # 使用示例
         | 
| @@ -147,9 +140,13 @@ translate.execute();//进行翻译 | |
| 147 140 |  | 
| 148 141 | 
             
            [详细使用说明](https://translate.zvo.cn/4041.html) |  [Vue2 中使用 translate.js 在线 Demo](https://lruihao.github.io/vue-el-demo/#/translate-js)
         | 
| 149 142 |  | 
| 143 | 
            +
             | 
| 144 | 
            +
             | 
| 150 145 | 
             
            # 谁在使用
         | 
| 151 146 |  | 
| 152 147 | 
             
            开源项目:  
         | 
| 148 | 
            +
            * [DzzOffice](http://www.dzzoffice.com/index.php?mod=dzzmarket&op=view&mid=58) 开源办公套件,搭建自己的类似“Google企业应用套件”、“微软Office365”的企业协同办公平台
         | 
| 149 | 
            +
            * [ModStart](https://modstart.com/m/WebTranslate) 基于 Laravel 的模块化全栈开发框架
         | 
| 153 150 | 
             
            * [管伊佳ERP](https://gitee.com/jishenghua/JSH_ERP) 国产开源ERP系统关注度第一,专注进销存、生产、总账
         | 
| 154 151 | 
             
            * [FixIt](https://github.com/hugo-fixit/cmpt-translate) 一款简洁、优雅且先进的Hugo 博客主题
         | 
| 155 152 | 
             
            * [Z-Blog](https://app.zblogcn.com/?id=49226) 易用的博客程序,功能丰富,模板多样,助轻松搭建个性博客。
         | 
| @@ -182,16 +179,6 @@ translate.execute();//进行翻译 | |
| 182 179 | 
             
            如果您有开源项目,比如文档、cms、UI 框架、后台管理框架、等等,需要采用此进行多语言切换,欢迎喊我,无偿提供全程接入讨论及遇到的问题跟随优化,希望我们的开源项目能互相产生作用一起越来越好。如果你的项目在这个列表中没有,欢迎联系我说明,我给加入进去。如果您不想出现在这里,也联系我,我给隐去。
         | 
| 183 180 |  | 
| 184 181 |  | 
| 185 | 
            -
            # 哪些能力
         | 
| 186 | 
            -
            #### 能力一:前端翻译
         | 
| 187 | 
            -
            加入一个js文件及两行js代码,即可让你现有页面具有几百种语种切换能力。零门槛!详细参见 [translate.js](http://translate.zvo.cn/4019.html)
         | 
| 188 | 
            -
            #### 能力二:翻译html的能力
         | 
| 189 | 
            -
            传入html源码,指定要范围为什么语种,能将翻译之后的html源码返回。详细参见 [translate.api](http://translate.zvo.cn/41165.html)
         | 
| 190 | 
            -
            #### 能力三:整站翻译及独立绑定域名
         | 
| 191 | 
            -
            将您现有的网站,翻译成全新的小语种网站,可以绑定域名并支持搜索引擎收录和排名。基于现有网站,无需改动源站,翻译全站网页,绑定独立域名,保证搜索收录。
         | 
| 192 | 
            -
            翻译是基于您现有的网站内容,不需要重新建设多语种网站,只需要解析域名到您私有部署的服务器,就可以完成全站翻译。
         | 
| 193 | 
            -
            详细参见 [TCDN](http://translate.zvo.cn/41159.html)
         | 
| 194 | 
            -
             | 
| 195 182 | 
             
            # TCDN部署
         | 
| 196 183 | 
             
            tcdn是translate.js 的高级版本,它的能力是让你原本的网站可以用不同的域名访问到不同的语种。而不同的语种,都可以被收录!它可以免费部署到服务器进行使用。注意,它需要使用个1核2G的服务器进行部署的。    
         | 
| 197 184 | 
             
            部署方式有两种: 
         | 
| @@ -202,20 +189,6 @@ tcdn是translate.js 的高级版本,它的能力是让你原本的网站可以 | |
| 202 189 | 
             
            ### 服务器部署
         | 
| 203 190 | 
             
            需要一个干净的服务器,不依赖任何环境的情况下进行的部署,需要你懂点linux命令行, 部署方式参考:  [https://translate.zvo.cn/236899.html](https://translate.zvo.cn/236899.html)
         | 
| 204 191 |  | 
| 205 | 
            -
            # 开源仓库目录结构
         | 
| 206 | 
            -
            * **deploy** - 部署相关,比如shell文件、sql数据库文件等
         | 
| 207 | 
            -
            * **doc** - 一些文档相关
         | 
| 208 | 
            -
            * **translate.admin** - [TCDN的管理后台,PC端的WEB管理后台,可以通过此添加翻译的源站、绑定别的域名及设置域名所展现的语言、针对翻译的过程中支持使用JavaScript脚本自定义调优,比如设置哪些不被翻译、设置一些自定义术语库等。并且提供了CDN的基本能力,比如根据URL清除缓存、根据域名清除缓存等。](http://translate.zvo.cn/41163.html)
         | 
| 209 | 
            -
            * **translate.api** - [翻译开放接口,他不同于 translate service 的点在于 translate service 开放的是文本翻译接口,而 translate api 开放的是html翻译接口,你传入一个网页的url,它返回的是这个网页被翻译之后源码(此特性非常适合对不同语言上SEO优化)](http://translate.zvo.cn/41165.html)
         | 
| 210 | 
            -
            * **translate.core** - [TCDN的公共模块,无具体功能]
         | 
| 211 | 
            -
            * **translate.js** - [提供了针对html的分析及翻译能力。在现有的html页面中引入一个js可以快速实现当前页面语种切换的能力。且适配面非常广泛!只要是html的,它都能适配(包含VUE、uniapp等),在很多情况下,它是单独进行使用的,在你的老网站中加入几行js代码即可植入,使其快速具备语种切换能力。](http://translate.zvo.cn/4019.html)
         | 
| 212 | 
            -
            * **translate.service** - [翻译服务,它对接了 小牛翻译、google翻译、华为云翻译 等翻译服务,如果需要别的翻译服务或者局域网无网环境下部署,也可以快速对接自有翻译接口。它的作用是开放文本翻译接口,将 translate.js中 需要翻译的文本传入,然后将翻译之后的文本输出。提供批量翻译能力(一个翻译请求可以包含数千段需要翻译的文本)。
         | 
| 213 | 
            -
            并且它开放翻译接口,不止适用于 translate.js,你可以用在任何需要对接翻译接口的地方进行使用。其开放接口,说明参见:http://api.translate.zvo.cn/doc/translate.json.html](http://translate.zvo.cn/41164.html)
         | 
| 214 | 
            -
            * **translate.user** - [TCDN 对用户开放访问的,当在 translate admin 中添加源站,并绑定域名指向某个语种后,用户访问这个域名时,便会访问进此,有此进行网页翻译的调度、缓存的处理等。当用户第一次访问某个页面时,缓存中没有,会通过 translate api 从源站获取网页源码,然后进行翻译,将翻译之后的html源码在此进行缓存,然后返回给用户浏览器进行显示。 当有用户在此访问这个页面时,便会直接从缓存中取。](http://translate.zvo.cn/41166.html)
         | 
| 215 | 
            -
             | 
| 216 | 
            -
            其中每一个都是可以作为一个单独的项目进行使用,比如 translate.service 便可以作为文本翻译接口进行使用、translate.api 可以作为html文件翻译接口使用、translate.js 可以作为网页端直接嵌入几行js代码就能快速翻译来使用。
         | 
| 217 | 
            -
            另外像是如果你网站已经配置好,不需要在使用 translate.admin 管理后台,你可以将此停掉,从而降低服务器资源的占用。
         | 
| 218 | 
            -
             | 
| 219 192 |  | 
| 220 193 | 
             
            # 项目由来
         | 
| 221 194 | 
             
            2021年,translate 翻译服务项目创建,最初为简化Google网页翻译JS进行了封装,可以更简单进行使用,但是因为扩展极其有限,文档也没那么好,于是开始了重构。  
         | 
| @@ -275,27 +248,20 @@ tcdn是translate.js 的高级版本,它的能力是让你原本的网站可以 | |
| 275 248 | 
             
            如果您在使用过程中遇到任何异常情况,请详细说一下您遇到的问题。如果可以,请写下您的网站,以便我们可以更全面地测试,以便快速找到问题所在  
         | 
| 276 249 | 
             
            作者微信:xnx3com(使用交流可加QQ群进行,我看微信很不及时)    
         | 
| 277 250 | 
             
            Telegram : [untran](https://t.me/untran)  
         | 
| 251 | 
            +
            交流QQ群:181781514  
         | 
| 252 | 
            +
            交流QQ群:641047127  
         | 
| 278 253 | 
             
            交流QQ群:240567964  
         | 
| 279 | 
            -
             | 
| 280 | 
            -
            交流QQ群:641047127  (已满)  
         | 
| 254 | 
            +
            作者邮箱:921153866@qq.com  
         | 
| 281 255 | 
             
            微信公众号:wangmarket  
         | 
| 282 256 | 
             
            github: [https://github.com/xnx3/translate](https://github.com/xnx3/translate)  
         | 
| 283 | 
            -
            gitee:  [https://gitee.com/mail_osc/translate](https://gitee.com/mail_osc/translate)
         | 
| 284 | 
            -
             | 
| 285 | 
            -
            # 有偿帮助
         | 
| 286 | 
            -
            我们位于三线城市,各方面开发成本相对较低,如果您有临时需要技术人员帮助,欢迎联系我们,也算对我们的支持,让我们能持续下去。
         | 
| 287 | 
            -
            * Java开发,5年以上经验,65元每小时
         | 
| 288 | 
            -
            * Java开发,半年经验(主要处理琐碎杂事),25元每小时
         | 
| 289 | 
            -
            * 前端开发,3年经验(vue、uniapp、微信小程序等都可以),50元每小时
         | 
| 290 | 
            -
            * Android开发,7年经验,65元每小时
         | 
| 291 | 
            -
             | 
| 292 | 
            -
            另外,如果有别编程语言的需要,也可以喊我,我微信 xnx3com  价格绝对实在,诚信第一,不满意不要钱!!
         | 
| 257 | 
            +
            gitee:  [https://gitee.com/mail_osc/translate](https://gitee.com/mail_osc/translate)  
         | 
| 293 258 |  | 
| 294 259 |  | 
| 295 | 
            -
            #  | 
| 296 | 
            -
            * [指点云](https://www.zhidianyun.cn/?i125cc1) 赞助服务器,用于开放公共、免费API给大家使用。指点云服务器便宜,性能很不错。   
         | 
| 297 | 
            -
            * AO3读者们,赞助美国服务器,部署全球网络加速节点
         | 
| 298 | 
            -
            * 微软  提供 client.edge 方式的翻译通道
         | 
| 299 | 
            -
            *  [小牛翻译](https://niutrans.com/register?userSource=translate-js)  赞助在线翻译接口,小牛翻译提供三百八十多种语种翻译能力,需要的语种,它基本都包含了!  
         | 
| 300 | 
            -
            * [如果您想参与赞助,可点此查看更多](https://gitee.com/mail_osc/translate/issues/I7OXEQ),如果有没列出来的,您感觉可以对本项目有帮助的,也欢迎联系我的,感谢大家的支持
         | 
| 260 | 
            +
            # 商业化声明
         | 
| 301 261 |  | 
| 262 | 
            +
            我完全允许你拿我的开源项目进行商业化包装盈利,而无需给我支付任何费用!  
         | 
| 263 | 
            +
            你能拿来赚钱,那是你的本事。  
         | 
| 264 | 
            +
            而我的开源项目能帮你赚钱,我会很荣幸,我能造福社会。  
         | 
| 265 | 
            +
            你在用它进行商业化盈利的时候,遇到问题也完全可以大方的向我求助,用它赚钱并不是什么偷偷摸摸的事情,技术能用来养家糊口改善生活是值得点赞的。  
         | 
| 266 | 
            +
            而且如果你不放心,我还可以白纸黑字盖章,送你一个定心丸。  
         | 
| 267 | 
            +
            说这么多,是体现一个态度,开源就是开源,我不会想法绑架你。我们可以在一起以最纯粹的状态交流,让生活更美好。
         | 
    
        package/index.js
    CHANGED
    
    | @@ -13,8 +13,8 @@ var translate = { | |
| 13 13 | 
             
            	 * 由 npm 脚本自动更新,无需手动修改
         | 
| 14 14 | 
             
            	 * 格式:major.minor.patch.date
         | 
| 15 15 | 
             
            	 */
         | 
| 16 | 
            -
            	// AUTO_VERSION_START
         | 
| 17 | 
            -
            	version: '3. | 
| 16 | 
            +
            	// AUTO_VERSION_START
         | 
| 17 | 
            +
            	version: '3.14.0.20250326',
         | 
| 18 18 | 
             
            	// AUTO_VERSION_END
         | 
| 19 19 | 
             
            	/*
         | 
| 20 20 | 
             
            		当前使用的版本,默认使用v2. 可使用 setUseVersion2(); 
         | 
| @@ -91,6 +91,7 @@ var translate = { | |
| 91 91 | 
             
            			var selectLanguage = document.createElement("select"); 
         | 
| 92 92 | 
             
            			selectLanguage.id = translate.selectLanguageTag.documentId+'SelectLanguage';
         | 
| 93 93 | 
             
            			selectLanguage.className = translate.selectLanguageTag.documentId+'SelectLanguage';
         | 
| 94 | 
            +
            			var to = translate.language.getCurrent();
         | 
| 94 95 | 
             
            			for(var i = 0; i<languageList.length; i++){
         | 
| 95 96 | 
             
            				var option = document.createElement("option"); 
         | 
| 96 97 | 
             
            			    option.setAttribute("value",languageList[i].id);
         | 
| @@ -110,10 +111,10 @@ var translate = { | |
| 110 111 | 
             
            				}
         | 
| 111 112 |  | 
| 112 113 | 
             
            				/*判断默认要选中哪个语言*/
         | 
| 113 | 
            -
             | 
| 114 | 
            +
             | 
| 115 | 
            +
            			    if(to != null && typeof(to) != 'undefined' && to.length > 0){
         | 
| 114 116 | 
             
            					//设置了目标语言,那就进行判断显示目标语言
         | 
| 115 | 
            -
            					
         | 
| 116 | 
            -
            					if(translate.to == languageList[i].id){
         | 
| 117 | 
            +
            					if(to == languageList[i].id){
         | 
| 117 118 | 
             
            						option.setAttribute("selected",'selected');
         | 
| 118 119 | 
             
            					}
         | 
| 119 120 | 
             
            			    }else{
         | 
| @@ -341,6 +342,18 @@ var translate = { | |
| 341 342 | 
             
            		}else{
         | 
| 342 343 | 
             
            			//不用刷新,直接翻译
         | 
| 343 344 | 
             
            			translate.execute(); //翻译
         | 
| 345 | 
            +
             | 
| 346 | 
            +
            			//检测是否有iframe中的子页面,如果有,也对子页面下发翻译命令。这个是针对 LayuiAdmin 框架的场景适配,它的主体区域是在 iframe 中的,不能点击切换语言后,只翻译外面的大框,而iframe中的不翻译
         | 
| 347 | 
            +
            			const iframes = document.querySelectorAll('iframe');
         | 
| 348 | 
            +
            			for (let i = 0; i < iframes.length; i++) {
         | 
| 349 | 
            +
            				const iframe = iframes[i];
         | 
| 350 | 
            +
            				// 获取 iframe 的 window 对象
         | 
| 351 | 
            +
            				const iframeWindow = iframe.contentWindow;        
         | 
| 352 | 
            +
            				if(typeof(iframeWindow.translate) == 'object' && typeof(iframeWindow.translate.version) == 'string'){
         | 
| 353 | 
            +
            					//iframe页面中存在 translate,那么也控制iframe中的进行翻译
         | 
| 354 | 
            +
            					iframeWindow.translate.execute();
         | 
| 355 | 
            +
            				}
         | 
| 356 | 
            +
            			}
         | 
| 344 357 | 
             
            		}
         | 
| 345 358 | 
             
            	},
         | 
| 346 359 |  | 
| @@ -801,13 +814,13 @@ var translate = { | |
| 801 814 | 
             
            				k/v 
         | 
| 802 815 | 
             
            		二维:对象形态,具体有:
         | 
| 803 816 | 
             
            			 key:expireTime 当前一维数组key的过期时间,到达过期时间会自动删除掉这个一维数组。如果<0则代表永不删除,常驻内存
         | 
| 804 | 
            -
            			 value:list  | 
| 817 | 
            +
            			 value:list 从DOM中自动识别出的语言文本及节点数据,按照语种进行了划分,每个语种便是其中的一项。
         | 
| 805 818 | 
             
            		三维:针对二维的value,  key:english、chinese_simplified等语种,这里的key便是对value的判断,取value中的要翻译的词是什么语种,对其进行了语种分类    value: k/v
         | 
| 806 819 | 
             
            		四维:针对三维的value,  key:要翻译的词(经过语种分割的)的hash,   value: node数组
         | 
| 807 820 | 
             
            		五维:针对四维的value,  这是个对象, 其中
         | 
| 808 | 
            -
            				original: 是三维的key的hash | 
| 821 | 
            +
            				original: 是三维的key的hash的原始文字, node 元素中的原始文字(可能是node元素整个内容,也可能是被分割出的某一块内容,比如中英文混合时单独提取中文)
         | 
| 809 822 | 
             
            				cacheHash: 如果翻译时匹配到了自定义术语库中的词,那么翻译完后存入到缓存中时,其缓存的翻译前字符串已经不是original,而是匹配完术语库后的文本的hash了。所以这里额外多增加了这个属性。如果匹配了术语库,那这里就是要进行缓存的翻译前文本的hash,如果未使用术语库,这里就跟其key-hash 相同。
         | 
| 810 | 
            -
            				translateText: 针对 original  | 
| 823 | 
            +
            				translateText: 针对 original 的经过加工过的文字,比如经过自定义术语、以及其他处理操作后的,待进行文本翻译的文字。
         | 
| 811 824 | 
             
            				nodes: 有哪些node元素中包含了这个词,都会在这里记录
         | 
| 812 825 | 
             
            		六维:针对五维的 nodes,将各个具体的 node 以及 其操作的 attribute 以数组形式列出
         | 
| 813 826 | 
             
            		七维:针对六维列出的nodes数组,其中包含:
         | 
| @@ -882,7 +895,8 @@ var translate = { | |
| 882 895 | 
             
            					translate.listener.addListener();
         | 
| 883 896 | 
             
            				}
         | 
| 884 897 |  | 
| 885 | 
            -
            				 | 
| 898 | 
            +
            				//执行完过一次,那才能使用
         | 
| 899 | 
            +
            				//if(translate.listener.isExecuteFinish){ 
         | 
| 886 900 | 
             
            					/*if(translate.listener.isStart){
         | 
| 887 901 | 
             
            						//已开启了
         | 
| 888 902 | 
             
            						return;
         | 
| @@ -894,6 +908,53 @@ var translate = { | |
| 894 908 |  | 
| 895 909 |  | 
| 896 910 | 
             
            		},
         | 
| 911 | 
            +
            		/* 
         | 
| 912 | 
            +
            			key: nodeid node的唯一标识,格式如 HTML1_BODY1_DIV2_#text1  ,它是使用 nodeuuid.uuid(node) 获得的
         | 
| 913 | 
            +
            					注意,document.getElementById 获得的并不是,需要这样获得 document.getElementById('xx').childNodes[0]  因为它是要给监听dom改动那里用的,监听到的改动的是里面具体的node
         | 
| 914 | 
            +
            			value:13位时间戳
         | 
| 915 | 
            +
            		*/
         | 
| 916 | 
            +
            		ignoreNode:[],
         | 
| 917 | 
            +
            		/*
         | 
| 918 | 
            +
            			通过 translate.execute() 触发的翻译,来使node发生的改动,这种改动加入到 ignoreNode 的过期时间是多少。 
         | 
| 919 | 
            +
            			单位是毫秒
         | 
| 920 | 
            +
            		*/
         | 
| 921 | 
            +
            		translateExecuteNodeIgnoreExpireTime:1000,
         | 
| 922 | 
            +
            		/*
         | 
| 923 | 
            +
            		  	增加一个被listener忽略的节点
         | 
| 924 | 
            +
            		  	这里通常是用于被 translate.js 本身翻译更改的节点、以及像是 Layui 被翻译后触发了渲染改动了dom , 这几种场景都是翻译本身自己触发的,是不需要再被listener触发,不然就形成死循环了
         | 
| 925 | 
            +
            		  	node 是哪个节点被listener扫描到改动后忽略。
         | 
| 926 | 
            +
            		  		可传入 node、也可以传入node的uuid字符串
         | 
| 927 | 
            +
            		  	expireTime 过期时间,也就是执行当前方法将 node 加入后,过多长时间失效,这里是毫秒,比如传入 500 则这个node在当前时间往后的500毫秒内,如果被listener监听到改动,是直接被忽略的,不会触发任何翻译操作
         | 
| 928 | 
            +
            		 */
         | 
| 929 | 
            +
            		addIgnore:function(node, expireTime){
         | 
| 930 | 
            +
            			let nodeid = '';
         | 
| 931 | 
            +
            			if(typeof(node) == 'string'){
         | 
| 932 | 
            +
            				nodeid = node;
         | 
| 933 | 
            +
            			}else{
         | 
| 934 | 
            +
            				nodeid = nodeuuid.uuid(node);
         | 
| 935 | 
            +
            			}
         | 
| 936 | 
            +
             | 
| 937 | 
            +
            			translate.listener.ignoreNode[nodeid] = Date.now()+expireTime;
         | 
| 938 | 
            +
             | 
| 939 | 
            +
            			//translate.listener.renderTaskFinish();
         | 
| 940 | 
            +
            		},
         | 
| 941 | 
            +
            		/*
         | 
| 942 | 
            +
            			刷新 ignoreNode 中的元素,也就是查找其中 expireTime 过期的,删掉
         | 
| 943 | 
            +
            		*/
         | 
| 944 | 
            +
            		refreshIgnoreNode:function(){
         | 
| 945 | 
            +
            			//console.log('refresh ignore ,current: '+Object.keys(translate.listener.ignoreNode).length);
         | 
| 946 | 
            +
            			var currentTime = Date.now();
         | 
| 947 | 
            +
            			for (const node in translate.listener.ignoreNode) {
         | 
| 948 | 
            +
            				if(translate.listener.ignoreNode[node] < currentTime){
         | 
| 949 | 
            +
            					//console.log('delete : ');
         | 
| 950 | 
            +
            					//console.log(node);
         | 
| 951 | 
            +
            					delete translate.listener.ignoreNode[node];
         | 
| 952 | 
            +
            				}
         | 
| 953 | 
            +
            			}
         | 
| 954 | 
            +
            			//console.log('refresh ignore finish: '+Object.keys(translate.listener.ignoreNode).length);
         | 
| 955 | 
            +
            		},
         | 
| 956 | 
            +
             | 
| 957 | 
            +
             | 
| 897 958 | 
             
            		//增加监听,开始监听。这个不要直接调用,需要使用上面的 start() 开启
         | 
| 898 959 | 
             
            		addListener:function(){
         | 
| 899 960 | 
             
            			translate.listener.isStart = true; //记录已执行过启动方法了
         | 
| @@ -953,12 +1014,12 @@ var translate = { | |
| 953 1014 | 
             
            					//判断是否属于在正在翻译的节点,重新组合出新的要翻译的node集合
         | 
| 954 1015 | 
             
            					var translateNodes = [];
         | 
| 955 1016 | 
             
            					//console.log(translate.inProgressNodes.length);
         | 
| 956 | 
            -
            					for(let  | 
| 957 | 
            -
            						//console.log('---type:'+ | 
| 1017 | 
            +
            					for(let node of documents){
         | 
| 1018 | 
            +
            						//console.log('---type:'+node.nodeType);
         | 
| 958 1019 |  | 
| 959 1020 | 
             
            						var find = false;
         | 
| 960 1021 | 
             
            						for(var ini = 0; ini < translate.inProgressNodes.length; ini++){
         | 
| 961 | 
            -
            							if(translate.inProgressNodes[ini].node.isSameNode( | 
| 1022 | 
            +
            							if(translate.inProgressNodes[ini].node.isSameNode(node)){
         | 
| 962 1023 | 
             
            								//有记录了,那么忽略这个node,这个node是因为翻译才导致的变动
         | 
| 963 1024 | 
             
            								//console.log('发现相同');
         | 
| 964 1025 | 
             
            								find = true;
         | 
| @@ -969,10 +1030,19 @@ var translate = { | |
| 969 1030 | 
             
            							continue;
         | 
| 970 1031 | 
             
            						}
         | 
| 971 1032 |  | 
| 1033 | 
            +
            						//console.log(node);
         | 
| 1034 | 
            +
            						let nodeid = nodeuuid.uuid(node);
         | 
| 1035 | 
            +
            						if(typeof(translate.listener.ignoreNode[nodeid]) == 'number'){
         | 
| 1036 | 
            +
            							if(translate.listener.ignoreNode[nodeid] > Date.now()){
         | 
| 1037 | 
            +
            								//console.log('node 未过忽略期,listener扫描后忽略:'+nodeid);
         | 
| 1038 | 
            +
            								continue;
         | 
| 1039 | 
            +
            							}
         | 
| 1040 | 
            +
            						}
         | 
| 1041 | 
            +
             | 
| 972 1042 | 
             
            						//不相同,才追加到新的 translateNodes
         | 
| 973 | 
            -
            						translateNodes.push( | 
| 974 | 
            -
            						//console.log('listener ++ '+ | 
| 975 | 
            -
            						//console.log( | 
| 1043 | 
            +
            						translateNodes.push(node);
         | 
| 1044 | 
            +
            						//console.log('listener ++ '+node.nodeValue);
         | 
| 1045 | 
            +
            						//console.log(node);
         | 
| 976 1046 | 
             
            					}
         | 
| 977 1047 | 
             
            					if(translateNodes.length < 1){
         | 
| 978 1048 | 
             
            						return;
         | 
| @@ -1004,7 +1074,45 @@ var translate = { | |
| 1004 1074 | 
             
            		*/
         | 
| 1005 1075 | 
             
            		renderTaskFinish:function(renderTask){
         | 
| 1006 1076 | 
             
            			//console.log(renderTask);
         | 
| 1007 | 
            -
            		}
         | 
| 1077 | 
            +
            		},
         | 
| 1078 | 
            +
             | 
| 1079 | 
            +
            		/*
         | 
| 1080 | 
            +
                        翻译执行过程中,相关的监控
         | 
| 1081 | 
            +
                    */
         | 
| 1082 | 
            +
                    execute:{
         | 
| 1083 | 
            +
             | 
| 1084 | 
            +
                        /*
         | 
| 1085 | 
            +
                            每当触发执行 translate.execute() 时,当缓存中未发现,需要请求翻译API进行翻译时,在发送API请求前,触发此
         | 
| 1086 | 
            +
                        */
         | 
| 1087 | 
            +
                        renderStartByApi : [],
         | 
| 1088 | 
            +
                        renderStartByApiRun:function(uuid){
         | 
| 1089 | 
            +
                            //console.log(translate.nodeQueue[uuid]);
         | 
| 1090 | 
            +
                            for(var i = 0; i < translate.listener.execute.renderStartByApi.length; i++){
         | 
| 1091 | 
            +
                                try{
         | 
| 1092 | 
            +
                                    translate.listener.execute.renderStartByApi[i](uuid);
         | 
| 1093 | 
            +
                                }catch(e){
         | 
| 1094 | 
            +
                                    console.log(e);
         | 
| 1095 | 
            +
                                }
         | 
| 1096 | 
            +
                            }
         | 
| 1097 | 
            +
                        },
         | 
| 1098 | 
            +
             | 
| 1099 | 
            +
                        /*
         | 
| 1100 | 
            +
                            每当 translate.execute() 执行完毕(前提是采用API翻译的,API将翻译结果返回,并且界面上的翻译结果也已经渲染完毕)后,触发此方法。
         | 
| 1101 | 
            +
                            uuid:translate.nodeQueue[uuid] 这里的
         | 
| 1102 | 
            +
                        */
         | 
| 1103 | 
            +
                        renderFinishByApi : [],
         | 
| 1104 | 
            +
                        renderFinishByApiRun:function(uuid){
         | 
| 1105 | 
            +
                            //console.log(translate.nodeQueue[uuid]);
         | 
| 1106 | 
            +
                            for(var i = 0; i < translate.listener.execute.renderFinishByApi.length; i++){
         | 
| 1107 | 
            +
                                try{
         | 
| 1108 | 
            +
                                    translate.listener.execute.renderFinishByApi[i](uuid);
         | 
| 1109 | 
            +
                                }catch(e){
         | 
| 1110 | 
            +
                                    console.log(e);
         | 
| 1111 | 
            +
                                }
         | 
| 1112 | 
            +
                            }
         | 
| 1113 | 
            +
                        }
         | 
| 1114 | 
            +
                    }
         | 
| 1115 | 
            +
             | 
| 1008 1116 | 
             
            	},
         | 
| 1009 1117 | 
             
            	//对翻译结果进行替换渲染的任务,将待翻译内容替换为翻译内容的过程
         | 
| 1010 1118 | 
             
            	renderTask:class{
         | 
| @@ -1104,6 +1212,9 @@ var translate = { | |
| 1104 1212 | 
             
            			//console.log(this.nodes);
         | 
| 1105 1213 | 
             
            			//console.log('===========task======end===');
         | 
| 1106 1214 |  | 
| 1215 | 
            +
            			//进行翻译前,先刷新一下 dom监听的忽略node,将过期的node剔除,降低listener的压力
         | 
| 1216 | 
            +
            			translate.listener.refreshIgnoreNode();
         | 
| 1217 | 
            +
             | 
| 1107 1218 | 
             
            			//对nodeQueue进行翻译
         | 
| 1108 1219 | 
             
            			for(var hash in this.nodes){
         | 
| 1109 1220 | 
             
            				var tasks = this.taskQueue[hash]; //取出当前node元素对应的替换任务
         | 
| @@ -1141,6 +1252,8 @@ var translate = { | |
| 1141 1252 |  | 
| 1142 1253 | 
             
            						}, 50, ipnode);
         | 
| 1143 1254 |  | 
| 1255 | 
            +
            						//加入 translate.listener.ignoreNode
         | 
| 1256 | 
            +
            						translate.listener.addIgnore(this.nodes[hash][task_index], translate.listener.translateExecuteNodeIgnoreExpireTime);
         | 
| 1144 1257 | 
             
            						translate.element.nodeAnalyse.set(this.nodes[hash][task_index], task.originalText, task.resultText, task['attribute']);
         | 
| 1145 1258 |  | 
| 1146 1259 |  | 
| @@ -1291,7 +1404,6 @@ var translate = { | |
| 1291 1404 | 
             
            		},
         | 
| 1292 1405 | 
             
            		//当前 translate.translateRequest[uuid] 的是否已经全部执行完毕,这里单纯只是对 translate.translateRequest[uuid] 的进行判断,这里要在 translate.json 接口触发完并渲染完毕后触发,当然接口失败时也要触发
         | 
| 1293 1406 | 
             
            		isAllExecuteFinish:function(uuid){
         | 
| 1294 | 
            -
            			
         | 
| 1295 1407 | 
             
            			for(var lang in translate.translateRequest[uuid]){
         | 
| 1296 1408 | 
             
            				for(var i = 0; i<translate.translateRequest[uuid][lang].length; i++){
         | 
| 1297 1409 | 
             
            					if(translate.translateRequest[uuid][lang][i].executeFinish == 0){
         | 
| @@ -1308,13 +1420,16 @@ var translate = { | |
| 1308 1420 | 
             
            			//都执行完了,那么设置完毕
         | 
| 1309 1421 | 
             
            			translate.state = 0;
         | 
| 1310 1422 | 
             
            			translate.executeNumber++;
         | 
| 1423 | 
            +
             | 
| 1424 | 
            +
            			translate.listener.execute.renderFinishByApiRun(uuid);
         | 
| 1311 1425 | 
             
            		}
         | 
| 1312 1426 |  | 
| 1313 1427 | 
             
            	},
         | 
| 1314 1428 |  | 
| 1315 1429 | 
             
            	//execute() 方法已经被执行过多少次了, 只有execute() 完全执行完,也就是界面渲染完毕后,它才会+1
         | 
| 1316 1430 | 
             
            	executeNumber:0,
         | 
| 1317 | 
            -
             | 
| 1431 | 
            +
            	
         | 
| 1432 | 
            +
            	/*translate.execute() start */
         | 
| 1318 1433 | 
             
            	/*
         | 
| 1319 1434 | 
             
            		执行翻译操作。翻译的是 nodeQueue 中的
         | 
| 1320 1435 | 
             
            		docs 如果传入,那么翻译的只是传入的这个docs的。传入如 [document.getElementById('xxx'),document.getElementById('xxx'),...]
         | 
| @@ -1881,7 +1996,8 @@ var translate = { | |
| 1881 1996 | 
             
            		//状态
         | 
| 1882 1997 | 
             
            		translate.state = 20;
         | 
| 1883 1998 |  | 
| 1884 | 
            -
             | 
| 1999 | 
            +
            		//listener
         | 
| 2000 | 
            +
                    translate.listener.execute.renderStartByApiRun(uuid);
         | 
| 1885 2001 |  | 
| 1886 2002 | 
             
            		//进行掉接口翻译
         | 
| 1887 2003 | 
             
            		for(var lang_index in fanyiLangs){ //一维数组,取语言
         | 
| @@ -1915,7 +2031,7 @@ var translate = { | |
| 1915 2031 | 
             
            			var data = {
         | 
| 1916 2032 | 
             
            				from:lang,
         | 
| 1917 2033 | 
             
            				to:translate.to,
         | 
| 1918 | 
            -
            				lowercase:translate.whole.isEnableAll? '0':'1', //首字母大写
         | 
| 2034 | 
            +
            				//lowercase:translate.whole.isEnableAll? '0':'1', //首字母大写
         | 
| 1919 2035 | 
             
            				//text:JSON.stringify(translateTextArray[lang])
         | 
| 1920 2036 | 
             
            				text:encodeURIComponent(JSON.stringify(translateTextArray[lang]))
         | 
| 1921 2037 | 
             
            			};
         | 
| @@ -1924,18 +2040,21 @@ var translate = { | |
| 1924 2040 | 
             
            				//console.log(data); 
         | 
| 1925 2041 | 
             
            				//console.log(translateTextArray[data.from]);
         | 
| 1926 2042 | 
             
            				if(data.result == 0){
         | 
| 1927 | 
            -
            					translate.translateRequest[uuid][ | 
| 1928 | 
            -
             | 
| 1929 | 
            -
             | 
| 1930 | 
            -
             | 
| 2043 | 
            +
            					if(typeof(translate.translateRequest[uuid]) == 'object' && typeof(translate.translateRequest[uuid][data.from]) == 'object'){
         | 
| 2044 | 
            +
            						translate.translateRequest[uuid][data.from]['result'] = 2;
         | 
| 2045 | 
            +
            						translate.translateRequest[uuid][data.from].executeFinish = 1; //1是执行完毕
         | 
| 2046 | 
            +
            						translate.translateRequest[uuid][data.from].stoptime = Math.floor(Date.now() / 1000);
         | 
| 2047 | 
            +
            					}else{
         | 
| 2048 | 
            +
            						console.log('WARINNG!!! translate.translateRequest[uuid][data.from] is not object');
         | 
| 2049 | 
            +
            					}
         | 
| 2050 | 
            +
            					
         | 
| 2051 | 
            +
            					translate.waitingExecute.isAllExecuteFinish(uuid);
         | 
| 1931 2052 | 
             
            					console.log('=======ERROR START=======');
         | 
| 1932 2053 | 
             
            					console.log(translateTextArray[data.from]);
         | 
| 1933 2054 | 
             
            					//console.log(encodeURIComponent(JSON.stringify(translateTextArray[data.from])));
         | 
| 1934 | 
            -
            					
         | 
| 1935 2055 | 
             
            					console.log('response : '+data.info);
         | 
| 1936 2056 | 
             
            					console.log('=======ERROR END  =======');
         | 
| 1937 2057 | 
             
            					//translate.temp_executeFinishNumber++; //记录执行完的次数
         | 
| 1938 | 
            -
             | 
| 1939 2058 | 
             
            					return;
         | 
| 1940 2059 | 
             
            				}
         | 
| 1941 2060 |  | 
| @@ -2007,16 +2126,19 @@ var translate = { | |
| 2007 2126 | 
             
            				translate.translateRequest[uuid][lang].result = 1;
         | 
| 2008 2127 | 
             
            				translate.translateRequest[uuid][lang].executeFinish = 1; //1是执行完毕
         | 
| 2009 2128 | 
             
            				translate.translateRequest[uuid][lang].stoptime = Math.floor(Date.now() / 1000);
         | 
| 2010 | 
            -
            				 | 
| 2129 | 
            +
            				setTimeout(function(){
         | 
| 2130 | 
            +
            					translate.waitingExecute.isAllExecuteFinish(uuid);
         | 
| 2131 | 
            +
            				},10);
         | 
| 2011 2132 | 
             
            			}, function(xhr){
         | 
| 2012 2133 | 
             
            				translate.translateRequest[uuid][lang].executeFinish = 1; //1是执行完毕
         | 
| 2013 2134 | 
             
            				translate.translateRequest[uuid][lang].stoptime = Math.floor(Date.now() / 1000);
         | 
| 2014 2135 | 
             
            				translate.translateRequest[uuid][lang].result = 3;
         | 
| 2015 | 
            -
            				translate.waitingExecute.isAllExecuteFinish();
         | 
| 2136 | 
            +
            				translate.waitingExecute.isAllExecuteFinish(uuid);
         | 
| 2016 2137 | 
             
            			});
         | 
| 2017 2138 | 
             
            			/*** 翻译end ***/
         | 
| 2018 2139 | 
             
            		}
         | 
| 2019 2140 | 
             
            	},
         | 
| 2141 | 
            +
            	/*translate.execute() end */
         | 
| 2020 2142 |  | 
| 2021 2143 | 
             
            	/**
         | 
| 2022 2144 | 
             
            	 * 翻译请求记录
         | 
| @@ -3438,6 +3560,7 @@ var translate = { | |
| 3438 3560 | 
             
            			number 阿拉伯数字
         | 
| 3439 3561 | 
             
            			japanese 日语
         | 
| 3440 3562 | 
             
            			korean 韩语
         | 
| 3563 | 
            +
            			greek 希腊语
         | 
| 3441 3564 | 
             
            		*/
         | 
| 3442 3565 | 
             
            		getCharLanguage:function(charstr){
         | 
| 3443 3566 | 
             
            			if(charstr == null || typeof(charstr) == 'undefined'){
         | 
| @@ -3474,6 +3597,9 @@ var translate = { | |
| 3474 3597 | 
             
            			if(this.korean(charstr)){
         | 
| 3475 3598 | 
             
            				return 'korean';
         | 
| 3476 3599 | 
             
            			}
         | 
| 3600 | 
            +
            			if(this.greek(charstr)){
         | 
| 3601 | 
            +
            				return 'greek';
         | 
| 3602 | 
            +
            			}
         | 
| 3477 3603 |  | 
| 3478 3604 | 
             
            			//未识别是什么语种
         | 
| 3479 3605 | 
             
            			//console.log('not find is language , char : '+charstr+', unicode: '+charstr.charCodeAt(0).toString(16));
         | 
| @@ -3805,6 +3931,16 @@ var translate = { | |
| 3805 3931 | 
             
            				return false;
         | 
| 3806 3932 | 
             
            			}
         | 
| 3807 3933 | 
             
            		},
         | 
| 3934 | 
            +
            		//是否包含希腊语
         | 
| 3935 | 
            +
            		greek:function(str){
         | 
| 3936 | 
            +
            			const greekRegex = /^[\u0391-\u03A9\u03B1-\u03C9]$/;
         | 
| 3937 | 
            +
            			//判断字符有  БВДЖЗИЙЛМНОПСТУФХЦЧШЩЪЫЬЮЯЇІ
         | 
| 3938 | 
            +
            			if(/^[\u0391-\u03A9\u03B1-\u03C9]$/.test(str)){ 
         | 
| 3939 | 
            +
            				return true
         | 
| 3940 | 
            +
            			} else {
         | 
| 3941 | 
            +
            				return false;
         | 
| 3942 | 
            +
            			}
         | 
| 3943 | 
            +
            		},
         | 
| 3808 3944 | 
             
            		//0-9 阿拉伯数字
         | 
| 3809 3945 | 
             
            		number:function(str){
         | 
| 3810 3946 | 
             
            			if(/.*[\u0030-\u0039]+.*$/.test(str)){
         | 
| @@ -3878,6 +4014,7 @@ var translate = { | |
| 3878 4014 |  | 
| 3879 4015 | 
             
            		    return maxLang || ''; 
         | 
| 3880 4016 | 
             
            		},
         | 
| 4017 | 
            +
            		/**romanceSentenceAnaly end**/
         | 
| 3881 4018 |  | 
| 3882 4019 | 
             
            		//是否包含特殊字符,包含,则是true
         | 
| 3883 4020 | 
             
            		specialCharacter:function(str){
         | 
| @@ -4103,7 +4240,72 @@ var translate = { | |
| 4103 4240 |  | 
| 4104 4241 |  | 
| 4105 4242 | 
             
            			return false;
         | 
| 4106 | 
            -
            		}
         | 
| 4243 | 
            +
            		},
         | 
| 4244 | 
            +
            		/*
         | 
| 4245 | 
            +
                        文本翻译的替换。
         | 
| 4246 | 
            +
             | 
| 4247 | 
            +
                        
         | 
| 4248 | 
            +
                        text: 原始文本,翻译的某句或者某个词就在这个文本之中
         | 
| 4249 | 
            +
                        translateOriginal: 翻译的某个词或句,在翻译之前的文本
         | 
| 4250 | 
            +
                        translateResult: 翻译的某个词或句,在翻译之后的文本,翻译结果
         | 
| 4251 | 
            +
                        language: 显示的语种,这里是对应的 translateResult 这个文本的语种。 也就是最终替换之后要显示给用户的语种。比如将中文翻译为英文,这里也就是英文。 这里会根据显示的语种不同,来自主决定是否前后加空格进行分割。 另外这里传入的语种也是 translate.js 的语种标识
         | 
| 4252 | 
            +
                    	
         | 
| 4253 | 
            +
                    	(注意,如果 translateResult 中发现 translateOriginal 的存在,将不进行任何处理,因为没必要了,还会造成死循环。直接将 text 返回)
         | 
| 4254 | 
            +
            			
         | 
| 4255 | 
            +
            			使用此方法:
         | 
| 4256 | 
            +
            			var text = '你世好word世界';
         | 
| 4257 | 
            +
            			var translateOriginal = '世';
         | 
| 4258 | 
            +
            			var translateResult = 'shi'; //翻译结果
         | 
| 4259 | 
            +
            			translate.language.textTranslateReplace(text, translateOriginal, translateResult, 'english');
         | 
| 4260 | 
            +
             | 
| 4261 | 
            +
                    */
         | 
| 4262 | 
            +
                    textTranslateReplace:function(text, translateOriginal, translateResult, language){
         | 
| 4263 | 
            +
                    	if(translateResult.indexOf(translateOriginal) > -1){
         | 
| 4264 | 
            +
                    		return text;
         | 
| 4265 | 
            +
                    	}
         | 
| 4266 | 
            +
             | 
| 4267 | 
            +
             | 
| 4268 | 
            +
                        let replaceResultText = ''+translateResult; //要替换的结果文本(这个文本可能前面有加空格或者后面有加空格的)
         | 
| 4269 | 
            +
             | 
| 4270 | 
            +
                        if(translate.language.wordBlankConnector(translate.to)){
         | 
| 4271 | 
            +
                            let originalIndex = text.indexOf(translateOriginal); //翻译之前,翻译的单词在字符串中的其实坐标(0开始)
         | 
| 4272 | 
            +
                            //console.log("originalIndex: "+originalIndex);
         | 
| 4273 | 
            +
             | 
| 4274 | 
            +
                            //要先判断后面,不然先判断前面,加了后它的长度就又变了
         | 
| 4275 | 
            +
             | 
| 4276 | 
            +
                            //判断它后面是否还有文本
         | 
| 4277 | 
            +
                            if(originalIndex+1 < text.length){
         | 
| 4278 | 
            +
                                let char = text.charAt(originalIndex+translateOriginal.length);
         | 
| 4279 | 
            +
                                //console.log(char);
         | 
| 4280 | 
            +
                                if(!(/\s/.test(char))){
         | 
| 4281 | 
            +
                                    //不是空白字符,补充上一个空格,用于将两个单词隔开
         | 
| 4282 | 
            +
                                    //text = text.replace(translateOriginal, translateResult+' ');
         | 
| 4283 | 
            +
                                    replaceResultText = replaceResultText + ' ';
         | 
| 4284 | 
            +
                                }
         | 
| 4285 | 
            +
                            }
         | 
| 4286 | 
            +
             | 
| 4287 | 
            +
                            //判断它前面是否还有文本
         | 
| 4288 | 
            +
                            if(originalIndex > 0){
         | 
| 4289 | 
            +
                                let char = text.charAt(originalIndex-1);
         | 
| 4290 | 
            +
                                //console.log(char);
         | 
| 4291 | 
            +
                                if(!(/\s/.test(char))){
         | 
| 4292 | 
            +
                                    //不是空白字符,补充上一个空格,用于将两个单词隔开
         | 
| 4293 | 
            +
                                    //text = text.replace(translateOriginal, ' '+translateResult);
         | 
| 4294 | 
            +
                                    replaceResultText = ' '+replaceResultText;
         | 
| 4295 | 
            +
                                }
         | 
| 4296 | 
            +
                            }
         | 
| 4297 | 
            +
                        }
         | 
| 4298 | 
            +
                        let resultText = text.replace(translateOriginal, replaceResultText);
         | 
| 4299 | 
            +
                        
         | 
| 4300 | 
            +
                        if(resultText.indexOf(translateOriginal) > -1){
         | 
| 4301 | 
            +
                        	//还有第二个、第三个单词一样,也要替换
         | 
| 4302 | 
            +
                        	//console.log(this);
         | 
| 4303 | 
            +
            				resultText = this.textTranslateReplace(resultText, translateOriginal, translateResult, language);
         | 
| 4304 | 
            +
                        }
         | 
| 4305 | 
            +
             | 
| 4306 | 
            +
                        //console.log(resultText);
         | 
| 4307 | 
            +
                        return resultText;
         | 
| 4308 | 
            +
                    }
         | 
| 4107 4309 | 
             
            	},
         | 
| 4108 4310 | 
             
            	//用户第一次打开网页时,自动判断当前用户所在国家使用的是哪种语言,来自动进行切换为用户所在国家的语种。
         | 
| 4109 4311 | 
             
            	//如果使用后,第二次在用,那就优先以用户所选择的为主
         | 
| @@ -4305,6 +4507,7 @@ var translate = { | |
| 4305 4507 | 
             
            		objSort:function(obj){
         | 
| 4306 4508 | 
             
            			// 获取对象数组的所有 key,并转换为普通数组
         | 
| 4307 4509 | 
             
            			var keys = Array.from(Object.keys(obj));
         | 
| 4510 | 
            +
            			//var keys = [].slice.call(Object.keys(obj)); //适配es5
         | 
| 4308 4511 |  | 
| 4309 4512 | 
             
            			// 对 key 数组进行排序
         | 
| 4310 4513 | 
             
            			keys.sort(function(a, b){
         | 
| @@ -4674,6 +4877,44 @@ var translate = { | |
| 4674 4877 |  | 
| 4675 4878 | 
             
            			//将其转化为  translate.js 的语言id,比如简体中文是 chinese_simplified 、 英语是 english
         | 
| 4676 4879 | 
             
            			return '';
         | 
| 4880 | 
            +
            		},
         | 
| 4881 | 
            +
            		/*
         | 
| 4882 | 
            +
            			对输入的文本 text 进行判断,判断它里面是否有url存在。如果有url存在,对其进行截取,将url跟非url进行截取处理。
         | 
| 4883 | 
            +
            			比如传入 “这个示例:https://www.ungm.org/Public/Notice/261001,其他得示例是 http://api.translate.zvo.cn 我呢”
         | 
| 4884 | 
            +
            			那么返回的截取结果为:
         | 
| 4885 | 
            +
            			{
         | 
| 4886 | 
            +
            				"https://www.ungm.org/Public/Notice/261001":"1",
         | 
| 4887 | 
            +
            				"http://api.translate.zvo.cn":"1",
         | 
| 4888 | 
            +
            				",其他得示例是 ":"0",
         | 
| 4889 | 
            +
            				"这个示例:":"0"
         | 
| 4890 | 
            +
            				" 我呢":"0"
         | 
| 4891 | 
            +
            			}
         | 
| 4892 | 
            +
            			其中的key 为截取的文本,value 的值是1或0, 1代表当前key的文本是网址,0则不是网址  
         | 
| 4893 | 
            +
            		*/
         | 
| 4894 | 
            +
            		urlSplitByText:function(text){
         | 
| 4895 | 
            +
            			// 匹配 http/https 的 URL 正则表达式(包含常见 URL 符号,排除中文等非 ASCII 字符)
         | 
| 4896 | 
            +
            			const urlRegex = /(https?:\/\/[\w\-._~:\/?#[\]@!$&'()*+;=%]+(?=[\s\u4e00-\u9fa5,。;,!?]|$))/gi;
         | 
| 4897 | 
            +
             | 
| 4898 | 
            +
            			// 使用正则表达式分割文本,保留URL
         | 
| 4899 | 
            +
            			const parts = text.split(urlRegex);
         | 
| 4900 | 
            +
             | 
| 4901 | 
            +
            			// 结果对象
         | 
| 4902 | 
            +
            			let result = {};
         | 
| 4903 | 
            +
             | 
| 4904 | 
            +
            			// 添加非URL部分,并标记为 0
         | 
| 4905 | 
            +
            			for (let i = 0; i < parts.length; i++) {
         | 
| 4906 | 
            +
            				if (i % 2 === 0) {
         | 
| 4907 | 
            +
            					// 非URL部分
         | 
| 4908 | 
            +
            					if (parts[i] !== "") {
         | 
| 4909 | 
            +
            						result[parts[i]] = "0";
         | 
| 4910 | 
            +
            					}
         | 
| 4911 | 
            +
            				} else {
         | 
| 4912 | 
            +
            					// URL部分
         | 
| 4913 | 
            +
            					result[parts[i]] = "1";
         | 
| 4914 | 
            +
            				}
         | 
| 4915 | 
            +
            			}
         | 
| 4916 | 
            +
             | 
| 4917 | 
            +
            			return result;
         | 
| 4677 4918 | 
             
            		}
         | 
| 4678 4919 | 
             
            	},
         | 
| 4679 4920 | 
             
            	//机器翻译采用哪种翻译服务
         | 
| @@ -4915,14 +5156,13 @@ var translate = { | |
| 4915 5156 | 
             
            					if(storage_hostQueue == null || typeof(storage_hostQueue) == 'undefined'){
         | 
| 4916 5157 | 
             
            						//本地存储中没有,也就是之前没设置过,是第一次用,那么直接讲 translate.request.api.host 赋予之
         | 
| 4917 5158 | 
             
            						//translate.request.api.host
         | 
| 4918 | 
            -
             | 
| 5159 | 
            +
            				
         | 
| 4919 5160 | 
             
            						if(typeof(translate.request.api.host) == 'string'){
         | 
| 4920 5161 | 
             
            							//单个,那么赋予数组形式
         | 
| 4921 5162 | 
             
            							//translate.request.speedDetectionControl.hostQueue = [{"host":translate.request.api.host, time:0 }];
         | 
| 4922 5163 | 
             
            							translate.request.api.host = [''+translate.request.api.host];
         | 
| 4923 5164 | 
             
            						}
         | 
| 4924 5165 |  | 
| 4925 | 
            -
            						//console.log(translate.request.api.host)
         | 
| 4926 5166 | 
             
            						//数组形态,多个,v2.8.2 增加多个,根据优先级返回
         | 
| 4927 5167 | 
             
            						translate.request.speedDetectionControl.hostQueue = [];
         | 
| 4928 5168 | 
             
            						for(var i = 0; i<translate.request.api.host.length; i++){
         | 
| @@ -5790,7 +6030,6 @@ var translate = { | |
| 5790 6030 | 
             
            			return;
         | 
| 5791 6031 | 
             
            		}
         | 
| 5792 6032 | 
             
            		translate.init_execute = '已进行';
         | 
| 5793 | 
            -
             | 
| 5794 6033 | 
             
            		try{
         | 
| 5795 6034 | 
             
            			translate.request.send(
         | 
| 5796 6035 | 
             
            				translate.request.api.init,
         | 
| @@ -5822,8 +6061,215 @@ var translate = { | |
| 5822 6061 | 
             
            			);
         | 
| 5823 6062 | 
             
            		}catch(e){
         | 
| 5824 6063 | 
             
            		}
         | 
| 5825 | 
            -
            	}
         | 
| 6064 | 
            +
            	},
         | 
| 6065 | 
            +
             | 
| 6066 | 
            +
            	/*
         | 
| 6067 | 
            +
            		翻译执行的进展相关
         | 
| 6068 | 
            +
            		比如,浏览器本地缓存没有,需要走API接口的文本所在的元素区域,出现 记载中的动画蒙版,给用户以友好的使用提示
         | 
| 6069 | 
            +
            	*/
         | 
| 6070 | 
            +
            	progress:{
         | 
| 6071 | 
            +
            		/*
         | 
| 6072 | 
            +
            			通过文本翻译API进行的
         | 
| 6073 | 
            +
            		 */
         | 
| 6074 | 
            +
            		api:{
         | 
| 6075 | 
            +
            			isTip:true,//是否显示ui的提示,true显示,false不显示
         | 
| 6076 | 
            +
            			setUITip:function(tip){
         | 
| 6077 | 
            +
            				translate.progress.api.isTip = tip;
         | 
| 6078 | 
            +
            			},
         | 
| 6079 | 
            +
            			startUITip:function(){
         | 
| 6080 | 
            +
            				// 创建一个 style 元素
         | 
| 6081 | 
            +
            		        const style = document.createElement('style');
         | 
| 6082 | 
            +
            		        // 设置 style 元素的文本内容为要添加的 CSS 规则
         | 
| 6083 | 
            +
            		       	style.textContent = `
         | 
| 6084 | 
            +
            					/* CSS部分 */
         | 
| 6085 | 
            +
            					/* 灰色水平加载动画 */
         | 
| 6086 | 
            +
            					.translate_api_in_progress {
         | 
| 6087 | 
            +
            					  position: relative;
         | 
| 6088 | 
            +
            					  overflow: hidden; /* 隐藏超出部分的动画 */
         | 
| 6089 | 
            +
            					}
         | 
| 6090 | 
            +
             | 
| 6091 | 
            +
            					/* 蒙版层 */
         | 
| 6092 | 
            +
            					.translate_api_in_progress::after {
         | 
| 6093 | 
            +
            					  content: '';
         | 
| 6094 | 
            +
            					  position: absolute;
         | 
| 6095 | 
            +
            					  top: 0;
         | 
| 6096 | 
            +
            					  left: 0;
         | 
| 6097 | 
            +
            					  width: 100%;
         | 
| 6098 | 
            +
            					  height: 100%;
         | 
| 6099 | 
            +
            					  background: rgba(255, 255, 255, 1); /* 半透明白色遮罩 */
         | 
| 6100 | 
            +
            					  z-index: 2;
         | 
| 6101 | 
            +
            					}
         | 
| 5826 6102 |  | 
| 6103 | 
            +
            					/* 水平加载条动画 */
         | 
| 6104 | 
            +
            					.translate_api_in_progress::before {
         | 
| 6105 | 
            +
            					  content: '';
         | 
| 6106 | 
            +
            					  position: absolute;
         | 
| 6107 | 
            +
            					  top: 50%;
         | 
| 6108 | 
            +
            					  left: 0;
         | 
| 6109 | 
            +
            					  width: 100%;
         | 
| 6110 | 
            +
            					  height:100%; /* 细线高度 */
         | 
| 6111 | 
            +
            					  background: linear-gradient(
         | 
| 6112 | 
            +
            					    90deg,
         | 
| 6113 | 
            +
            					    transparent 0%,
         | 
| 6114 | 
            +
            					    #e8e8e8 25%,  /* 浅灰色 */
         | 
| 6115 | 
            +
            					    #d0d0d0 50%,  /* 中灰色 */
         | 
| 6116 | 
            +
            					    #e8e8e8 75%,  /* 浅灰色 */
         | 
| 6117 | 
            +
            					    transparent 100%
         | 
| 6118 | 
            +
            					  );
         | 
| 6119 | 
            +
            					  background-size: 200% 100%;
         | 
| 6120 | 
            +
            					  animation: translate_api_in_progress_horizontal-loader 3.5s linear infinite;
         | 
| 6121 | 
            +
            					  z-index: 3;
         | 
| 6122 | 
            +
            					  transform: translateY(-50%);
         | 
| 6123 | 
            +
            					}
         | 
| 6124 | 
            +
             | 
| 6125 | 
            +
            					@keyframes translate_api_in_progress_horizontal-loader {
         | 
| 6126 | 
            +
            					  0% {
         | 
| 6127 | 
            +
            					    background-position: 200% 0;
         | 
| 6128 | 
            +
            					  }
         | 
| 6129 | 
            +
            					  100% {
         | 
| 6130 | 
            +
            					    background-position: -200% 0;
         | 
| 6131 | 
            +
            					  }
         | 
| 6132 | 
            +
            					}
         | 
| 6133 | 
            +
            				`;
         | 
| 6134 | 
            +
            		        // 将 style 元素插入到 head 元素中
         | 
| 6135 | 
            +
            		        document.head.appendChild(style);
         | 
| 6136 | 
            +
             | 
| 6137 | 
            +
             | 
| 6138 | 
            +
            				if(translate.progress.api.isTip){
         | 
| 6139 | 
            +
            					translate.listener.execute.renderStartByApi.push(function(uuid){
         | 
| 6140 | 
            +
            					    for(var lang in translate.nodeQueue[uuid].list){
         | 
| 6141 | 
            +
            						    if(translate.language.getCurrent() == lang){
         | 
| 6142 | 
            +
            						        //忽略这个语种
         | 
| 6143 | 
            +
            						        continue;
         | 
| 6144 | 
            +
            						    }
         | 
| 6145 | 
            +
            						    for(var hash in translate.nodeQueue[uuid].list[lang]){
         | 
| 6146 | 
            +
            						    	for(var nodeindex in translate.nodeQueue[uuid].list[lang][hash].nodes){
         | 
| 6147 | 
            +
            						    		var node = translate.nodeQueue[uuid].list[lang][hash].nodes[nodeindex].node;
         | 
| 6148 | 
            +
            						    		var nodeParent = node.parentNode;
         | 
| 6149 | 
            +
            							        if(nodeParent == null){
         | 
| 6150 | 
            +
            							        	continue;
         | 
| 6151 | 
            +
            							        }
         | 
| 6152 | 
            +
            									if(nodeParent.childNodes.length != 1){
         | 
| 6153 | 
            +
            										continue;
         | 
| 6154 | 
            +
            									}
         | 
| 6155 | 
            +
             | 
| 6156 | 
            +
            									if(typeof(nodeParent.className) == 'undefined' || nodeParent.className == null || nodeParent.className == ''){
         | 
| 6157 | 
            +
            										nodeParent.className = ' translate_api_in_progress';
         | 
| 6158 | 
            +
            									}else{
         | 
| 6159 | 
            +
            										//这个元素本身有class了,那就追加
         | 
| 6160 | 
            +
             | 
| 6161 | 
            +
            										if(nodeParent.className.indexOf('translate_api_in_progress') > -1){	
         | 
| 6162 | 
            +
            											continue;
         | 
| 6163 | 
            +
            										}
         | 
| 6164 | 
            +
             | 
| 6165 | 
            +
            										nodeParent.className = nodeParent.className+' translate_api_in_progress';
         | 
| 6166 | 
            +
            									}
         | 
| 6167 | 
            +
             | 
| 6168 | 
            +
            						    	}
         | 
| 6169 | 
            +
            						    }
         | 
| 6170 | 
            +
            						}
         | 
| 6171 | 
            +
            					});
         | 
| 6172 | 
            +
            					translate.listener.execute.renderFinishByApi.push(function(uuid){
         | 
| 6173 | 
            +
            					    for(var lang in translate.nodeQueue[uuid].list){
         | 
| 6174 | 
            +
            						    if(translate.language.getCurrent() == lang){
         | 
| 6175 | 
            +
            						        //忽略这个语种
         | 
| 6176 | 
            +
            						        continue;
         | 
| 6177 | 
            +
            						    }
         | 
| 6178 | 
            +
            						    for(var hash in translate.nodeQueue[uuid].list[lang]){
         | 
| 6179 | 
            +
            						    	for(var nodeindex in translate.nodeQueue[uuid].list[lang][hash].nodes){
         | 
| 6180 | 
            +
            						    		var node = translate.nodeQueue[uuid].list[lang][hash].nodes[nodeindex].node;
         | 
| 6181 | 
            +
            						    		var nodeParent = node.parentNode;
         | 
| 6182 | 
            +
            							        if(nodeParent == null){
         | 
| 6183 | 
            +
            							        	continue;
         | 
| 6184 | 
            +
            							        }
         | 
| 6185 | 
            +
             | 
| 6186 | 
            +
            							        /*
         | 
| 6187 | 
            +
            							        注释这个,因为可能是给这个元素动态追加删除导致其子元素不是11
         | 
| 6188 | 
            +
            									if(nodeParent.childNodes.length != 1){
         | 
| 6189 | 
            +
            										continue;
         | 
| 6190 | 
            +
            									}
         | 
| 6191 | 
            +
            									*/
         | 
| 6192 | 
            +
             | 
| 6193 | 
            +
            									var parentClassName = nodeParent.className;
         | 
| 6194 | 
            +
            									if(typeof(parentClassName) == 'undefined' || parentClassName == null || parentClassName == ''){
         | 
| 6195 | 
            +
            										continue;
         | 
| 6196 | 
            +
            									}
         | 
| 6197 | 
            +
            									if(parentClassName.indexOf('translate_api_in_progress') < -1){
         | 
| 6198 | 
            +
            										continue;
         | 
| 6199 | 
            +
            									}
         | 
| 6200 | 
            +
            									
         | 
| 6201 | 
            +
            									nodeParent.className = parentClassName.replace(/translate_api_in_progress/g, '');
         | 
| 6202 | 
            +
            									//nodeParent.className = parentClassName.replace(/loading/g, '');
         | 
| 6203 | 
            +
            						    	}
         | 
| 6204 | 
            +
            						    }
         | 
| 6205 | 
            +
            						}
         | 
| 6206 | 
            +
            					});
         | 
| 6207 | 
            +
             | 
| 6208 | 
            +
            				}
         | 
| 6209 | 
            +
            			}
         | 
| 6210 | 
            +
            		}
         | 
| 6211 | 
            +
            	},
         | 
| 6212 | 
            +
            	/*
         | 
| 6213 | 
            +
            		对js对象进行翻译
         | 
| 6214 | 
            +
            		obj: 可以是JS定义的 对象、数组、甚至是单个具体的值
         | 
| 6215 | 
            +
            	*/
         | 
| 6216 | 
            +
            	jsObject:function (obj, parentKey = '') {
         | 
| 6217 | 
            +
            		/*
         | 
| 6218 | 
            +
            			存放扫描的结果
         | 
| 6219 | 
            +
            			key 存放要被翻译的文本,也就是对象里面某个具体属性的值
         | 
| 6220 | 
            +
            			value 存放 obj 中的 key (的调取路径),比如 series[0].data[0].name   这个是个数组形态,因为同一个翻译的文本内容有可能会在obj中出现多次
         | 
| 6221 | 
            +
            		*/
         | 
| 6222 | 
            +
            		var kvs = {};	
         | 
| 6223 | 
            +
             | 
| 6224 | 
            +
            	    if (typeof obj === 'object' && obj!== null) {
         | 
| 6225 | 
            +
            	        if (Array.isArray(obj)) {
         | 
| 6226 | 
            +
            	            // 处理数组
         | 
| 6227 | 
            +
            	            obj.forEach((item, index) => {
         | 
| 6228 | 
            +
            	                const currentKey = parentKey? `${parentKey}[${index}]` : `[${index}]`;
         | 
| 6229 | 
            +
            	                translate.jsObject(item, currentKey);
         | 
| 6230 | 
            +
            	            });
         | 
| 6231 | 
            +
            	        } else {
         | 
| 6232 | 
            +
            	            // 处理普通对象
         | 
| 6233 | 
            +
            	            for (const key in obj) {
         | 
| 6234 | 
            +
            	                const currentKey = parentKey? `${parentKey}.${key}` : key;
         | 
| 6235 | 
            +
            	                if (typeof obj[key] === 'object' && obj[key]!== null) {
         | 
| 6236 | 
            +
            	                    // 如果值是对象,递归调用函数
         | 
| 6237 | 
            +
            	                    translate.jsObject(obj[key], currentKey);
         | 
| 6238 | 
            +
            	                } else {
         | 
| 6239 | 
            +
            	                    // 打印键值对
         | 
| 6240 | 
            +
             | 
| 6241 | 
            +
            	                    if(typeof(obj[key]) == 'string'){
         | 
| 6242 | 
            +
            	                    	//console.log(`${currentKey}: ${obj[key]}`);
         | 
| 6243 | 
            +
            	                    	//console.log(obj[key]);
         | 
| 6244 | 
            +
            	                    	//console.log(typeof(kvs[obj[key]]));
         | 
| 6245 | 
            +
            	                    	if(typeof(kvs[obj[key]]) == 'undefined'){
         | 
| 6246 | 
            +
            	                    		kvs[obj[key]] = new Array();
         | 
| 6247 | 
            +
            	                    	}
         | 
| 6248 | 
            +
            	                    	//kvs[obj[key].push(currentKey);
         | 
| 6249 | 
            +
            	                    }
         | 
| 6250 | 
            +
            	                    
         | 
| 6251 | 
            +
            	                }
         | 
| 6252 | 
            +
            	            }
         | 
| 6253 | 
            +
            	        }
         | 
| 6254 | 
            +
            	    } else {
         | 
| 6255 | 
            +
            	        // 如果不是对象,直接打印
         | 
| 6256 | 
            +
            	        if(typeof(obj) == 'string'){
         | 
| 6257 | 
            +
             | 
| 6258 | 
            +
            	        	if(typeof(obj) == 'string'){
         | 
| 6259 | 
            +
                            	//console.log(`${parentKey}: ${obj}`);
         | 
| 6260 | 
            +
                            	if(typeof(kvs[obj]) == 'undefined'){
         | 
| 6261 | 
            +
                            		kvs[obj] = new Array();
         | 
| 6262 | 
            +
                            	}
         | 
| 6263 | 
            +
                            	kvs[obj].push('not key');
         | 
| 6264 | 
            +
                            }
         | 
| 6265 | 
            +
             | 
| 6266 | 
            +
            	        	
         | 
| 6267 | 
            +
            	        }
         | 
| 6268 | 
            +
            	    }
         | 
| 6269 | 
            +
             | 
| 6270 | 
            +
            	    return kvs;
         | 
| 6271 | 
            +
            	}
         | 
| 6272 | 
            +
            	/*jsObject end*/
         | 
| 5827 6273 |  | 
| 5828 6274 |  | 
| 5829 6275 | 
             
            }
         | 
| @@ -5893,12 +6339,12 @@ var nodeuuid = { | |
| 5893 6339 | 
             
            			待同事实现
         | 
| 5894 6340 | 
             
            		*/
         | 
| 5895 6341 |  | 
| 5896 | 
            -
            	}
         | 
| 5897 | 
            -
             | 
| 6342 | 
            +
            	},
         | 
| 5898 6343 |  | 
| 5899 6344 | 
             
            }
         | 
| 5900 6345 | 
             
            console.log('------ translate.js ------\nTwo lines of js html automatic translation, page without change, no language configuration file, no API Key, SEO friendly! Open warehouse : https://github.com/xnx3/translate \n两行js实现html全自动翻译。 无需改动页面、无语言配置文件、无API Key、对SEO友好!完全开源,代码仓库:https://gitee.com/mail_osc/translate');
         | 
| 5901 6346 |  | 
| 6347 | 
            +
            /*兼容 AMD、CMD、CommonJS 规范 - start*/
         | 
| 5902 6348 | 
             
            /**
         | 
| 5903 6349 | 
             
             * 兼容 AMD、CMD、CommonJS 规范
         | 
| 5904 6350 | 
             
             * node 环境使用:`npm i i18n-jsautotranslate` 安装包
         | 
| @@ -5914,3 +6360,4 @@ console.log('------ translate.js ------\nTwo lines of js html automatic translat | |
| 5914 6360 | 
             
            })(this, function () {
         | 
| 5915 6361 | 
             
              return translate;
         | 
| 5916 6362 | 
             
            });
         | 
| 6363 | 
            +
            /*兼容 AMD、CMD、CommonJS 规范 - end*/
         | 
    
        package/package.json
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            {
         | 
| 2 2 | 
             
              "name": "i18n-jsautotranslate",
         | 
| 3 | 
            -
              "version": "3. | 
| 3 | 
            +
              "version": "3.14.0",
         | 
| 4 4 | 
             
              "description": "Two lines of js realize automatic html translation. No need to change the page, no language configuration file, no API key, SEO friendly!",
         | 
| 5 5 | 
             
              "main": "index.js",
         | 
| 6 6 | 
             
              "scripts": {
         |