你真的认为Google翻译不影响"前端"页面性能吗?

背景

     又是一个时光飞逝的工作日, QA同学忽然提出bug, 文本输入框的"计数"性能生效, 通过大家多方查找最初发现居然是因为测试同学开启了"谷歌翻译"造成的无奈"计数", 这就引起了我的浓厚兴趣, 到底这个看起来"人畜有害"的翻译性能是如何影响了我的输入框? 魏蜀吴争霸从此揭开序幕,啊~额(中箭)。

     这篇文章是按我的探索过程编写的, 所以并不是一下就找到正确的方向, 跟着我过后的思路一起摸索吧。

一、dom构造的扭转 (以react代码为例)

     想要晓得为什么"翻译性能"会影响页面, 要从察看每次"翻译"性能失效时页面构造的变动开始, 最为简略的一段代码:

return ( <div>你好</div> )

翻译前:

翻译后:

     查问一下font标签的个性, 居然曾经不倡议应用了:

     尝试一下是否能够获取到这个font标签元素, 将代码改装一下

  function handleShowDom() {    console.log(document.getElementById("box").children);  } return(    <div id="box" onClick={handleShowDom}>    你好   </div> )

     能够获取到这个元素就有意思了, 如果某些状况下代码外面存在通过获取子元素进行操作的逻辑, 那么实践上就会出问题啊。

     难道是因为dom构造的扭转, 导致的文本输入框的计数性能会隐没吗?

二、比照vue与react各类ui库

     通过查看element ui的源码没有发现非凡的代码逻辑, 那到底是怎么回事? 满心的疑难让我萌发一种想法, 难道跟vue与react框架自身的原理无关? 那么接下来我会别离试验4种ui框架的成果:

1: react -> antd (无bug )

antd官网

2: react -> arco (有bug)

arco 官网

3: vue -> element(有bug)

     这个不必演示了, 开局就是靠它。

4: vue -> iview(有bug)

iview 官网

     上述只有 antd是完满解决了这个bug (必须: respect), 那必须要钻研一下它是如何"力压群芳"的呢?

