Closed da1nerd closed 6 years ago
Yea I will have to give that some thought. Right now any HTML is rendered by using React's dangerouslySetInnerHTML prop.
In order to accomplish something like this you'd need something to convert a string version of JSX, and have that converted to fully rendered React component with props and state. I'm pretty sure there is no out of the box way to accomplish this at runtime. There may be a way to do it during a bundling step, and have it somehow run the translation string through the babel JSX transform for example.
Anyways as I mentioned this will require some thought, but if you have any ideas on how this might be accomplished feel free to send my way.
Yes I agree this would be complicated. There is this library that converts HTML to a React tree https://github.com/aknuds1/html-to-react. However, this could quickly turn your tidy localize library into a monolith like some other localization libraries.
To make things a little simpler you could potentially expose your translation rendering so that a custom renderer could be used. Then a plugin could be made that uses https://github.com/aknuds1/html-to-react.
That way all the work is not on you to maintaining that complicated piece.
I have done a draft implementation of how I think this could be achieved without any major breaking changes*.
https://github.com/thchia/react-localize-redux/tree/data-component
The basic idea is that you can pass a React Component to data
like so:
const StrongName = ({ name }) => <strong>{name}</strong>
const translations = {
greeting: 'Hello ${name}'
}
...
<Translate id='greeting' data={{ name: <StrongName name='Ryan' /> }} />
This is achieved by converting the templater
function to return a string if there are no React components in data
(like normal). If there are React components, it returns an array representation of the string to be translated, like:
[ 'Hello ', <StrongName /* ...props */ />]
Then in getLocalizedElement
, if the result form templater
is a string, perform the usual conversion to dangerouslySetInnerHTML
. Otherwise, return
React.createElement('span', null, ...arrayFromTemplater)
* One problem I have not been able to solve is that if you want to use React components as arguments, you cannot have html in the translation. This is because the new templater
will return something like this:
[ '<p>Hello ', <Component />, '</p>' ]
Which cannot be converted to innerHTML
since it is a mixture of string literal HTML and React components.
Willing to discuss further if this looks like something you would consider supporting @ryandrewjohnson.
@thchia thanks for putting this together. Unfortunately I don't have much bandwidth to look into your solution, as what little time I do have right now is going towards getting v3 #67 ready. Once that is published I'll have some time to take a closer look at this. In the meantime maybe have a look at v3, as there are some significant changes that would most likely impact this implementation.
No worries, it's a fairly rough implementation anyway. In the meantime I will take a look at v3 and try to do a similar thing there.
Edit: The only things I changed were templater
and getLocalizedElement
anyway so I have hope for v3 😃
@thchia I've officially added you as a collaborator. Thanks for all your help, and feel free to assign any issues you want to work on to yourself.
Just wanted to say it's exciting to see the potential for this feature!
Tracking this in #100
Added in #100 and published in v3.2.0
. Thanks for the create work on this one @thchia.
It would be amazing if I could inject components into a string.
Let's suppose I have this translation
I'd like to be able to do this:
The result would be:
This is just a simple sample which can actually already be accomplished. However, I'm interested in being able to attach click listeners to components and then inject them into the translation.