How can I use text formatting (bold, italic, etc.) with i18n using Gatsby? - internationalization

I'm using gatsby-plugin-react-i18next for translating my website, and it works with simple text. But when I try to format parts of the text, with bold text or italic text, it doesn't work (I don't know how to do it).
How can I format a specific part of a paragraph using i18n?
Below is an example of my setup.
page JS
const IndexPage = () => {
const { t } = useTranslation();
return (
<Layout>
<Seo title="Home" />
<div>
<h1>
{t("HomepageHeader")}
</h1>
<p>
{t("HomepageDescription")}
</p>
</div>
</Layout>
)
}
export default IndexPage
Folder structure:
locales
-en
--translation.json
-nl
--translation.json
Example JSON en
{
"HomepageHeader": "Grow your business with a modern website!",
"HomepageDescription": "Your website is the number 1 selling point, to your customers. Make sure you get the most out of it!"
}
How can I make for example only "number 1 selling point" in the HomepageDescription bold?

Have a look at the Trans Component: https://react.i18next.com/latest/trans-component
Or use a markdown component, something like:
import React from 'react';
import Markdown from './Markdown';
import { useTranslation } from '../utils';
export function Text({
i18nKey,
ns = 'client-locize-app-loaders',
i18nOptions = {},
message,
defaultValue,
linkTarget = '_blank',
}) {
const { t, ready } = useTranslation(ns, { useSuspense: false });
if (!ready)
return (
<Markdown source={message || 'loading...'} noContainer options={{ linkTarget: '_blank' }} />
);
return (
<Markdown
source={message || t(i18nKey, { defaultValue, ...i18nOptions })}
noContainer
options={{ linkTarget }}
/>
);
}
import React from 'react';
import { Remarkable } from 'remarkable';
export class Markdown extends React.Component {
constructor(props) {
super(props);
this.content = this.content.bind(this);
this.renderMarkdown = this.renderMarkdown.bind(this);
}
componentWillUpdate(nextProps, nextState) {
if (nextProps.options !== this.props.options) {
this.md = new Remarkable(nextProps.options);
}
}
content() {
if (this.props.source)
return <span dangerouslySetInnerHTML={{ __html: this.renderMarkdown(this.props.source) }} />;
return React.Children.map(this.props.children, (child) => {
if (typeof child === 'string') {
return <span dangerouslySetInnerHTML={{ __html: this.renderMarkdown(child) }} />;
}
return child;
});
}
renderMarkdown(source) {
if (!this.md) this.md = new Remarkable(this.props.options);
if (this.props.renderInline) return this.md.renderInline(source);
return this.md.render(source);
}
render() {
const Container = this.props.container;
if (this.props.noContainer) return this.content();
return (
<Container className={this.props.className} style={this.props.style}>
{this.content()}
</Container>
);
}
}
Markdown.defaultProps = {
noContainer: false,
renderInline: false,
container: 'div',
options: {},
className: '',
};

Related

Trouble rendering react components that import google-maps-react on Heroku only

I have a react-in-rails application that utilizes the google-maps-react api. The app works fine locally but when deployed to heroku, any component that imports google-maps-react does not render. Since this is generally the landing page for most users, the app is not accessible at all.
When all the components that import or render google-maps-react are removed, the app deploys correctly.
import React from "react"
import MapContainer from "./MapContainer"
import StoreList from './StoreList'
class FindBar extends React.Component {
render () {
const {stores, openTab, success} = this.props
return (
<div className="findbar" >
<div className="mapcomponent">
<MapContainer
stores={stores}
openTab={openTab}
success={success}
/>
</div>
<br/>
<StoreList
stores={stores}
openTab={openTab}
/>
{this.props.success &&
<Redirect to="/user_home/opentabs" />
}
</div>
);
}
}
export default FindBar
import React, { Component } from 'react';
import { Button, Card } from 'reactstrap';
import { Map, GoogleApiWrapper, Marker, InfoWindow } from 'google-maps-react';
import UserHome from './UserHome.js'
import StoreMarkerWindow from './StoreMarkerWindow.js'
import InfoWindowEx from './InfoWindowEx.js'
const mapStyles = {
width: '100%',
height: '100vh',
};
class MapContainer extends Component {
constructor(props) {
super(props)
this.state = {
showingInfoWindow: false,
activeMarker: {},
selectedPlace: {},
address: [],
location: {},
displayMarkers: [],
success: false,
}
}
componentDidMount = () => {
this.fetchMarkers()
}
componentDidUpdate = (prevProps) => {
if (prevProps.stores === this.props.stores){
return true
}
this.fetchMarkers()
}
openTab = () => {
console.log(this.state.selectedPlace.storeId)
// this.props.openTab(this.state.selectedPlace.storeId)
}
onClick = (props, marker, e) => {
this.setState({
selectedPlace: props,
activeMarker: marker,
showingInfoWindow: true
})
}
onClose = props => {
if (this.state.showingInfoWindow) {
this.setState({
showingInfoWindow: false,
activeMarker: null
});
}
}
fetchMarkers = () => {
const newMarkers = []
this.props.stores.map((store, index) => {
const location = `${store.address1}, ${store.city}, ${store.state}, ${store.zip}`
this.geocodeAddress(location)
.then((geoco)=>{
newMarkers.push({lat: geoco.lat,
lng: geoco.lng,
storeId: store.id,
name: store.establishmentname,
location: location,
info: store.additionalinfo,
})
this.setState({ displayMarkers:newMarkers})
})
})
}
// create a function that maps stores.address, stores.city, stores.state, stores.zipcode
// and returns it to the geocodeAddress and then geocodeAddress returns it to
// the displayMarkers
geocodeAddress = (address) => {
const geocoder = new google.maps.Geocoder()
return new Promise((resolve, reject) => {
geocoder.geocode({'address': address}, function(results, status) {
if (status === google.maps.GeocoderStatus.OK) {
resolve(results[0].geometry.location.toJSON())
} else {
reject()
}
})
})
}
render() {
const{
activeMarker,
showingInfoWindow,
selectedPlace,
onMapOver,
}=this.props
return (
<div className="mapContainer" style={mapStyles}>
<Map
google={this.props.google}
onMouseover={this.onMapOver}
zoom={14}
style={mapStyles}
initialCenter={{
lat: 32.7091,
lng: -117.1580
}}
>
{this.state.displayMarkers.map((coordinates, index) => {
const{storeId, lat, lng, name, location, info} = coordinates
return (
<Marker onClick={this.onClick}
key={index}
id={storeId}
name={name}
position = {{lat, lng}}
location={location}
info= {info}
>
</Marker>
)
})}
<InfoWindowEx
marker={this.state.activeMarker}
visible={this.state.showingInfoWindow}
onClose={this.onClose}
>
<div>
<StoreMarkerWindow
name={this.state.selectedPlace.name}
location={this.state.selectedPlace.location}
info={this.state.selectedPlace.info}
id={this.state.selectedPlace.id}
openTab={this.props.openTab}
/>
</div>
</InfoWindowEx>
</Map>
</div>
);
}
}
export default GoogleApiWrapper({
apiKey: 'xxxx'
})(MapContainer);
TypeError: t is not a function
at Object.a (windowOrGlobal.js:18)
at Object.<anonymous> (windowOrGlobal.js:5)
at Object.<anonymous> (windowOrGlobal.js:5)
at n (bootstrap:19)
at Object.<anonymous> (ScriptCache.js:3)
at n (bootstrap:19)
at Object.<anonymous> (GoogleApiComponent.js:5)
at n (bootstrap:19)
at Object.<anonymous> (index.js:5)
at n (bootstrap:19)

redirect dependent on ajax result using react

I would like to redirect to a component in case the data of the success has a certain value.
When ajax returns the data, depending on the value of the data redirected to the Contents class that I previously imported.
I've been looking for information about the push method
My error is: Error: Invariant failed: You should not use <Redirect> outside a <Router>
import React, { Component } from 'react';
import { Modal,Button } from 'react-bootstrap';
import $ from 'jquery';
import { Redirect } from 'react-router';
import Contents from './Contents';
class Login extends Component {
constructor(props, context) {
super(props, context);
this.handleShow = this.handleShow.bind(this);
this.handleClose = this.handleClose.bind(this);
this.handleloginClick = this.handleloginClick.bind(this);
this.handleUsernameChange = this.handleUsernameChange.bind(this);
this.handlePasswordChange = this.handlePasswordChange.bind(this);
this.state = {
show: true,
username: "",
password: "",
};
}
handleloginClick(event) {
var parametros = {
username: this.state.username,
password: this.state.password
}
const { history } = this.props;
$.ajax({
data: parametros,
url: "https://privada.mgsehijos.es/react/login.php",
type: "POST",
success: function (data) {
}
});
}
handleUsernameChange(event) {
this.setState({username: event.target.value});
}
handlePasswordChange(event) {
this.setState({password: event.target.value});
}
handleClose() {
this.setState({ show: false });
}
handleShow() {
this.setState({ show: true });
}
render() {
If(Condicion){
return (<Redirect to={'./Contents'} />);
}
return (
//Here my modal.
);
}
}
export default Login;
you can use Router dom to navigate.
My fiddle: https://jsfiddle.net/leolima/fLnh9z50/1/
const AboutUs = (props) => {
console.log(props.location.state)
console.log('Hi, you are in About page, redirecting with router dom in 3 seconds')
setTimeout(() => {
props.history.push('/')}, 3000);
return <h1>Now we're here at the about us page.</h1>;
};
Full Example:
// Select the node we wish to mount our React application to
const MOUNT_NODE = document.querySelector('#app');
// Grab components out of the ReactRouterDOM that we will be using
const { BrowserRouter, Route, Switch, NavLink, Link } = window.ReactRouterDOM;
// PropTypes is used for typechecking
const PropTypes = window.PropTypes;
// Home page component
const Home = () => {
return <h1>Here we are at the home page.</h1>;
};
// AboutUs page component
const AboutUs = (props) => {
console.log(props.location.state)
return <h1>Now we're here at the about us page.</h1>;
};
// NotFoundPage component
// props.match.url contains the current url route
const NotFoundPage = ({ match }) => {
const {url} = match;
return (
<div>
<h1>Whoops!</h1>
<p><strong>{url.replace('/','')}</strong> could not be located.</p>
</div>
);
};
// Header component is our page title and navigation menu
const Header = () => {
// This is just needed to set the Home route to active
// in jsFiddle based on the URI location. Ignore.
const checkActive = (match, location) => {
if(!location) return false;
const {pathname} = location;
return pathname.indexOf('/tophergates') !== -1 || pathname.indexOf('/_display/') !== -1;
}
return (
<header>
<h1>Basic React Routing</h1>
<nav>
<ul className='navLinks'>
{/* Your home route path would generally just be '/'' */}
<li><NavLink to="/tophergates" isActive={checkActive}>Home</NavLink></li>
<li><Link to={{
pathname: "/about",
state: { fromDashboard: true }
}}>About</Link></li>
</ul>
</nav>
</header>
);
};
// Out layout component which switches content based on the route
const Layout = ({children}) => {
return (
<div>
<Header />
<main>{children}</main>
</div>
);
};
// Ensure the 'children' prop has a value (required) and the value is an element.
Layout.propTypes = {
children: PropTypes.element.isRequired,
};
// The top level component is where our routing is taking place.
// We tell the Layout component which component to render based on the current route.
const App = () => {
return (
<BrowserRouter>
<Layout>
<Switch>
<Route path='/tophergates' component={Home} />
<Route path='/_display/' component={Home} />
<Route exact path='/' component={Home} />
<Route path='/about' component={AboutUs} />
<Route path='*' component={NotFoundPage} />
</Switch>
</Layout>
</BrowserRouter>
);
};
// Render the application
ReactDOM.render(
<App />,
MOUNT_NODE
);

Is there a simple way of implementing a column picker for a List?

We are going to implement a columnpicker and currently the only idea I have is to implement a ColumnPickableList that wraps a List. This would also hold a list of checkboxes that will enable the user to hide a column.
But before I go ahead do that I just wondered if I'm reinveting the wheel and if there is a simpler approach to solving this?
No simpler way. You'll have to implement your own List component for that
I'm following up on this since I'm struggling to make this work. Maybe it is because I have chosen to create a wrapper that filters the children to be displayed. So techically this approach doesn't implement its own List.
I have made a naive draft which I was hoping would work, but it fails to re-render the children even though they are changed/filtered in the parent component.
The console.log(..) in ColumnPickableList render()-function does print the correct children/props, but still the children won't update/re-render. Any clues as to why? Is this approach too naive?
So here is the current draft:
ColumnPicker.js
import React, { PropTypes } from 'react';
import Checkbox from 'material-ui/Checkbox';
export default class ColumnPicker extends React.Component {
constructor(props) {
super(props);
this.onCheck = this.onCheck.bind(this);
}
onCheck(column, isChecked) {
return this.props.onCheckboxChanged(column, isChecked);
}
renderCheckbox(column, onCheck) {
const disabled = (column.source === 'id');
return (<Checkbox key={column.source} label={column.source.toUpperCase()} onCheck={(event, checked) => onCheck(column, checked)} defaultChecked disabled={disabled} />);
}
render() {
const columns = this.props.columns || [];
return (
<div className="column-picker">
{columns.map((column) => {
return this.renderCheckbox(column, this.onCheck);
})}
</div>
);
}
}
ColumnPicker.propTypes = {
columns: PropTypes.array,
onCheckboxChanged: PropTypes.func,
};
ColumnPicker.defaultProps = {
columns: [], // [{source: myField, checked: true} ...]
};
ColumnPickableList.js:
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { List, Datagrid } from 'admin-on-rest';
import ColumnPicker from './ColumnPicker';
import { toggleColumnPickerStatusAction, initializeColumnPickerAction } from './actions';
export class ColumnPickableList extends React.Component {
componentWillMount() {
let columnSourceNames = [];
if (this.props.children) {
columnSourceNames = React.Children.map(this.props.children, (child) => {
return ({ source: child.props.source, checked: true });
});
}
const columnsDisplayed = columnSourceNames.filter((column) => column.source);
this.props.initializeColumnPicker(this.props.resource, columnsDisplayed);
}
shouldComponentUpdate(nextProps) {
const diff = nextProps.columnsDisplayed.filter((currentColumn) => {
return !this.props.columnsDisplayed.some((prevColumn) => {
return currentColumn.source === prevColumn.source && currentColumn.checked === prevColumn.checked;
});
});
return diff.length > 0;
}
removeHiddenColumns(children) {
return React.Children.map(children, (child) => {
if (!child.props.source) {
return child;
}
const column = this.props.columnsDisplayed.find((columnDisplayed) => {
return columnDisplayed.source === child.props.source;
});
if (this.props.columnsDisplayed.length === 0 || (column && column.checked)) {
return React.cloneElement(child);
}
return null;
});
}
render() {
const { children, ...rest } = this.props;
const displayedChildren = this.removeHiddenColumns(children);
console.log('Does it render? Rendering children', displayedChildren.map((child) => child.props.source));
return (
<div className="columnpickable-list">
<ColumnPicker columns={this.props.columnsDisplayed} onCheckboxChanged={this.props.handleCheckboxChanged} />
<List {...rest}>
<Datagrid>
{displayedChildren}
</Datagrid>
</List>
</div>
);
}
}
ColumnPickableList.propTypes = {
resource: PropTypes.string,
columnsDisplayed: PropTypes.array,
children: PropTypes.node,
initializeColumnPicker: PropTypes.func,
handleCheckboxChanged: PropTypes.func,
};
ColumnPickableList.defaultProps = {
columnsDisplayed: [],
};
function mapStateToProps(state) {
return {
columnsDisplayed: state.columnsDisplayed || [],
};
}
actions.js:
export const actions = {
INIT_COLUMNPICKER: 'INIT_COLUMNPICKER',
TOGGLE_COLUMNPICKER_STATUS: 'UPDATE_COLUMNPICKER_STATUS',
UPDATE_COLUMNPICKER_STATUSES: 'UPDATE_COLUMNPICKER_STATUSES',
}
export function initializeColumnPickerAction(resource, columns) {
return {
type: actions.INIT_COLUMNPICKER,
columns,
meta: { resource },
};
}
export function toggleColumnPickerStatusAction(column) {
return {
type: actions.TOGGLE_COLUMNPICKER_STATUS,
column,
};
}
reducers.js:
import { actions } from './actions';
function columnPickerReducer(state = [], action) {
switch (action.type) {
case actions.INIT_COLUMNPICKER: {
console.log('Init columnopicker reducer');
return action.columns;
}
case actions.TOGGLE_COLUMNPICKER_STATUS: {
const columns = state.map((column) => {
if (column.source === action.column.source) {
return { ...column, checked: !column.checked };
}
return column;
});
return columns;
}
default:
return state;
}
}
export default columnPickerReducer;
Example snippet of parent component:
...
<ColumnPickableList title="SillyStuff" {...props}>
<TextField source="id" />
<TextField source="NAME" />
<TextField source="SILLY_NAME" />
<TextField source="CHANGED_BY" />
<DateField source="CHANGED_TS" showTime />
<EditButton />
<DeleteButton />
</ColumnPickableList>
...

relay refetch doesn't show the result

I'm trying to create a live search-result component(lazy load one). It works perfectly for the first time but refetch doesn't update the data. I see the request and respoonse in Network tab! so it does get the data, but it doesn't supply it to the component!
any idea why?
import React, { Component } from 'react';
import {
createRefetchContainer,
graphql,
} from 'react-relay';
import ProfileShow from './ProfileShow';
class ProfileList extends Component {
render() {
console.log("rendering....", this.props)
return (
<div className="row">
<input type="text" onClick={this._loadMe.bind(this)} />
{this.props.persons.map((person) => {
return (
<div className="col-md-3">
<ProfileShow person={person} />
</div>
);
})}
</div>
);
}
_loadMe(e) {
const refetchVariables = fragmentVariables => ({
queryStr: e.target.value,
});
this.props.relay.refetch(refetchVariables, null, (...data) => {
console.log(data)
});
}
}
const FragmentContainer = createRefetchContainer(
ProfileList,
{
persons: graphql.experimental`
fragment ProfileList_persons on Person #relay(plural: true) {
fullname
number
email
pic
}
`
},
graphql.experimental`
query ProfileListRefetchQuery($queryStr: String!) {
talentList(query: $queryStr) {
...ProfileList_persons
}
}
`,
);
export default FragmentContainer;

Set state like this props in react

Hello i have this code
import React from 'react'
import Link from 'react-router/lib/Link'
import { connect } from "react-redux"
import { load } from '../../actions/customerActions'
import List from './list';
import MdAdd from 'react-icons/lib/md/add'
#connect(store => {
return {
customers: store.customer.customers
}
})
export default class Customer extends React.Component {
componentDidMount() {
this.props.dispatch(load({location:localStorage.getItem('locationb')}));
}
render() {
const { customers } = this.props;
const tea = customers.customers && customers.customers.map(customer => <List key={customer.profile} customer={customer} />) || [];
return(
<div class="container">
{ customers.customers ?
<div class="columns is-multiline mb-100">
{ tea }
</div>
: 'Não exitem Clientes'}
<Link to="/customer/create" class="button is-info btn-rounded" title="Novo"><MdAdd /></Link>
</div>
)
}
}
But i only have access to customers in render passing this props.
How can i pass customer to a state variable in component did mount or else ?
i mean customers const { customers } = this.props; how i make like this.setState({customers: customers}) Having in the beginning this.state(customers: [])
YOu can use
componentWillReceiveProps(newProps){
console.log(newProps.customers.customers)
this.setState({customers: newProps.customers.customers})
}
it works for me
thanks
Carlos Vieira

Resources