Search code examples
stringreactjsjsxgatsbytemplate-strings

How do i replace some text template with a custom JSX Component in ReactJS?


This is all about having translation text strings and implementing them in JSX.

Lets say I have two strings. One for english and another for spanish like this:

English

const phrase = `this is just a string with some [replace]weird[/replace] link inside`

Spanish

const phrase = `esto es solo un string con un [replace]raro[/replace] enlace dentro`

When I am in English mode the string will of course come as the first example.

I am trying to replace the [replace]word inside[/replace] with a component like this.

<p dangerouslySetInnerHTML={{
    __html: phrase.replace(/\[replace\](.*)\[\/replace\]/, <Link to={linkurl} >test</Link>)
}}>

The output is: this is just a string with some [object Object] link inside

This one works fine, using just plain html tags

<p dangerouslySetInnerHTML={{
    __html: phrase.replace(/\[replace\](.*)\[\/replace\]/, "<b>$1</b")
  }}>
</p>

the output is: this is just a string with some weird link inside

I've also tried the following:

<p dangerouslySetInnerHTML={{
    __html: phrase.replace(/\[replace\](.*)\[\/replace\]/, "<Link to=\""+linkurl+"\">$1</Link>")
  }}>
</p>

the output is: this is just a string with some weird link inside

but the word 'weird' should be a link element, and it's not...

By the way the component is just a component from gatsby, it allows you to navigate with routing (currently using reach router).


Solution

  • This is pretty easy to do if you treat your text templates as Markdown:

    1. Replace keywords with Markdown link syntax ([linked phrase](https://www.example.com/))
    2. Run the markdown through markdown-to-jsx to convert it to JSX
    3. Use the overrides option to use a custom component with a tags (e.g. a wrapper that extracts the href and provides it as the to prop on Gatsby's Link).

    If you want a leaner pipeline, you could piece something together with dangerouslySetInnerHTML but it won't be as flexible or easily sanitized.

    Example code:

    import * as React from "react"
    import Link from "gatsby"
    import Markdown from "markdown-to-jsx"
    
    const MagicText = ({ children, linkUrl }) => (
      <Markdown
        options={{
          overrides: {
            replace: Link,
          },
        }}
      >
        {children
          .replace("[replace]", `<replace to=${linkUrl}>`)
          .replace("[/replace]", "</replace>")}
      </Markdown>
    )
    

    And in use:

    <MagicText linkUrl="https://www.example.com/">{phrase}</MagicText>