Using react components in string for react-intl-universal - reactjs

Trying to use Link within an i18n string but it doesn't read the Link component properly. How do you include react components in react-intl-universal?
language json file
{
"somekey": "some<Link to={ link } somewhere </Link>"
}
javascript
import { Link } from 'react-router'
<Fragment>{ intl.getHTML('somekey', { link: `/somewhere` }) }</Fragment>

You cannot pass a component in react-intl-universal getHTML() method. When you call this method, react-intl-universal create a span element and sets its inner HTML. So the translation that you return with intl.getHTML() is just a HTML string and not a component that will be translated into HTML by react.
You should breakdown your translation in 2 parts and write something like:
import { Link } from 'react-router'
<Fragment>
{intl.get('contentBeforeLink')}
<Link to="/somewhere">
{intl.get('contentInsideLink')}
</Link>
</Fragment>

Related

how do I interpolate a Link component in Next-i18next / React i18next that changes position in the text

Currently I'm using Next.js with Next-i18next for I18N, but I understand that the React/i18next implementation is basically the same.
The problem I'm having is that I need to interpolate a next Link component inside some translation text, but depending on the language (English vs German), the order of the text and the link would change.
For instance the text I'm struggling with is: 'Accept data policy' vs 'Datenschutzerklärung akzeptieren'
As of the moment I have a quick fix by creating two values in the translation JSON files for the text and the link and then swapping the position based on the current language. Obviously this is not a sustainable solution. I have tried to utilise the 'Trans' component but this is showing some unexpected behaviour where the translation only kicks in after the page is refreshed, otherwise you see the text inside the Trans component.
example:
function LinkText({ href, children}) {
return <Link to={href || ''}>{children}</Link>;
}
return (
<Trans i18nKey="sentence">
text before link
<LinkText href="/data-policy">{t("dataPolicy")}</LinkText>
text after link
</Trans>
);
and the JSON in question:
{
"sentence": "agree to our <1><0/></1>",
"dataPolicy": "data policy"
}
Here's a link to CodeSandbox I made to replicate the problem with in React: link
(P.S The implementation of i18next doesn't seem to effectively swap out the languages in Codesandbox at the moment, but I included it as the code is there for a MWE)
Thanks in advance for your help, this has been driving me insane.
You had few missing parts,
Your i18next config was lack of a way to fetch the locale files, I've added i18next-http-backend.
You should use Trans component to inject the link to the sentence.
Your locale json should look like this:
{
"sentence": "Accept <0>data policy</0>"
}
// TranslatedLink.js
import React from 'react';
import { useTranslation, Trans } from 'react-i18next';
import { Link } from 'react-router-dom';
function LinkText({ href, children }) {
return <Link to={href || ''}>{children}</Link>;
}
export default function TranslatedLink() {
const { t } = useTranslation(['common']);
return (
<div style={{ padding: 50 }}>
<Trans i18nKey="sentence" t={t} components={[<LinkText href="/data-policy" />]} />
</div>
);
}
A working example: https://codesandbox.io/s/react-i18n-interpolation-issue-forked-ck8l4

reactJS adding an event listener to a navbar tile

I am running the current version of reactJS with hooks. I have three code modules in my app: header.js which creates a navbar and exports it to app.js which adds some other objects and exports all of this to index.js.
I am trying to add an event listener to the individual tiles in the navbar so that I can redirect to the appropriate page.
code
var listenerElement = document.getElementById("Tile1");
if (listenerElement !== null) {
listenerElement.addEventListener("click", navbarClicked) ;
console.log(listenerElement);
} else {
console.log("Element with ID=Tile1 not found");
}
<div id="Tile1" className="linkcontainer">Home</div>
/code
However, I cannot find an appropriate place to add the event-listener and the element with ID "Tile1" is never found - perhaps because it hasn't been rendered as yet?
The element in question is only rendered by index.js but I can't add a function after the reactDOM.render block in index.js - I get an error "not a react function"
Any suggestions would be much appreciated :-)
For react, you should use "refs" to link to a specific aspect of the navabar.
But as you are just trying to have something affect the navbar, you should use the "onClick" property for the div or iconButton or similar.
for example in a function component:
function handleClick() {
console.log("clicked");}
<nav> <iconButton onClick={handleClick} > button </iconButton> </nav>
https://reactjs.org/docs/handling-events.html
In react, you don't work with the DOM directly. React makes a copy of the DOM called virtual DOM and then compares them to update the DOM. You should add your event listener using props.
So instead of:
document.getElementById("Tile1").addEventListener("click", navbarClicked);
you should do <div onClick={navbarClicked} id="Tile1" className="linkcontainer">Home</div>

