Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Links and other tags in messages #68

Closed
gpbl opened this issue Jan 21, 2015 · 10 comments
Closed

Links and other tags in messages #68

gpbl opened this issue Jan 21, 2015 · 10 comments

Comments

@gpbl
Copy link

gpbl commented Jan 21, 2015

How would you deal with messages containing tags, e.g. links?

For example this can't be rendered by React:

const message = 'Visit <a href="https://github.com">github</a> now!';

A solution is that in use by khan academy. Then I would write something like:

const messages = { visit: 'Visit %(link)s now!', link: 'github' }
<p>
  <$_ link={ <a href="https://github.com">this.getIntlMessage('link')</a> }>
       { this.getIntlMessage('visit') }
  </$_>
</p>

I wonder how are other developers solving this case? Could react-intl help with it?

@ericf
Copy link
Collaborator

ericf commented Jan 21, 2015

@gpbl In the soon-to-finished v1.1.0 release we're adding React Components — They'll become the recommended way to use React Intl — and one new component is <FormattedHTMLMessage>:

const message = 'Visit <a href="https://github.com">github</a> now!';
<p><FormattedHTMLMessage message={message} /></p>

That said, the way we have to implement the <FormattedHTMLMessage> component so that it's safe (it will HTML-escape values, but assumes HTML in the message string is trusted), means we end up needing to construct a fragment of HTML that is then injected via dangerouslySetInnerHTML. This means we have to forfeit React's virtual DOM diffing, so if you can we'd recommend using <FormattedMessage> like this, which React can diff:

const message = 'Visit {link} now!';
<p>
  <FormattedMessage
    message={message}
    link={<a href="https://github.com">github</a>} />
</p>

This removes the HTML from the static message string and moves it into JSX land where both the <FormattedMessage> and <FormattedHTMLMessage> components can accept and work with React Elements passed as prop values.


This stuff is available right now on master and you can get the latest v1.1.0 RC release:

npm install react-intl@next

@gpbl
Copy link
Author

gpbl commented Jan 21, 2015

Awesome, I had not even thought to pass <FormattedMessage> a react element. Thanks a lot for the tip.

The FormattedHTMLMessage is a very welcome addition, I have a case where I can't avoid adding some simple formatting, like bolds and italics. At least I can hide that dangerouslySetInnerHTML from my code and let react-intl do the dirty work :-)

@gpbl gpbl closed this as completed Jan 21, 2015
@ericf
Copy link
Collaborator

ericf commented Jan 21, 2015

Awesome to hear! Yeah we just added support for being able to pass React Elements as prop values when formatting messages: #65 (comment)

I'm working on updating the docs for the site now and we'll add an example of doing this so people are aware that it's possible.

@geekyme
Copy link

geekyme commented Apr 21, 2015

@ericf I just ran into this similar issue as well and I realized that while we can write 'Visit {link} now!', the text inside {link} will not be translated.

It will be useful to have the entire 'Visit {link} now!' string translated so any kind of string extraction CLI tool will extract the strings with its full contents so that translators can know how to translate.

Ref: #89

@firaskrichi
Copy link

firaskrichi commented Jan 22, 2017

Is there a way to translate what's inside 'link' ?

@esellin
Copy link

esellin commented Feb 1, 2017

I ended up doing something like this:

<FormattedMessage
  id="HELP_PREVIEW_6"
  values={{
    settings: (
      <Link to={`/setup/${this.props.params.eventId}/settings`}>
        <FormattedMessage id="TITLE_SETTINGS" />
      </Link>
    )
  }} />

with my HELP_PREVIEW_6 string containing something like

Go to {settings}

@phiggins42
Copy link

Just to throw my $0.02 in here, I needed a way to put a link around individual words in the source bundles, but couldn't rely on an english-only token to look for so came up with:


import React from 'react';
import { Link } from 'react-router-dom';

/**
 * Detect special characters in a string, and create <Link> elements anywhere
 * a link is described. This is used to put anchors around words inside of i18n
 * messages, to avoid having to maintain raw html inside.
 *
 * linkMessage('This is a ((test|/home))') would generate:
 * ['This is a ', <Link to=/home>test</Link>]
 *
 * @param {string} content The string content to scan for anchor markers
 * @returns {Array} A mixed array of strings and JSX components
 */
const linkMessage = content => (
  content
    .split(/(\(\(.*?\|?.*?\)\))/g)
    .map((part, index) => {
      if (/^\(\(/.test(part)) {
        // if the part starts with '((' break it up into link parts
        const [anchor, href] = part.replace(/[()]+/g, '').split('|');
        return (
          <Link key={ index } to={ href.trim() }>
          { anchor.trim() }
          </Link>
        );
      }
      return part;
    })
);

and the usage is:

<FormattedMessage id='somekey'>
  { text => <span>{ linkMessage(text) }</span> }
</FormattedMessage>

in case anyone else finds it useful.

@ledahu05
Copy link

ledahu05 commented Sep 8, 2019

Awesome, just what I was looking for. Thanks a lot, it works like a charm.

@nicolasrenon
Copy link

nicolasrenon commented Oct 19, 2020

@phiggins42 it's an interesting approach, but I don't see where you make /home as a variable.

Ideally we would have something like that standardized:

<FormattedMessage
  id="some.text.with.link"
  defaultMessage="Click {url|`on this link`} to read more."
  values={{
    url: localizedUrl,
  }}
/>
  • The translator would know they need to translate on this link as part of the message too.
  • url variable works exactly as it would be as {url}

Note: I'm using the backtick as a safeguard in case we need quotes.

@longlho
Copy link
Member

longlho commented Oct 19, 2020

We already support rich text natively

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants