Multilanguage support in react router - react-router

I'm building multilingual site where the language preference is part of the URL, e.g.
http://example.com/<somepage> (Russian, default)
http://example.com/en/<somepage> (English)
http://example.com/jp/<somepage> (Japanese)
http://example.com/../ (etc)
Everything is ok, when I use prefix for all languages:
<Route path="/:lang">
<Route path="somepage" component={Somepage}/>
</Route>
But for default language, I don't need to include language in url, as shown in example.
In fluxible router it can be solved by using regexp in path:
path: '/:lang([a-z]{2})?/<somepage>'
But it doesn't work in react router, because path must be a string, not a regexp.
Any ideas how to handle this use case?

Have you tried duplicating your routes? Seems to work for me thus far.
var innerRoutes = (
<Route>
<Route path="somepage" component={Somepage}/>
<Route path="otherpage" component={Otherpage}/>
</Route>
);
var routes = (
<Route path="/" component={App}>
{innerRoutes}
<Route path=":lang">
{innerRoutes}
</Route>
</Route>
);

your routes would need to look like:
<Router history={createBrowserHistory()}>
<Route component={App}>
<IndexRoute component={Home} />
<Route path=':lang/'>
<Route path='about' component={About} />
</Route>
<Redirect from='*' to='ru/about' />
</Route>
</Router>
The trailing slash in the :lang/ indicates that it will only be matched if the URL contains something after it (e.g. /de/about) otherwise there is a Redirect with a greedy matching which will always redirect to the page you specify in the to parameter. You can read more about Route Matching in the docs.

If you are using react-router v4 and react-intl you can use react-i18n-routing library

Related

react-router-dom switch not rendering components after dynamic path

