{"id":44,"date":"2019-06-02T00:31:28","date_gmt":"2019-06-01T21:31:28","guid":{"rendered":"https:\/\/guoyunhe.me\/en\/?p=44"},"modified":"2020-04-18T18:23:56","modified_gmt":"2020-04-18T15:23:56","slug":"fix-react-issues-with-google-translate","status":"publish","type":"post","link":"https:\/\/guoyunhe.me\/en\/2019\/06\/02\/fix-react-issues-with-google-translate\/","title":{"rendered":"Fix React issues with Google Translate"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Note: we are only talking about Google Translate function in Chrome or Chromium based browsers. Other translate plugins or software don't necessarily work with this solution. And this solution doesn't solve all issues, just a part of them.<\/p>\n\n\n\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_89 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/guoyunhe.me\/en\/2019\/06\/02\/fix-react-issues-with-google-translate\/#When_does_it_happen\" >When does it happen<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/guoyunhe.me\/en\/2019\/06\/02\/fix-react-issues-with-google-translate\/#How_to_fix_it\" >How to fix it<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/guoyunhe.me\/en\/2019\/06\/02\/fix-react-issues-with-google-translate\/#Event_target\" >Event target<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/guoyunhe.me\/en\/2019\/06\/02\/fix-react-issues-with-google-translate\/#If_you_use_third-party_components_from_a_library\" >If you use third-party components from a library<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/guoyunhe.me\/en\/2019\/06\/02\/fix-react-issues-with-google-translate\/#If_the_element_doesnt_support_child_elements\" >If the element doesn&#8217;t support child elements<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/guoyunhe.me\/en\/2019\/06\/02\/fix-react-issues-with-google-translate\/#If_you_want_to_disable_Google_Translate\" >If you want to disable Google Translate<\/a><\/li><\/ul><\/nav><\/div>\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"When_does_it_happen\"><\/span>When does it happen<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You have a component:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const Button = ({children, icon, isLoading, ...rest}) => (\n  &lt;button {...rest}>\n    {icon}\n    {children}\n    {isLoading &amp;&amp; &lt;Loader\/>}\n  &lt;\/button>\n)\n\nconst Test = () => &lt;Button icon=\"+\">Hello World&lt;\/Button><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Which is rendered to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;button>+Hello World&lt;\/button><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If an element (<code>&lt;button&gt;<\/code> in this case) contains multiple rendered string variables, they become text nodes in React's VDOM and HTML DOM. However, Google Translate doesn't care about text nodes and wrap them inside a <code>&lt;font&gt;<\/code> element:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;button>&lt;font>+\u4f60\u597d\u4e16\u754c&lt;\/font>&lt;button><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Since they are not text nodes anymore, synchronization between React and DOM was broken. The button content will not be updated anymore.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"How_to_fix_it\"><\/span>How to fix it<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Simply avoid this situation. Write every <code>{variable}<\/code> inside an element, as the only child.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const Button = ({children, icon, isLoading, ...rest}) => (\n  &lt;button {...rest}>\n    &lt;span className=\"button__icon\">{icon}&lt;\/span>\n    &lt;span className=\"button__text\">{children}&lt;\/span>\n    {isLoading &amp;&amp; &lt;Loader\/>}\n  &lt;\/button>\n)\n\nconst Test = () => &lt;Button icon=\"+\">Hello World&lt;\/Button><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now every variable is synchronized with the <code>&lt;span&gt;<\/code> element, not text nodes. Inserting <code>&lt;font&gt;<\/code> elements doesn't break the connection. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Another situation is that when you mix text nodes with elements.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;p>\n  Copyright 2016-{new Date().getFullYear()}\n&lt;\/p><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Should be converted to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;p>\n  &lt;span>Copyright 2016-&lt;\/span>\n  &lt;span>{new Date().getFullYear()}&lt;\/span>\n&lt;\/p><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Just make sure: a text node or string variable must be the <strong>only child<\/strong> of an element.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Event_target\"><\/span>Event target<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Another issue is that the click event target will change. It might be <code>&lt;font&gt;<\/code> elements instead of <code>&lt;button&gt;<\/code>. Carefully check everywhere you use <code>e.target<\/code>, considering they might not be the button, input or other elements you expected.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A further suggestion is to avoid using any <code>e.target<\/code> reference. Here is a piece of legacy code:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const {sizes, onChange} = this.props\nreturn (\n  &lt;div>\n    {sizes.map(size => (\n      &lt;button\n        key={size}\n        name=\"size\"\n        value={size}\n        onClick={e => this.props.onChange(e.target.value)}>\n        {size.toUpperCase()}\n      &lt;\/button>\n    ))}\n  &lt;\/div>\n)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Can be changed to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>const {sizes, onChange} = this.props\nreturn (\n  &lt;div>\n    {sizes.map(size => (\n      &lt;button\n        key={size}\n        name=\"size\"\n        value={size}\n        onClick={e => this.props.onChange(size)}>\n        {size.toUpperCase()}\n      &lt;\/button>\n    ))}\n  &lt;\/div>\n)<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"If_you_use_third-party_components_from_a_library\"><\/span>If you use third-party components from a library<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In this case, you usually cannot modify the component as you want.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can try to use <code>&lt;span&gt;your string&lt;\/span&gt;<\/code> instead of <code>\"your string\"<\/code> as component properties.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Report to the library maintainers and make a PR with above methods.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"If_the_element_doesnt_support_child_elements\"><\/span>If the element doesn&#8217;t support child elements<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Some components doesn't support inner wrappers, like <code>&lt;option&gt;<\/code>. If you put <code>&lt;span&gt;<\/code> inside <code>&lt;option&gt;<\/code>, React will give you warnings in console, even though the rendering works. So you probably don't want to do it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example you have:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;select>\n  {fruites.map(f => &lt;option value={f.name}>{f.name} - {f.price}&lt;\/option>)}\n&lt;\/select><\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Change it to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;select>\n  {fruites.map(f => {\n    const label = f.name + ' - ' + f.price;\n  \treturn &lt;option value={f.name}>{label}&lt;\/option>\n  })}\n&lt;\/select><\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"If_you_want_to_disable_Google_Translate\"><\/span>If you want to disable Google Translate<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Even if you do all above, something can still go wrong. If you don't have time to waste and just want to disable Google Translate, it is simple:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;body class=\"notranslate\">\n  ...\n&lt;\/body><\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Note: we are only talking about Google Translate function in Chrome or Chromium based browsers. Other translate plugins or software don't necessarily work with this solution. And this solution doesn't solve all issues, just a part of them. When does it happen You have a component: Which is rendered to: If an element (&lt;button&gt; in [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[8,6,5,7],"class_list":["post-44","post","type-post","status-publish","format-standard","hentry","category-code","tag-front-end","tag-javascript","tag-react","tag-web"],"_links":{"self":[{"href":"https:\/\/guoyunhe.me\/en\/wp-json\/wp\/v2\/posts\/44","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/guoyunhe.me\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/guoyunhe.me\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/guoyunhe.me\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/guoyunhe.me\/en\/wp-json\/wp\/v2\/comments?post=44"}],"version-history":[{"count":14,"href":"https:\/\/guoyunhe.me\/en\/wp-json\/wp\/v2\/posts\/44\/revisions"}],"predecessor-version":[{"id":139,"href":"https:\/\/guoyunhe.me\/en\/wp-json\/wp\/v2\/posts\/44\/revisions\/139"}],"wp:attachment":[{"href":"https:\/\/guoyunhe.me\/en\/wp-json\/wp\/v2\/media?parent=44"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/guoyunhe.me\/en\/wp-json\/wp\/v2\/categories?post=44"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/guoyunhe.me\/en\/wp-json\/wp\/v2\/tags?post=44"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}