React-i18next: Nested HTML element within Trans seems like not working

Created on 30 Sep 2019  路  9Comments  路  Source: i18next/react-i18next

Describe the bug
Nested HTML element within Trans seems like not working

Occurs in react-i18next version
10.11.3

To Reproduce
Steps to reproduce the behavior:

i have this

<Trans i18nKey={"Are you sure you want to <0>delete</0> account  <0><1>{{name}}</1></0>  ?"} values={{name}} components={[<b key={0} />, <i key={1} />]} >
</Trans>               

{{name}} should be bold then italic, however, it becomes simply not shown.

Most helpful comment

But to be fair, this is a rather confusing API, that yields an awkward components prop declaration and hard to maintain translation texts like <0><0><0>this</0></0></0>.

I see there's already some ongoing discussion at #833 to allow for named placeholders by passing an object to components prop, which would help a lot.

In my opinion, making the numbered placeholders match the equivalent position in the components array would be a more intuitive API than having to track nesting levels.

But more importantly, how to use <Trans> with nested components should definitely be in the documentation.

All 9 comments

Does not work this way...inner <0><1> -> <1> must be inside b it's nesting not replacing by number

<Trans i18nKey={"Are you sure you want to <0>delete</0> account <1>{{name}}</1> ?"} values={{name}} components={[<b key={0} />, <b><i key={1} /></b>]} > </Trans>

@jamuhl I'm facing a similar problem, and I still don't understand how to properly use the components array, if they don't work by replacing the equivalent numbered tag. The documentation is not clear on this.

I need to map a large array of translations, with varying nesting of elements, and tried do something similar to this:

const keys = [
  'test1', // "<0>Text inside paragraph</0>"
  'test2', // "<0>Text inside paragraph with <1>bold text</1></0>",
  'test3', // "just some <1>bold text</1>",
  'test4' // "<0>Text inside paragraph with <3>a link</3> for the user</0>"
]

// ...

<ul>
  {keys.map(key => (
    <li key={key}>
      <Trans
        i18nKey={key}
        components={[<p />, <strong />, <a href='#'></a>]}
      />
    </li>
  ))}
</ul>

Expected output:

<ul>
  <li>
    <p>Text inside paragraph</p>
  </li>
  <li>
    <p>Text inside paragraph with <strong>bold text</strong></p>
  </li>
  <li>just some <strong>bold text</strong></li>
  <li>
    <p>Text inside paragraph with <a href='#'>a link</a> for the user</p>
  </li>
</ul>

Actual output:

<ul>
  <li>
    <p>Text inside paragraph</p>
  </li>
  <li>
    <p></p>
  </li>
  <li>just some <strong>bold text</strong></li>
  <li>
    <p></p>
  </li>
</ul>

How could I achieve the "expected" output using the <Trans> component, or by any other means in react-i18next?

@tisoap the problem is when you got nested numbers <0> hi <0>strong</0></0> it expects components={[<span><strong></strong></span>]} <- the nesting is also here

basically the same as:

<Trans><span>hello <strong>world</strong></span></Trans> // --> with a slightly difference in inner index the string would be -> <0> hi <1>strong</1></0>

Oh, now I finally understand how the components prop works! For future readers reference, this is how I could have written my example above to get the expected results:

const keys = [
  'test1', // "<0>Text inside paragraph</0>"
  'test2', // "<0>Text inside paragraph with <0>bold text</0></0>",
  'test3', // "just some <1>bold text</1>",
  'test4' // "<0>Text inside paragraph with <1>a link</1> for the user</0>"
]

// ...

<ul>
  {keys.map(key => (
    <li key={key}>
      <Trans
        i18nKey={key}
        components={[
          // index 0
          <p>
            { /* New nesting level means the index starts over */ }
            <strong /> { /* index 0 */ }
            <a href='#' /> { /* index 1 */ }
          </p>,
          // index 1
          <strong />
        ]}
      />
    </li>
  ))}
</ul>

But to be fair, this is a rather confusing API, that yields an awkward components prop declaration and hard to maintain translation texts like <0><0><0>this</0></0></0>.

I see there's already some ongoing discussion at #833 to allow for named placeholders by passing an object to components prop, which would help a lot.

In my opinion, making the numbered placeholders match the equivalent position in the components array would be a more intuitive API than having to track nesting levels.

But more importantly, how to use <Trans> with nested components should definitely be in the documentation.

@tisoap the main use case was always using Trans children...using components was just a fallback for the devs using ICU...but agree with you things can be improved:

  • feel free to improve the docs
  • feel free to provide a PR with a mode to use components index

Yes, I'll try to tackle those on my spare time!

"<0>Text inside paragraph with <0>bold text</0></0>",

Wouldn't that one be <1>bold text</1> as there is text before it? 馃

@DominicTobias-b1

<Trans
        i18nKey={key}
        components={[
          // index 0
          <p>
            { /* New nesting level means the index starts over */ }
            <strong /> { /* index 0 */ }
            <a href='#' /> { /* index 1 */ }
          </p>,
          // index 1
          <strong />
        ]}
      />

The JSX has no text in front...if so - yes would be <1>

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ezze picture ezze  路  4Comments

ok2ju picture ok2ju  路  3Comments

whtsky picture whtsky  路  4Comments

ChCosmin picture ChCosmin  路  4Comments

aniket-dalvi picture aniket-dalvi  路  4Comments