Create Html from React Component including Style

I have a simple react component in which using ref I am getting the div but I have to generate a html includes styling as well. So I can pass this html to PDF generation backend server.
pdfRef(elem){
console.log(elem);
//<div><span>dataPDF</span> </div>
}
render() {
return (
<div ref={(elem) => this.pdfRef(elem)} className="SomeCssClass">
<span >dataPDF</span>
</div>
);
}
}
[Edit]
When I try to print the div via ref, the elements are printed with class name. But when I send this string to pdf service, since only html element is sent and class name without the actual css , the pdf is generated without style.
is there any way to generate html with css as as string so further it can be send to pdf service. Hope the question is clear
Any pointers?
The server.js script in react-dom lets you render a React component to static html string. You can require it in your code like:
const ReactDOMServer = require('react-dom/server');
Or using ES6 syntax:
import ReactDomServer from 'react-dom/server'
After this you can render your component to HTML string using the ReactDomServer.renderToString or ReactDomServer.renderToStaticMarkup functions as follows:
const htmlStr = ReactDomServer.renderToStaticMarkup(<MyComponent prop1={'value1'} />);
This looks almost exactly like ReactDom.render, except that it doesn't need the second parameter of dom node to render at, and the html string is returned. Additionally this method can be used on both client and server side. For your generate-pdf use case renderToStaticMarkup would suffice. If required check the documentation at following link for subtle difference between the two methods mentioned above: https://reactjs.org/docs/react-dom-server.html

React - pass props/state to rendered HTML string?

In my React app, I have stored a text template as an HTML string on the server which is passed up to the client to be rendered. Is it possible to render this HTML string in such a way that it can access it's parent component state/props? I've tried using dangerouslySetInnerHTML and ReactDOMServer.renderToString(), both of which render the string as HTML, but render {props.text} as a literal string, rather than a reference to the component's props.
For example, on the server I have stored:
<div>Welcome to my app</div>
<div>{props.message}</div>
<div>Have fun</div>
And the component
import React from "react"
import { connect } from "react-redux"
const mapStateToProps = (state) => {
return { state }
},
WelomeBody = (props) => {
return (
<div dangerouslySetInnerHTML={{"__html": props.state.welcomeMessageBody}} />
)
}
export default connect(mapStateToProps, null)(WelomeBody)
but this results in:
Welcome to my app
{props.message}
Have fun
Is there a way that this can be rendered so as to access the value of props.message, rather than just rendering it literally?
If what you have in mind is to send down a React component (in JSX syntax) from your server to your client and have the client somehow rehydrate/compile it into an actual, working component, this is not achievable that easily.
When you build and bundle your React app, only components that are statically referenced/imported in your application at compile time can be used at runtime on the browser.
So, in order to dynamically render a component from a template and embed variables into it, your choices are:
Render it into final HTML on your server, send down that HTML and have a simple React component perform dangerouslySetInnerHTML for it. But, like you've already observed, that content has to be the full HTML code, no templates, variables, JSX, etc. Everything is string and HTML at this point, no more processing.
Alternatively, send down a Markdown document and have a Markdown component parse it into HTML and display it.
Create a sophisticated component that can receive a string, parse it, tokenize it, substitute values in it, etc. Essentially, create your own template-processing component that can read a template (the string sent down from your server) and embed the appropriate values into it.
A simple solution (to substitute values into a template) would be:
function Filler(props) {
let html = props.template;
Object.keys(props).forEach(key => {
if (key !== "template")
html = html.replace("{" + key + "}", props[key]);
});
return <div dangerouslySetInnerHTML={{__html: html}} />;
}
and use it like
<Filler template={"<h1>Hello, {firstname} {lastname}</h1>"} firstname="John" lastname="Doe" />
But again, this is far from a full-fledged actual React component.

React IF - ELSE Link does a real load of the page

I am using react and try to navigate to another route
using <Link>.
My problem is that a click on the link results in a real
page load instead of a SPA like navigation.
Ive noticed that this happens because i wrapped the link in a if else block.
This works:
<Link to="/login">Login</Link>
This does not work:
let loginOrLogout = (isUserLoggedIn) ?
(<Link to="/logout">Logout</Link>) :
(<Link to="/login">Login</Link>);
{loginOrLogout}
Try a React stateless component like:
function LoginOrLogout(props) {
if (props.isUserLoggedIn) {
return <Link to="/logout">Logout</Link>;
}
return <Link to="/login">Login</Link>;
}
call in the render method:
<LoginOrLogout isUserLoggedIn={isUserLoggedIn}>

Resources