npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

eslint-plugin-react-google-translate

v0.0.114

Published

ESLint plugin to highlight code patterns in React applications which can lead to browser exceptions while the Google Translate browser extension is in use.

Downloads

46,497

Readme

eslint-plugin-react-google-translate

ESLint plugin to highlight code patterns in React applications which can lead to browser exceptions while the Google Translate browser extension is in use. This is a common problem for React applications and a known issue to both React and Google.

When active on a page, the Google Translate browser extension is very liberal with its DOM manipulation, notably, replacing text nodes with font tags. This can be a problem for React applications as it can cause exceptions to be thrown when conditionally rendering text nodes with siblings within JSX expressions.

Whilst many proposals have been suggested to avoid browser issues, this ESLint plugin aims to solve the problem far earlier in the development process by highlighting certain code patterns to the developer which can cause a browser exception to be thrown where Google Translate is in use.

Examples of code that can throw:

function SomeComponent({ val }) {
  return (
    <div>
      <p>
        // ❌ foo & bar must be wrapped
        {val ? 'foo' : 'bar'} <span>hello world</span>
      </p>
      <p>
        // ❌ static text nodes must be wrapped when they are preceeded by a
        conditional expression
        {val ? <span>foo</span> : <span>bar</span>} hello world
      </p>
      // ❌ all text must be wrapped in spans ('foo', 'bar' & 'hello world')
      <p>{val ? 'foo' : 'bar'} hello world</p>
      <p>
        // ❌ `val.toLocaleString()` returns a text node and should be wrapped
        {val ? val.toLocaleString() : <span>bar</span>} <span>hello world</span>
      </p>
      <p>
        // ❌ object properties rendering a text node should be wrapped
        {val ? obj.a : <span>bar</span>} <span>hello</span>
      </p>
      <p>
        // ❌ 'foo' needs to be wrapped in a span (expression has a sibling)
        {val && 'foo'}
        <span>hello world</span>
      </p>
      // ✅ conditionally rendered text nodes with no siblings won't throw
      <p>{val || 'bar'}</p>
      // ✅ conditionally rendered text nodes with no siblings won't throw
      <p>{val ? 'foo' : 'bar'}</p>
      // ✅ conditional expression follows the static text node and won't throw
      <p>hello world {val ? <span>foo</span> : <span>bar</span>}</p>
    </div>
  );
}

The safe way to write this code, avoiding browser exceptions, is to wrap each of the conditionally rendered text nodes (with siblings) in an element (for example, a <span>). Static text nodes with preceeding conditionally rendered siblings must also be wrapped:

function SomeComponent({ val }) {
  return (
    <div>
      // ✅ all text nodes are wrapped
      <p>
        {val ? <span>foo</span> : <span>bar</span>}
        <span>hello world</span>
      </p>
      <p>
        // ✅ `val.toLocaleString()` is wrapped
        {val ? <span>{val.toLocaleString()}</span> : <span>bar</span>}
        <span>hello world</span>
      </p>
      <p>
        // ✅ object properties rendering a text node are wrapped
        {val ? <span>{obj.a}</span> : <span>bar</span>} <span>hello</span>
      </p>
      <p>
        // ✅ 'foo' is wrapped (expression has a sibling)
        {val && <span>foo</span>} <span>hello world</span>
      </p>
      // ✅ conditionally rendered text, but no siblings
      <p>{val || 'bar'}</p>
      // ✅ conditionally rendered text, but no siblings
      <p>{val ? 'foo' : 'bar'}</p>
    </div>
  );
}

An additional problem identified is React components returning text nodes directly (or numerical values which will be rendered as text). When a React component returns values other than JSX / null, Google Translate can continue to display stale values after state changes, without any error being thrown. Since this is very hard to debug it is better to avoid it altogether.

export function SomeComponent({ input }) {
  if (!input) {
    return null; // ✅ not a problem
  }

  if (input === 'a') {
    return 'A'; // ❌ the browser can display the stale value when state changes
  } else if (input === 'b') {
    return 2; // ❌ numerical values which are rendered as strings can also experience this
  } else if (input === 'c') {
    return `Template Litera${1}`; // ❌ template literals are displayed as strings and can also experience this
  } else {
    return <span>I am fine</span>; // ✅ returning JSX prevents the problem
  }
}

Installation

You'll first need to install ESLint:

npm i eslint --save-dev

Next, install eslint-plugin-react-google-translate:

npm install eslint-plugin-react-google-translate --save-dev

Usage

Add react-google-translate to the plugins section of your .eslintrc configuration file. You can omit the eslint-plugin- prefix:

{
  "plugins": ["react-google-translate"]
}

Then configure the rules under the rules section. They have been separated to allow the user to chose which rules to adopt.

{
  "rules": {
    "react-google-translate/no-conditional-text-nodes-with-siblings": "error",
    "react-google-translate/no-return-text-nodes": "error"
  }
}

Each rule can also be treated as a warning if an error is deemed too strict.

{
  "rules": {
    "react-google-translate/no-conditional-text-nodes-with-siblings": "error",
    "react-google-translate/no-return-text-nodes": "warn"
  }
}

Limitations

  • This plugin will highlight instances where a text node is generated by calling toString or toLocaleString, though it is not able to identify text nodes returned from other functions. For example, the following code will not show an error.
<p>
  {val ? getSomeValue() : <span>bar</span>} <span>hello world</span>
</p>
  • Conditional expressions are limited to a single ternary operator. Values derived from nested ternary expressions will not be reported.

  • Object properties are identified by the plugin, though only those which are one level deep.

<p>
  // ✅ `val.a` is only one level deep and will be reported
  {showVal ? val.a : <span>bar</span>} <span>hello world</span>
  // ❌ `val.a.b` is two levels deep and will not be reported
  {showVal ? val.a.b : <span>bar</span>} <span>hello world</span>
</p>
  • Optional chaining is not supported.
<p>
  // ❌ `val?.a` uses optional chaining and will not be reported
  {showVal ? val?.a : <span>bar</span>} <span>hello world</span>
  // ❌ `toLocaleString` being optionally chained will also fail to report
  {showVal ? val?.toLocaleString() : <span>bar</span>} <span>hello world</span>
</p>