Closed billneff79 closed 6 years ago
After thinking about this more, I wonder if we should just do composition with preact-markup
. E.g.
import Markup from 'preact-markup';
<Markup markup={<Text id="somethingWithMarkup"/>} type="html"/>
This appears to work with the suggestion of preact-markup
, but with the assistance of withText
to get a plain string to use as the markup
attribute:
@withText(({ id }) => ({ markup: <Text id={id} /> })
class Notify extends Component {
render({ markup }) {
assert(markup === 'I am a message <b>with markup!</b>.');
return (
<span>
<Markup markup={markup} type="html" trim={false} />
<span>
);
}
}
Now I wonder: Should we create a helper component to do this for the user (e.g. <MarkupText>
) which does this automatically, or should we document this as a recommended solution?
Here's a proof of concept for <MarkupText>
. It's pretty small for how useful this feature could be.
@withText((props) => ({ markup: <Text {...props} /> }))
class MarkupText extends Component {
render({ markup }) {
return (
<Markup markup={markup} trim={false} type="html" />
);
}
}
I like those approaches. We'll just want to make sure that any solution avoids pulling in preact-markup
unnecessarily (i.e. don't use it as a result of an object value or anything)
Can simplify via Localizer
:
const MarkupText = ({ id, children, ...props }) => (
<Localizer>
<Markup
{...props}
markup={<Text id={id}>{children}</Text>}
type="html"
/>
</Localizer>
);
... or without preact-markup at all:
const MarkupText = ({ id, children, ...props }) => (
<Localizer>
<Html {...props} html={<Text id={id}>{children}</Text>} />
</Localizer>
);
const Html = ({ html, ...props }) => (
<span dangerouslySetInnerHTML={{ __html: html }} {...props} />
);
I was messing around with this, and I had a more complex use case I thought I would share.
Say I take this one step further, and I need to do template replacement into a string that required both markup and a component, in this case <Icon />
You can extend @developit <MarkupText />
component to include a fields
argument like this:
const MarkupText = ({ id, fields, children, ...props }) => (
<Localizer>
<Html {...props} html={<Text id={id} fields={fields}>{children}</Text>} />
</Localizer>
)
Then use preact-render-to-string
to pre-render that component when passing it to <MarkupText />
:
<MarkupText id='nav.text' fields={
{ navArrowLeft: `<span class='nav__icons'>${render(<Icon name='prev' />)}</span>` }
} />
Assuming that your translation string contains {{navArrowLeft}}
.
We have use cases where we would like to insert markup inside of a phrase that should be translated as a whole unit, e.g.
<a href="http://example.com>Please click here</a> to open the page
As the system currently works, we would need to construct it as,
<Text id='link.pre'/><a href="http://example.com><Text id='link.text'/></a><Text id='link.post'/>
because different languages might translate this sentence akin toPlease, to open the page <a href="http://example.com>click here</a>
or other variations of ordering, which forces a before, during, and after markup set of text. This gets out of control if you have more than one piece of markup in your text. It also means that a translation service has to try to translate this set of strings:I image that is difficult for a translation service.
I wonder if this could be solved by simply allowing for markup in the string, and having a boolean flag for something like
<Text id="openPage" dangerouslySetInnerHTML />