i18n-jsautotranslate 3.13.6 → 3.13.12

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.
Files changed (3) hide show
  1. package/README.md +68 -82
  2. package/index.js +344 -25
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -3,8 +3,8 @@
3
3
  translate.js
4
4
  </h1>
5
5
  <h4 align="center">
6
- 两行js实现html全自动翻译。 <br/>
7
- 无需改动页面、无语言配置文件、无API Key、对SEO友好!
6
+ AI i18n,两行js实现html全自动翻译。 <br/>
7
+ 交给AI,无需改动页面、无语言配置文件、无API Key、对SEO友好!
8
8
  </h4>
9
9
  <h4 align="center">
10
10
  简体中文 |
@@ -16,27 +16,55 @@
16
16
  <a href="http://translate.zvo.cn/4019.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
- * **不增加工作量。** 无需另行改造页面本身,也没有各种语言都要单独配置的语言文件,更不需要你对页面本身要显示的文字区域进行代码调用,我认为那样对技术人员实在是太不友好了。而且它也不需要你到某某网站申请什么key,它本身就是开放的,拿来即用。
32
- * **极其灵活扩展。** 您可指定它[只翻译某些指定区域](http://translate.zvo.cn/41548.html)、切换语言时[显示下拉框](http://translate.zvo.cn/41544.html)还是通过[摆放多个切换语言按钮](http://translate.zvo.cn/41549.html)进行、可指定某些特定的元素不进行翻译忽略……
33
- * [**自动匹配语种。** 自动根据用户所在的国家切换其国家所使用的语种](http://translate.zvo.cn/41550.html)
34
- * [**瞬间翻译能力。** 内置缓存预加载机制,只要翻译过的网页,再次看时会达到瞬间翻译的效果,给用户的感觉就是,这个页面本来就是这种语言的,而不是经过第三方翻译的。](http://translate.zvo.cn/41750.html)
35
- * [**永久免费使用。** 采用Apache-2.0开源协议,您可永久免费使用。](https://github.com/xnx3/translate/blob/master/LICENSE)
36
- * **搜索引擎友好。** 完全不影响你本身网站搜索引擎的收录。爬虫所爬取的网页源代码,它不会对其进行任何改动,你可完全放心。
37
- * [**支持私有部署。** 在某些政府机关及大集团内部项目中,对数据隐私及安全保密有强要求场景、或您对自有客户希望提供自建高可靠翻译服务场景时,您可将后端翻译接口进行私有化部署,不走我们公开开放的翻译接口,以做到安全保密及后端服务全部自行掌控。](http://translate.zvo.cn/41160.html)
38
- * **多个翻译节点**。每间隔1分钟自动获取一次延迟最小的节点进行接入使用,全面规避全球使用时,某个地域网络波动导致后端翻译接口无法响应的情况发生。自动适配最快节点,做到更好的使用体验!
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渲染完毕后触发些什么。
40
68
 
41
69
  # 在线体验
42
70
  http://res.zvo.cn/translate/demo.html
@@ -65,42 +93,6 @@ translate.execute();//进行翻译
65
93
  </script>
66
94
  ````
67
95
 
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
96
 
105
97
 
106
98
  # 使用示例
@@ -150,6 +142,8 @@ translate.execute();//进行翻译
150
142
  # 谁在使用
151
143
 
152
144
  开源项目:
145
+ * [DzzOffice](http://www.dzzoffice.com/index.php?mod=dzzmarket&op=view&mid=58) 开源办公套件,搭建自己的类似“Google企业应用套件”、“微软Office365”的企业协同办公平台
146
+ * [ModStart](https://modstart.com/m/WebTranslate) 基于 Laravel 的模块化全栈开发框架
153
147
  * [管伊佳ERP](https://gitee.com/jishenghua/JSH_ERP) 国产开源ERP系统关注度第一,专注进销存、生产、总账
154
148
  * [FixIt](https://github.com/hugo-fixit/cmpt-translate) 一款简洁、优雅且先进的Hugo 博客主题
155
149
  * [Z-Blog](https://app.zblogcn.com/?id=49226) 易用的博客程序,功能丰富,模板多样,助轻松搭建个性博客。
@@ -182,16 +176,6 @@ translate.execute();//进行翻译
182
176
  如果您有开源项目,比如文档、cms、UI 框架、后台管理框架、等等,需要采用此进行多语言切换,欢迎喊我,无偿提供全程接入讨论及遇到的问题跟随优化,希望我们的开源项目能互相产生作用一起越来越好。如果你的项目在这个列表中没有,欢迎联系我说明,我给加入进去。如果您不想出现在这里,也联系我,我给隐去。
183
177
 
184
178
 
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
179
  # TCDN部署
196
180
  tcdn是translate.js 的高级版本,它的能力是让你原本的网站可以用不同的域名访问到不同的语种。而不同的语种,都可以被收录!它可以免费部署到服务器进行使用。注意,它需要使用个1核2G的服务器进行部署的。
197
181
  部署方式有两种:
@@ -275,27 +259,29 @@ tcdn是translate.js 的高级版本,它的能力是让你原本的网站可以
275
259
  如果您在使用过程中遇到任何异常情况,请详细说一下您遇到的问题。如果可以,请写下您的网站,以便我们可以更全面地测试,以便快速找到问题所在
276
260
  作者微信:xnx3com(使用交流可加QQ群进行,我看微信很不及时)
277
261
  Telegram : [untran](https://t.me/untran)
278
- 交流QQ群:240567964
279
262
  交流QQ群:181781514 (已满)
280
263
  交流QQ群:641047127 (已满)
264
+ 交流QQ群:240567964 (快满)
265
+ 交流QQ群:1034085260
281
266
  微信公众号:wangmarket
282
267
  github: [https://github.com/xnx3/translate](https://github.com/xnx3/translate)
283
268
  gitee: [https://gitee.com/mail_osc/translate](https://gitee.com/mail_osc/translate)
284
269
 
285
- # 有偿帮助
286
- 我们位于三线城市,各方面开发成本相对较低,如果您有临时需要技术人员帮助,欢迎联系我们,也算对我们的支持,让我们能持续下去。
287
- * Java开发,5年以上经验,65元每小时
288
- * Java开发,半年经验(主要处理琐碎杂事),25元每小时
289
- * 前端开发,3年经验(vue、uniapp、微信小程序等都可以),50元每小时
290
- * Android开发,7年经验,65元每小时
291
270
 
292
- 另外,如果有别编程语言的需要,也可以喊我,我微信 xnx3com 价格绝对实在,诚信第一,不满意不要钱!!
271
+ # 寻找合作
272
+ 寻找合作伙伴探讨盈利方式 - 以下全自有技术研发
273
+
274
+ 1. html源码翻译开放API http://doc.zvo.cn/tcdn/api/doc.html
275
+ 2. TCDN全自动网站源码级翻译,适合翻译后语种分别分配域名、进行SEO优化 http://translate.zvo.cn/236896.html
276
+
277
+ 联系:17076012262(微信同号) 我们是纯技术团队,欢迎联系,希望能跟你探讨合作盈利商机,我们专心技术,您来拓展商务销售
293
278
 
294
279
 
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),如果有没列出来的,您感觉可以对本项目有帮助的,也欢迎联系我的,感谢大家的支持
280
+ # 商业化声明
301
281
 
282
+ 我完全允许你拿我的开源项目进行商业化包装盈利,而无需给我支付任何费用!
283
+ 你能拿来赚钱,那是你的本事。
284
+ 而我的开源项目能帮你赚钱,我会很荣幸,我能造福社会。
285
+ 你在用它进行商业化盈利的时候,遇到问题也完全可以大方的向我求助,用它赚钱并不是什么偷偷摸摸的事情,技术能用来养家糊口改善生活是值得点赞的。
286
+ 而且如果你不放心,我还可以白纸黑字盖章,送你一个定心丸。
287
+ 说这么多,是体现一个态度,开源就是开源,我不会想法绑架你。我们可以在一起以最纯粹的状态交流,让生活更美好。
package/index.js CHANGED
@@ -14,7 +14,7 @@ var translate = {
14
14
  * 格式:major.minor.patch.date
15
15
  */
16
16
  // AUTO_VERSION_START
17
- version: '3.13.6.20250217',
17
+ version: '3.13.12.20250307',
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
- if(translate.to != null && typeof(translate.to) != 'undefined' && translate.to.length > 0){
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 待翻译的页面的node队列
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的原始文字,也就是 node 中的原始文字。
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数组,其中包含:
@@ -894,6 +907,53 @@ var translate = {
894
907
 
895
908
 
896
909
  },
910
+ /*
911
+ key: nodeid node的唯一标识,格式如 HTML1_BODY1_DIV2_#text1 ,它是使用 nodeuuid.uuid(node) 获得的
912
+ 注意,document.getElementById 获得的并不是,需要这样获得 document.getElementById('xx').childNodes[0] 因为它是要给监听dom改动那里用的,监听到的改动的是里面具体的node
913
+ value:13位时间戳
914
+ */
915
+ ignoreNode:[],
916
+ /*
917
+ 通过 translate.execute() 触发的翻译,来使node发生的改动,这种改动加入到 ignoreNode 的过期时间是多少。
918
+ 单位是毫秒
919
+ */
920
+ translateExecuteNodeIgnoreExpireTime:1000,
921
+ /*
922
+ 增加一个被listener忽略的节点
923
+ 这里通常是用于被 translate.js 本身翻译更改的节点、以及像是 Layui 被翻译后触发了渲染改动了dom , 这几种场景都是翻译本身自己触发的,是不需要再被listener触发,不然就形成死循环了
924
+ node 是哪个节点被listener扫描到改动后忽略。
925
+ 可传入 node、也可以传入node的uuid字符串
926
+ expireTime 过期时间,也就是执行当前方法将 node 加入后,过多长时间失效,这里是毫秒,比如传入 500 则这个node在当前时间往后的500毫秒内,如果被listener监听到改动,是直接被忽略的,不会触发任何翻译操作
927
+ */
928
+ addIgnore:function(node, expireTime){
929
+ let nodeid = '';
930
+ if(typeof(node) == 'string'){
931
+ nodeid = node;
932
+ }else{
933
+ nodeid = nodeuuid.uuid(node);
934
+ }
935
+
936
+ translate.listener.ignoreNode[nodeid] = Date.now()+expireTime;
937
+
938
+ //translate.listener.renderTaskFinish();
939
+ },
940
+ /*
941
+ 刷新 ignoreNode 中的元素,也就是查找其中 expireTime 过期的,删掉
942
+ */
943
+ refreshIgnoreNode:function(){
944
+ //console.log('refresh ignore ,current: '+Object.keys(translate.listener.ignoreNode).length);
945
+ var currentTime = Date.now();
946
+ for (const node in translate.listener.ignoreNode) {
947
+ if(translate.listener.ignoreNode[node] < currentTime){
948
+ //console.log('delete : ');
949
+ //console.log(node);
950
+ delete translate.listener.ignoreNode[node];
951
+ }
952
+ }
953
+ //console.log('refresh ignore finish: '+Object.keys(translate.listener.ignoreNode).length);
954
+ },
955
+
956
+
897
957
  //增加监听,开始监听。这个不要直接调用,需要使用上面的 start() 开启
898
958
  addListener:function(){
899
959
  translate.listener.isStart = true; //记录已执行过启动方法了
@@ -953,12 +1013,12 @@ var translate = {
953
1013
  //判断是否属于在正在翻译的节点,重新组合出新的要翻译的node集合
954
1014
  var translateNodes = [];
955
1015
  //console.log(translate.inProgressNodes.length);
956
- for(let ipnode of documents){
957
- //console.log('---type:'+ipnode.nodeType);
1016
+ for(let node of documents){
1017
+ //console.log('---type:'+node.nodeType);
958
1018
 
959
1019
  var find = false;
960
1020
  for(var ini = 0; ini < translate.inProgressNodes.length; ini++){
961
- if(translate.inProgressNodes[ini].node.isSameNode(ipnode)){
1021
+ if(translate.inProgressNodes[ini].node.isSameNode(node)){
962
1022
  //有记录了,那么忽略这个node,这个node是因为翻译才导致的变动
963
1023
  //console.log('发现相同');
964
1024
  find = true;
@@ -969,10 +1029,19 @@ var translate = {
969
1029
  continue;
970
1030
  }
971
1031
 
1032
+ //console.log(node);
1033
+ let nodeid = nodeuuid.uuid(node);
1034
+ if(typeof(translate.listener.ignoreNode[nodeid]) == 'number'){
1035
+ if(translate.listener.ignoreNode[nodeid] > Date.now()){
1036
+ //console.log('node 未过忽略期,listener扫描后忽略:'+nodeid);
1037
+ continue;
1038
+ }
1039
+ }
1040
+
972
1041
  //不相同,才追加到新的 translateNodes
973
- translateNodes.push(ipnode);
974
- //console.log('listener ++ '+ipnode.nodeValue);
975
- //console.log(ipnode);
1042
+ translateNodes.push(node);
1043
+ //console.log('listener ++ '+node.nodeValue);
1044
+ //console.log(node);
976
1045
  }
977
1046
  if(translateNodes.length < 1){
978
1047
  return;
@@ -1004,7 +1073,45 @@ var translate = {
1004
1073
  */
1005
1074
  renderTaskFinish:function(renderTask){
1006
1075
  //console.log(renderTask);
1007
- }
1076
+ },
1077
+
1078
+ /*
1079
+ 翻译执行过程中,相关的监控
1080
+ */
1081
+ execute:{
1082
+
1083
+ /*
1084
+ 每当触发执行 translate.execute() 时,当缓存中未发现,需要请求翻译API进行翻译时,在发送API请求前,触发此
1085
+ */
1086
+ renderStartByApi : [],
1087
+ renderStartByApiRun:function(uuid){
1088
+ //console.log(translate.nodeQueue[uuid]);
1089
+ for(var i = 0; i < translate.listener.execute.renderStartByApi.length; i++){
1090
+ try{
1091
+ translate.listener.execute.renderStartByApi[i](uuid);
1092
+ }catch(e){
1093
+ console.log(e);
1094
+ }
1095
+ }
1096
+ },
1097
+
1098
+ /*
1099
+ 每当 translate.execute() 执行完毕(前提是采用API翻译的,API将翻译结果返回,并且界面上的翻译结果也已经渲染完毕)后,触发此方法。
1100
+ uuid:translate.nodeQueue[uuid] 这里的
1101
+ */
1102
+ renderFinishByApi : [],
1103
+ renderFinishByApiRun:function(uuid){
1104
+ //console.log(translate.nodeQueue[uuid]);
1105
+ for(var i = 0; i < translate.listener.execute.renderFinishByApi.length; i++){
1106
+ try{
1107
+ translate.listener.execute.renderFinishByApi[i](uuid);
1108
+ }catch(e){
1109
+ console.log(e);
1110
+ }
1111
+ }
1112
+ }
1113
+ }
1114
+
1008
1115
  },
1009
1116
  //对翻译结果进行替换渲染的任务,将待翻译内容替换为翻译内容的过程
1010
1117
  renderTask:class{
@@ -1104,6 +1211,9 @@ var translate = {
1104
1211
  //console.log(this.nodes);
1105
1212
  //console.log('===========task======end===');
1106
1213
 
1214
+ //进行翻译前,先刷新一下 dom监听的忽略node,将过期的node剔除,降低listener的压力
1215
+ translate.listener.refreshIgnoreNode();
1216
+
1107
1217
  //对nodeQueue进行翻译
1108
1218
  for(var hash in this.nodes){
1109
1219
  var tasks = this.taskQueue[hash]; //取出当前node元素对应的替换任务
@@ -1141,6 +1251,8 @@ var translate = {
1141
1251
 
1142
1252
  }, 50, ipnode);
1143
1253
 
1254
+ //加入 translate.listener.ignoreNode
1255
+ translate.listener.addIgnore(this.nodes[hash][task_index], translate.listener.translateExecuteNodeIgnoreExpireTime);
1144
1256
  translate.element.nodeAnalyse.set(this.nodes[hash][task_index], task.originalText, task.resultText, task['attribute']);
1145
1257
 
1146
1258
 
@@ -1291,7 +1403,6 @@ var translate = {
1291
1403
  },
1292
1404
  //当前 translate.translateRequest[uuid] 的是否已经全部执行完毕,这里单纯只是对 translate.translateRequest[uuid] 的进行判断,这里要在 translate.json 接口触发完并渲染完毕后触发,当然接口失败时也要触发
1293
1405
  isAllExecuteFinish:function(uuid){
1294
-
1295
1406
  for(var lang in translate.translateRequest[uuid]){
1296
1407
  for(var i = 0; i<translate.translateRequest[uuid][lang].length; i++){
1297
1408
  if(translate.translateRequest[uuid][lang][i].executeFinish == 0){
@@ -1308,6 +1419,8 @@ var translate = {
1308
1419
  //都执行完了,那么设置完毕
1309
1420
  translate.state = 0;
1310
1421
  translate.executeNumber++;
1422
+
1423
+ translate.listener.execute.renderFinishByApiRun(uuid);
1311
1424
  }
1312
1425
 
1313
1426
  },
@@ -1881,7 +1994,8 @@ var translate = {
1881
1994
  //状态
1882
1995
  translate.state = 20;
1883
1996
 
1884
-
1997
+ //listener
1998
+ translate.listener.execute.renderStartByApiRun(uuid);
1885
1999
 
1886
2000
  //进行掉接口翻译
1887
2001
  for(var lang_index in fanyiLangs){ //一维数组,取语言
@@ -1915,7 +2029,7 @@ var translate = {
1915
2029
  var data = {
1916
2030
  from:lang,
1917
2031
  to:translate.to,
1918
- lowercase:translate.whole.isEnableAll? '0':'1', //首字母大写
2032
+ //lowercase:translate.whole.isEnableAll? '0':'1', //首字母大写
1919
2033
  //text:JSON.stringify(translateTextArray[lang])
1920
2034
  text:encodeURIComponent(JSON.stringify(translateTextArray[lang]))
1921
2035
  };
@@ -1927,7 +2041,7 @@ var translate = {
1927
2041
  translate.translateRequest[uuid][lang].result = 2;
1928
2042
  translate.translateRequest[uuid][lang].executeFinish = 1; //1是执行完毕
1929
2043
  translate.translateRequest[uuid][lang].stoptime = Math.floor(Date.now() / 1000);
1930
- translate.waitingExecute.isAllExecuteFinish();
2044
+ translate.waitingExecute.isAllExecuteFinish(uuid);
1931
2045
  console.log('=======ERROR START=======');
1932
2046
  console.log(translateTextArray[data.from]);
1933
2047
  //console.log(encodeURIComponent(JSON.stringify(translateTextArray[data.from])));
@@ -2007,12 +2121,14 @@ var translate = {
2007
2121
  translate.translateRequest[uuid][lang].result = 1;
2008
2122
  translate.translateRequest[uuid][lang].executeFinish = 1; //1是执行完毕
2009
2123
  translate.translateRequest[uuid][lang].stoptime = Math.floor(Date.now() / 1000);
2010
- translate.waitingExecute.isAllExecuteFinish();
2124
+ setTimeout(function(){
2125
+ translate.waitingExecute.isAllExecuteFinish(uuid);
2126
+ },10);
2011
2127
  }, function(xhr){
2012
2128
  translate.translateRequest[uuid][lang].executeFinish = 1; //1是执行完毕
2013
2129
  translate.translateRequest[uuid][lang].stoptime = Math.floor(Date.now() / 1000);
2014
2130
  translate.translateRequest[uuid][lang].result = 3;
2015
- translate.waitingExecute.isAllExecuteFinish();
2131
+ translate.waitingExecute.isAllExecuteFinish(uuid);
2016
2132
  });
2017
2133
  /*** 翻译end ***/
2018
2134
  }
@@ -4915,14 +5031,13 @@ var translate = {
4915
5031
  if(storage_hostQueue == null || typeof(storage_hostQueue) == 'undefined'){
4916
5032
  //本地存储中没有,也就是之前没设置过,是第一次用,那么直接讲 translate.request.api.host 赋予之
4917
5033
  //translate.request.api.host
4918
- //console.log(typeof(translate.request.api.host))
5034
+
4919
5035
  if(typeof(translate.request.api.host) == 'string'){
4920
5036
  //单个,那么赋予数组形式
4921
5037
  //translate.request.speedDetectionControl.hostQueue = [{"host":translate.request.api.host, time:0 }];
4922
5038
  translate.request.api.host = [''+translate.request.api.host];
4923
5039
  }
4924
5040
 
4925
- //console.log(translate.request.api.host)
4926
5041
  //数组形态,多个,v2.8.2 增加多个,根据优先级返回
4927
5042
  translate.request.speedDetectionControl.hostQueue = [];
4928
5043
  for(var i = 0; i<translate.request.api.host.length; i++){
@@ -5790,7 +5905,6 @@ var translate = {
5790
5905
  return;
5791
5906
  }
5792
5907
  translate.init_execute = '已进行';
5793
-
5794
5908
  try{
5795
5909
  translate.request.send(
5796
5910
  translate.request.api.init,
@@ -5822,6 +5936,212 @@ var translate = {
5822
5936
  );
5823
5937
  }catch(e){
5824
5938
  }
5939
+ },
5940
+
5941
+ /*
5942
+ 翻译执行的进展相关
5943
+ */
5944
+ progress:{
5945
+ /*
5946
+ 通过文本翻译API进行的
5947
+ */
5948
+ api:{
5949
+ isTip:true,//是否显示ui的提示,true显示,false不显示
5950
+ setUITip:function(tip){
5951
+ translate.progress.api.isTip = tip;
5952
+ },
5953
+ startUITip:function(){
5954
+ // 创建一个 style 元素
5955
+ const style = document.createElement('style');
5956
+ // 设置 style 元素的文本内容为要添加的 CSS 规则
5957
+ style.textContent = `
5958
+ /* CSS部分 */
5959
+ /* 灰色水平加载动画 */
5960
+ .translate_api_in_progress {
5961
+ position: relative;
5962
+ overflow: hidden; /* 隐藏超出部分的动画 */
5963
+ }
5964
+
5965
+ /* 蒙版层 */
5966
+ .translate_api_in_progress::after {
5967
+ content: '';
5968
+ position: absolute;
5969
+ top: 0;
5970
+ left: 0;
5971
+ width: 100%;
5972
+ height: 100%;
5973
+ background: rgba(255, 255, 255, 1); /* 半透明白色遮罩 */
5974
+ z-index: 2;
5975
+ }
5976
+
5977
+ /* 水平加载条动画 */
5978
+ .translate_api_in_progress::before {
5979
+ content: '';
5980
+ position: absolute;
5981
+ top: 50%;
5982
+ left: 0;
5983
+ width: 100%;
5984
+ height:100%; /* 细线高度 */
5985
+ background: linear-gradient(
5986
+ 90deg,
5987
+ transparent 0%,
5988
+ #e8e8e8 25%, /* 浅灰色 */
5989
+ #d0d0d0 50%, /* 中灰色 */
5990
+ #e8e8e8 75%, /* 浅灰色 */
5991
+ transparent 100%
5992
+ );
5993
+ background-size: 200% 100%;
5994
+ animation: translate_api_in_progress_horizontal-loader 3.5s linear infinite;
5995
+ z-index: 3;
5996
+ transform: translateY(-50%);
5997
+ }
5998
+
5999
+ @keyframes translate_api_in_progress_horizontal-loader {
6000
+ 0% {
6001
+ background-position: 200% 0;
6002
+ }
6003
+ 100% {
6004
+ background-position: -200% 0;
6005
+ }
6006
+ }
6007
+ `;
6008
+ // 将 style 元素插入到 head 元素中
6009
+ document.head.appendChild(style);
6010
+
6011
+
6012
+ if(translate.progress.api.isTip){
6013
+ translate.listener.execute.renderStartByApi.push(function(uuid){
6014
+ for(var lang in translate.nodeQueue[uuid].list){
6015
+ if(translate.language.getCurrent() == lang){
6016
+ //忽略这个语种
6017
+ continue;
6018
+ }
6019
+ for(var hash in translate.nodeQueue[uuid].list[lang]){
6020
+ for(var nodeindex in translate.nodeQueue[uuid].list[lang][hash].nodes){
6021
+ var node = translate.nodeQueue[uuid].list[lang][hash].nodes[nodeindex].node;
6022
+ var nodeParent = node.parentNode;
6023
+ if(nodeParent == null){
6024
+ continue;
6025
+ }
6026
+ if(nodeParent.childNodes.length != 1){
6027
+ continue;
6028
+ }
6029
+
6030
+ if(typeof(nodeParent.className) == 'undefined' || nodeParent.className == null || nodeParent.className == ''){
6031
+ nodeParent.className = ' translate_api_in_progress';
6032
+ }else{
6033
+ //这个元素本身有class了,那就追加
6034
+
6035
+ if(nodeParent.className.indexOf('translate_api_in_progress') > -1){
6036
+ continue;
6037
+ }
6038
+
6039
+ nodeParent.className = nodeParent.className+' translate_api_in_progress';
6040
+ }
6041
+
6042
+ }
6043
+ }
6044
+ }
6045
+ });
6046
+ translate.listener.execute.renderFinishByApi.push(function(uuid){
6047
+ for(var lang in translate.nodeQueue[uuid].list){
6048
+ if(translate.language.getCurrent() == lang){
6049
+ //忽略这个语种
6050
+ continue;
6051
+ }
6052
+ for(var hash in translate.nodeQueue[uuid].list[lang]){
6053
+ for(var nodeindex in translate.nodeQueue[uuid].list[lang][hash].nodes){
6054
+ var node = translate.nodeQueue[uuid].list[lang][hash].nodes[nodeindex].node;
6055
+ var nodeParent = node.parentNode;
6056
+ if(nodeParent == null){
6057
+ continue;
6058
+ }
6059
+
6060
+ /*
6061
+ 注释这个,因为可能是给这个元素动态追加删除导致其子元素不是11
6062
+ if(nodeParent.childNodes.length != 1){
6063
+ continue;
6064
+ }
6065
+ */
6066
+
6067
+ var parentClassName = nodeParent.className;
6068
+ if(typeof(parentClassName) == 'undefined' || parentClassName == null || parentClassName == ''){
6069
+ continue;
6070
+ }
6071
+ if(parentClassName.indexOf('translate_api_in_progress') < -1){
6072
+ continue;
6073
+ }
6074
+
6075
+ nodeParent.className = parentClassName.replace(/translate_api_in_progress/g, '');
6076
+ //nodeParent.className = parentClassName.replace(/loading/g, '');
6077
+ }
6078
+ }
6079
+ }
6080
+ });
6081
+
6082
+ }
6083
+ }
6084
+ }
6085
+ },
6086
+ /*
6087
+ 对js对象进行翻译
6088
+ obj: 可以是JS定义的 对象、数组、甚至是单个具体的值
6089
+ */
6090
+ jsObject:function (obj, parentKey = '') {
6091
+ /*
6092
+ 存放扫描的结果
6093
+ key 存放要被翻译的文本,也就是对象里面某个具体属性的值
6094
+ value 存放 obj 中的 key (的调取路径),比如 series[0].data[0].name 这个是个数组形态,因为同一个翻译的文本内容有可能会在obj中出现多次
6095
+ */
6096
+ var kvs = {};
6097
+
6098
+ if (typeof obj === 'object' && obj!== null) {
6099
+ if (Array.isArray(obj)) {
6100
+ // 处理数组
6101
+ obj.forEach((item, index) => {
6102
+ const currentKey = parentKey? `${parentKey}[${index}]` : `[${index}]`;
6103
+ translate.jsObject(item, currentKey);
6104
+ });
6105
+ } else {
6106
+ // 处理普通对象
6107
+ for (const key in obj) {
6108
+ const currentKey = parentKey? `${parentKey}.${key}` : key;
6109
+ if (typeof obj[key] === 'object' && obj[key]!== null) {
6110
+ // 如果值是对象,递归调用函数
6111
+ translate.jsObject(obj[key], currentKey);
6112
+ } else {
6113
+ // 打印键值对
6114
+
6115
+ if(typeof(obj[key]) == 'string'){
6116
+ //console.log(`${currentKey}: ${obj[key]}`);
6117
+ //console.log(obj[key]);
6118
+ //console.log(typeof(kvs[obj[key]]));
6119
+ if(typeof(kvs[obj[key]]) == 'undefined'){
6120
+ kvs[obj[key]] = new Array();
6121
+ }
6122
+ //kvs[obj[key].push(currentKey);
6123
+ }
6124
+
6125
+ }
6126
+ }
6127
+ }
6128
+ } else {
6129
+ // 如果不是对象,直接打印
6130
+ if(typeof(obj) == 'string'){
6131
+
6132
+ if(typeof(obj) == 'string'){
6133
+ //console.log(`${parentKey}: ${obj}`);
6134
+ if(typeof(kvs[obj]) == 'undefined'){
6135
+ kvs[obj] = new Array();
6136
+ }
6137
+ kvs[obj].push('not key');
6138
+ }
6139
+
6140
+
6141
+ }
6142
+ }
6143
+
6144
+ return kvs;
5825
6145
  }
5826
6146
 
5827
6147
 
@@ -5893,8 +6213,7 @@ var nodeuuid = {
5893
6213
  待同事实现
5894
6214
  */
5895
6215
 
5896
- }
5897
-
6216
+ },
5898
6217
 
5899
6218
  }
5900
6219
  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');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "i18n-jsautotranslate",
3
- "version": "3.13.6",
3
+ "version": "3.13.12",
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": {