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

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

Related

React-Intl pass translation as string variable and not object

I'm in the process of adding react-intl to a payment app I'm building but hitting a snag. I apologize if this has been addressed somewhere. I scoured the issues and documentation and couldn't find a direct answer on this (probably just overlooking it).
Use Case: Once a payment is processed I'd like to give the user the option to tweet a translated message indicating they've donated.
Problem: Twitter uses an iframe to "share tweets", and requires a text field as a string variable. When I pass my translation I get [object Object] in the tweet instead of the translated text. This makes sense based on my understanding of the translation engine. But I cant seem to find a way to pass a string rather than a translation object.
what I get when I use {translate('example_tweet')}
const translationText = object
what I need
const translationText = 'this is the translated text'
Question
How do I get the translated text as a string variable rather than an object to be rendered on a page?
Code
button
import { Share } from 'react-twitter-widgets'
import translate from '../i18n/translate'
export default function TwitterButton () {
return (
<Share
url='https://www.sampleSite.org' options={{
text: {translate('example_tweet')},
size: 'large'
}}
/>
)
}
translate
import React from 'react'
import { FormattedMessage } from 'react-intl'
const translate = (id, value = {}) => <FormattedMessage id={id} values={{ ...value }} />
export default translate
I was able to solve it without messing with react-intl. I built a function that scrapes the text I need from the page itself. So it really doesnt matter what the language is. I was hoping to figure out how to snag the translations as variables, but this gets the job done.
function makeTweetableUrl (text, pageUrl) {
const tweetableText = 'https://twitter.com/intent/tweet?url=' + pageUrl + '&text=' + encodeURIComponent(text)
return tweetableText
}
function onClickToTweet (e) {
e.preventDefault()
window.open(
makeTweetableUrl(document.querySelector('#tweetText').innerText, pageUrl),
'twitterwindow',
'height=450, width=550, toolbar=0, location=0, menubar=0, directories=0, scrollbars=0'
)
}
function TwitterButton ({ text, onClick }) {
return (
<StyledButton onClick={onClick}>{text}</StyledButton>
)
}

using links in react-i8next

I was learning react through online sources, and I'm unable to find the solution for my problem-
suppose I have a json file -
"test":"This is a test file, contact at {{email}}"
and currently i use it as -
const [t] = useTranslation();
<div>t('test',{{email}})<div>
suppose I want to change the colour of the email text only, how do I do that?
I researched online, and read the Transcomponent documentation, but I'm unable to understand how to implement it.
You'll have to exclude the {{email}} placeholder from the translated text.
So this would be the i18n part:
{
"test": "This is a test file, contact at"
}
And this would be the React part:
const { t } = useTranslation();
return (
<div>
{t("test")} <span style={{color: "hotpink"}}>{email}</span>
</div>
);
There are a lot of variations for what you are trying to do (e.g. using external stylesheet, CSS classes, and so on), but this would be a straight-forward approach.
You can handle that using a css file, for that you need to import it to your react component file:
import './styles.css';
For this to work you should create a style.css file on the same folder/directory of your react file, after that you should set a css rule:
style.css
a {
color: hotpink;
}

How do I apply a URL in a string?

I have some data in an object that I'm iterating through, and I'm pulling a property (string) from this object to render to the screen.
The object looks like this:
`object: { id: 1, sample: 'To learn all about React, click here https://en.wikipedia.org/wiki/React_(JavaScript_library)' }`
I did lots of research and a lot of the answers pointed to using the Linkify plugin. I set up the Linkify plugin like so:
<Linkify>{sample}</Linkify>
This works good but I'm wondering if I'm able to modify the string so that I'm not displaying the actual address and instead, could I assign the address to the word 'here'. For example:
'To learn all about React, click `here`'.
Is this possible with the Linkify plugin or do I have to do something different?
You can try parsing the string to fetch the url from it. and then use the url as the value to the href attribute in a tag./
To fetch the url you could use regex.
(https?:\/\/\S+)|([a-z]+\.[a-z]+(?:\/\S+)?)
I tried using the regex to parse your string and it totally works.
I have taken this regex from here https://stackoverflow.com/a/39944457/10100750. You could see the link to know about this regex further.
You can implement this with react as well. Create a link component, that accepts 2 props. {url} and {link}.
hyperLink.js
import React from 'react'
export default ({ text, link }) =>{
return(
<a href={link}> {text} </a>
)
}
Then import into your index your index.js
import Hyperlink from './hyperLink'
<div>
To learn more about react click <Hyperlink link={#} text="here">
</div>

Using react components in string for react-intl-universal

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>

ReactiveSearch - Can't Force a Selection (e.g. strictSelection) from the autoComplete?

I've followed the tutorials on ReactiveSearch, and I'm using it with React and a hosted Elastic instance on Appbase.io.
I want the user to see auto suggestions, but then only be able to select from the list of suggestions (so if "foo" isn't in the list of suggestions, the query shouldn't be executed).
This is because I don't want to have a search results page, just for the app to immediately take you to the right page based on the selected value.
I thought I could do this with strictSelection and onValueSelected, but it still is allowing a value like "foo" (which is not an autocomplete value) to go through.
import React, { Component } from "react";
import ReactDOM from "react-dom";
import { ReactiveBase, DataSearch } from "#appbaseio/reactivesearch";
class Main extends Component {
render() {
return (
<div className="flex-col lighter">
<ReactiveBase
app="bravos"
credentials="b8AuX6o06:19f6637f-0a80-48f7-8fe7-9fa0339b7c71"
>
<DataSearch
className=""
autosuggest={true}
strictSelection={true}
componentId="search"
placeholder="Search Name/Ticker"
dataField={["symbol", "name"]}
onValueSelected={value => {
document.location.href = `./${value}`;
}}
/>
</ReactiveBase>
</div>
);
}
}
ReactDOM.render(<Main />, document.getElementById("root"));
Codesandbox link: https://codesandbox.io/embed/wqjpoq25w
You've almost gotten it. The key here with strictSelection is to also check the cause of value selection in onValueSelected docs:
onValueSelected is called whenever a suggestion is selected or a search is performed by pressing enter key. It also passes the cause of action and the source object if the cause of action was 'SUGGESTION_SELECT'. The possible causes are:
'SUGGESTION_SELECT'
'ENTER_PRESS'
'CLEAR_VALUE'
This API helps in writing different flows for strictSelection. Here's how you may check for a suggestion selection:
<DataSearch
...
onValueSelected={(value, cause, source) => {
if (cause === 'SUGGESTION_SELECT') {
document.location.href = `./${value}`;
}
}}
/>
Demo

Resources