I`ve been following an e-commerce tutorial and building on top of it. Im new to React and React Router Dom.
I've set a dynamic path for individual product pages, and now i' trying to add some new paths i.e. contact, about, etc.. If I add the new paths above the dynamic path they are rendered properly, but if I place the routes under the one with the dynamic path, for example the /hello, they won't render. Is this normal behaviour??
<Router>
<div>
<Navbar totalItems={cart.total_items} />
<Switch>
<Route exact path="/">
<Home products={products} handleAddToCart={handleAddToCart} fetchProduct={fetchProduct} />
</Route>
<Route exact path="/checkout">
<Checkout cart={cart} order={order} handleCaptureCheckout={handleCaptureCheckout} error={errorMessage} refreshCart={refreshCart} />
</Route>
<Route exact path="/cart">
<Cart
cart={cart}
handleUpdateCartQuantity={handleUpdateCartQuantity}
handleRemoveFromCart={handleRemoveFromCart}
handleEmptyCart={handleEmptyCart}
/>
</Route>
<Route exact path="/contact">
<Contact />
</Route>
<Route exact path="/:id">
<Details product={product} handleAddToCart={handleAddToCart} />
</Route>
<Route exact path="/hello">
<h1>Hello World</h1>
</Route>
</Switch>
</div>
<Router>
Yes, this behavior is completely normal, and expected. Recall that the Switch component "Renders the first child <Route> or <Redirect> that matches the location." This means that in the Switch component path order and specificity matter!
A path "/hello" is more specific than "/:id", so depending on route order may or may not be matched first. Or in other words, "/hello" can always be matched to "/:id", but not always the other way around.
You should always order the routes from more specific paths to less specific paths, and if done correctly there should be a near zero need for the exact prop.
"/hello" is more specific than "/:id" which is more specific than "/".
<Switch>
<Route path="/checkout">
<Checkout ... />
</Route>
<Route path="/cart">
<Cart ... />
</Route>
<Route path="/contact">
<Contact />
</Route>
<Route path="/hello">
<h1>Hello World</h1>
</Route>
<Route path="/:id">
<Details ... />
</Route>
<Route path="/">
<Home ... />
</Route>
</Switch>
If you had a nested "/contact/add" route for example, this is more specific than "/contact" and should be listed higher/before in the Switch.
Try removing the exact from the Route.
<Route exact path="/:id">
to:
<Route path="/:id">

React router path as an array

I have a code like this :
<BrowserRouter>
<Switch>
<Route path="/" exact component={component1} />
<Route path="/somewhere/:something" component={component2} />
</Switch>
</BrowserRouter>
I tried this, because in the end, I want to match several paths with the same component / result :
<BrowserRouter>
<Switch>
<Route path={["/somewhere/:something","/somewhere2/:something"]} component={component2} />
</Switch>
</BrowserRouter>
and the path is matched, but my parameter (:something) isnt passed to it. Any idea why ? react-router's docs tells me :
Any valid URL path or array of paths that path-to-regexp#^1.7.0 understands.
The feature was only recently added to React-Router. You need to upgrade your react-router installation to be able to match the documentation and use the feature.

redirect in react-router undefined?

This is what my react-router code looks like
render((
<Router history={browserHistory}>
<Route path={CORP} component={App}>
<IndexRoute component={Home} />
<Route path={"outreach"} component={OutReach}/>
<Route path={"careers/m"} component={Career}/>
<Route path={"members"} component={Members}/>
<Redirect from="*" to={"/home"} />
</Route>
</Router>
), document.getElementById('app'))
But when I go to my page, I get this error in my console
Uncaught ReferenceError: Redirect is not defined
How do I tell react-router to redirect the user to the /home only when the user's destination does not match any of the route paths mentioned above?
You just need to add
import { Redirect } from 'react-router';
In the top of your file

Nested Routes in React Router v4

I'm trying to set up some nested routes to add a common layout. Check the code out:
<Router>
<Route component={Layout}>
<div>
<Route path='/abc' component={ABC} />
<Route path='/xyz' component={XYZ} />
</div>
</Route>
</Router>
While this works perfectly fine, I still get the warning:
Warning: You should not use <Route component> and <Route children> in the same
route; will be ignored
CESCO's answer renders first the component AppShell then one of the components inside Switch. But these components are NOT going to render inside AppShell, they will NOT be children of AppShell.
In v4 to wrap components you don't put anymore your Routes inside another Route, you put your Routes directly inside a component.
I.E : for the wrapper instead of <Route component={Layout}> you directly use <Layout>.
Full code :
<Router>
<Layout>
<Route path='/abc' component={ABC} />
<Route path='/xyz' component={XYZ} />
</Layout>
</Router>
The change is probably explained by the idea to make React Router v4 to be pure
React so you only use React elements like with any other React element.
EDIT : I removed the Switch component as it's not useful here. See when it's useful here.
You need to use the switch component to nesting to work nice. Also, see this question
// main app
<div>
// not setting a path prop, makes this always render
<Route component={AppShell}/>
<Switch>
<Route exact path="/" component={Login}/>
<Route path="/dashboard" component={AsyncDashboard(userAgent)}/>
<Route component={NoMatch}/>
</Switch>
</div>
And version-4 components do not take children, instead, you should use the render prop.
<Router>
<Route render={(props)=>{
return <div>Whatever</div>}>
</Route>
</Router>
Try:
<Router>
<Layout>
<Route path='/abc' component={ABC} />
<Route path='/xyz' component={XYZ} />
</Layout>
</Router>
If you do not want Layout to run at loaded. Use this method:
<div className="container">
<Route path="/main" component={ChatList}/>
<Switch>
<Route exact path="/" component={Start} />
<Route path="/main/single" component={SingleChat} />
<Route path="/main/group" component={GroupChat} />
<Route path="/login" component={Login} />
</Switch>
</div>
Whenever history changes, componentWillReceiveProps in the ChatList will run.
You can also try this :
<Route exact path="/Home"
render={props=>(
<div>
<Layout/>
<Archive/>
</div>
)}
/>

how can i change the hash prefix/format of React-router

i'm using react-router in my app. it changes url like this:
xxx/index.html#/a1
xxx/index.html#/a2
but i want this:
xxx/index.html#!/a1
xxx/index.html#!/a2
because of my old app config.
i dont want to change the interface.
i had try to like this
<Route path="!/">
<Route name="a1" path="a1" handler={a1}/>
<Route name="a2" path="a2" handler={a2}/>
</Route>
or this
<Route path="!">
<Route name="a1" path="a1" handler={a1}/>
<Route name="a2" path="a2" handler={a2}/>
</Route>
but they all got
xxx/index.html#/!/a1
how can i do this ?
You could implement your own CustomLocation.
I've never done this myself, but you could look at the HashLocation implementation and change what's necessary.
Then you could just pass it to Router.run
Router.run(routes, MyCustomLocation, function (Handler) {
React.render(<Handler/>, document.body);
});