三、深究textarea

     既然是这个输入框元素产生的问题, 那么咱们就从它开始吧, 一起看一下element-uiantd别离产生的textarea元素长什么样子:

     区别还是比拟显著的, element-ui的内容信息不是放在标签外部的, 因为咱们在dom构造的视角无奈查看到内容, 然而antd恰恰相反, 这兴许能够成为一个突破口。

     那咱们把"火力"集中在<textarea>身上, 看看它到底有多少种赋值写法:

  return (    <div className="App">      <textarea rows="5" cols="40">        内容1      </textarea>      <br />      <textarea rows="5" cols="40" value="内容2"></textarea>      <br />      <textarea rows="5" cols="40" defaultValue="内容3"></textarea>   </div>

     很微妙, 上述三种写法都会产生同样的dom构造, 那么就比拟好奇是什么样的写法能够暗藏标签内的文字? 我就尝试了一下js指定value的形式:

  useEffect(() => {    document.getElementById("wrap").value = "你好世界";  }, []);  return (    <div className="App">      <textarea id="wrap" rows="5" cols="40">        内容4      </textarea>   </div> )

     果然问题出在这里, dom构造内保留的竟然是初始值, 外界显示的是正确的值, 除了这些还有什么区别那? 咱们把相干的值都打印进去吧:

vs

     真是不钻研不晓得, 原来同样的组件成果不同的库实现进去差这么多, 感觉属性值差的还挺多的。

     然而通过试验发现, 这些属性并不是这个bug的间接起因, 咱们还须要深刻源码进行探索, 此时我意识到这个问题可能不是elemnet的责任。

四、谷歌翻译是否影响vue

     通过屡次尝试连本人都不敢相信, 居然vue的计算属性等双向绑定的数据会在翻译后生效:

<template>  <div id="app">    <button @click="handleClick">你好: {{n}}</button>  </div></template><script>export default {  name: 'App',  methods:{    handleClick(){      this.n += 1;      console.log(this.n)    }  },  data(){    return {      n:1    }  },}</script>

     下面能够看出vue的变量曾经变动, 只是因为dom构造的扭转导致了页面无奈被正确更新。

     这是一个很危险的隐患, 因为有的用户可能会抉择"总是翻译", 这就导致页面性能齐全乱掉了啊!

五、谷歌翻译是否影响react

     既然react的arco框架会出问题, 那么react框架也肯定会被影响, 让咱们尝试一下什么状况下会出bug, 翻译之后点击:

import { useState } from "react";import "./App.css";function App() {  const [n, setN] = useState(0);  function handleClick() {    setN(n + 1);    console.log(n + 1);  }  return <div onClick={handleClick}>你好:{n}</div>;}export default App;

如果改成则不会受影响:

<div onClick={handleClick}>{n}</div>;

六、受影响范畴 (以react的写法为例)

     通过观察antd与element-ui实现的不同我发现, antd是应用after伪类类做的, 难道此事与伪类无关? 这也证实了某些状况是不受影响的, 让咱们试验一下谷歌翻译都影响哪些写法:

1: 拼接文本

     不受影响的写法, 甚至这种写法每次n发生变化, 会移除font标签的dom构造。

<div>{n}</div>;

     受影响的写法次要是拼接的文本。

<div>你好 {n}</div>;<div>{n} {n}</div>;
2: 伪元素(不会被翻译)

空空的dom

<div className={"box"}>.</div>

定义伪元素

.box {  height: 10px;  width: 10px;  border: 1px solid red;}.box::after {  content: 'hello';  display: inline-block;}

所以antd很可能是因为伪元素才没有出bug, 如果antd不是无心之举那就太细节了。

3: 属性(十分非凡)

     之所以说它十分非凡, 是因为属性是否被翻译须要分两种状况探讨, 是否有文本元素, 并且这个文本不能是input外部的文本。

第一种状况: 页面只有一个输入框

    <div>      <span>        <input          type="Please enter content"          value={value}          onChange={change}          placeholder={"Please enter content"}        />      </span>    </div>

不言而喻, 这个输入框没有被翻译:

第二种状况: 随便增加一个字符串

    <div>      <span>你好</span>      <span>        <input          type="Please enter content"          value={value}          onChange={change}          placeholder={"Please enter content"}        />      </span>    </div>

     胜利进行了翻译并且像placeholder这种可能会展现给用户的属性也被翻译了, 其余功能性的属性并不会被翻译。

<span xxx={"xxxxxxxxx hello"}>你好</span>

七、如何屏蔽翻译

     为避免因谷歌翻译引起不良体验, 只须要在html标签上增加translate="no"属性即可屏蔽掉翻译性能:

八、检测被翻译成了什么

     其实存在一部分用户默认就开启谷歌翻译性能的, 更有甚者你做的是国际化我的项目, 不同语言的人应用你的网站更有可能应用默认的谷歌翻译, 那么不编间接屏蔽的状况下, 咱们要至多要监听一下用户都将咱们的网站翻译成了什么语言? 这样也不便咱们日后对网站的i18n进行优化。

     比方咱们网站本人没有韩语的翻译, 然而常常被用过翻译成韩语, 那么咱们能够思考减少韩语呢?

     再比方咱们尽管提供了韩语的翻译, 然而用户依然被动将网站翻译成韩语, 那就要思考是不是咱们能够将已有的翻译性能, 更明确的提醒给用户应用? 毕竟咱们自带的翻译更精确体验也更好。

1: MutationObserver 简介

     能够监控dom元素自身的所有扭转, MutationObserver实例化后要传入一个配置项, 这个配置项能够自定义须要监听dom的哪些变动, 上面列出次要的几个属性:

  1. attributes 布尔值, 监测dom的属性变动
  2. attributeFilter 数组, 监测dom的具体某个属性的变动, 填写这个参数就不必每次判断哪个属性变动了
  3. childList布尔值, 子元素的变动
  4. characterData布尔值, 监督指定指标节点或子节点树中节点所蕴含的字符数据的变动

     须要留神的是: childList,attributes 或者 characterData 三个属性之中,至多有一个必须为 true,否则会抛出 TypeError 异样。

2: 监控翻译的思路

     因为每次谷歌翻译都会批改咱们的<html lang="en">标签的lang属性, 所以咱们就监控这个属性的变动, 并且因为哪怕以后是lang="en"谷歌翻译成英语还是lang="en", 也是会被检测到的 , 所以这个技术计划也是可行的。

     新建一个listenerI18n.js文件, 已插件的模式引入即可:

(function () {  const oHtml = document.getElementsByTagName("html")[0];  const observer = new window.MutationObserver((mutations) => {    console.log(`上报: 翻译为  ${oHtml.getAttribute("lang")}`);  });  observer.observe(oHtml, { attributes: true, attributeFilter: ["lang"] });})();

     比拟侥幸的是就算你设置了<html lang="en" translate="no">禁止应用翻译性能, 上述办法仍能检测到用户想要用谷歌翻译翻译成什么语言。

我整顿了一份谷歌翻译的对照表, 有须要的同学请自取, 外面并不全面但列举出比拟罕用的国家:

[  {    "name": "简体中文",    "lang": "zh-CN"  },  {    "name": "英语",    "lang": "en"  },  {    "name": "阿拉伯语",    "lang": "ar"  },  {    "name": "爱尔兰语",    "lang": "ga"  },  {    "name": "白俄罗斯语",    "lang": "be"  },  {    "name": "保加利亚语",    "lang": "bg"  },  {    "name": "繁体中文",    "lang": "zh-TW"  },  {    "name": "波兰语",    "lang": "pl"  },  {    "name": "波斯语",    "lang": "fa"  },  {    "name": "丹麦语",    "lang": "da"  },  {    "name": "德语",    "lang": "de"  },  {    "name": "俄语",    "lang": "ru"  },  {    "name": "法语",    "lang": "fr"  },  {    "name": "菲律宾语",    "lang": "tl"  },  {    "name": "芬兰语",    "lang": "fi"  },  {    "name": "高棉语",    "lang": "km"  },  {    "name": "格鲁吉亚语",    "lang": "ka"  },  {    "name": "哈萨克语",    "lang": "kk"  },  {    "name": "韩语",    "lang": "ko"  },  {    "name": "荷兰语",    "lang": "nl"  },  {    "name": "老挝语",    "lang": "lo"  },  {    "name": "罗马尼亚语",    "lang": "ro"  },  {    "name": "马来语",    "lang": "ms"  },  {    "name": "蒙古语",    "lang": "mn"  },  {    "name": "孟加拉语",    "lang": "bn"  },  {    "name": "缅甸语",    "lang": "my"  },  {    "name": "尼泊尔语",    "lang": "ne"  },  {    "name": "挪威语",    "lang": "no"  },  {    "name": "葡头牙语",    "lang": "pt"  },  {    "name": "日语",    "lang": "ja"  },  {    "name": "瑞典语",    "lang": "sv"  },  {    "name": "世界语",    "lang": "eo"  },  {    "name": "泰语",    "lang": "th"  },  {    "name": "土耳其语",    "lang": "tr"  },  {    "name": "乌克兰语",    "lang": "uk"  },  {    "name": "西班牙语",    "lang": "es"  },  {    "name": "希腊语",    "lang": "el"  },  {    "name": "匈牙利语",    "lang": "hu"  },  {    "name": "意大利语",    "lang": "it"  },  {    "name": "印度尼西亚语",    "lang": "id"  },  {    "name": "越南语",    "lang": "vi"  },  {    "name": "爪哇语",    "lang": "jw"  }]

九、总结

     看似"人畜有害"的翻译性能, 背地居然暗藏着各种深浅不一的"坑井", 假如在某些"金额结算页"用户应用了谷歌翻译, 那么是否会造成不小的问题, 所以最好的方法还是提供欠缺的"语言切换"性能才是王道啊。

end

     这次就是这样, 心愿与你一起提高。