3

The URL structure we're implementing has URLS like mysite.com/en/some-page where en is the language the page is translated into. A simplified example of my code would be:

<Router>
    <Routes>
        <Route path="/" element={<RedirectToLocale />} />
        <Route path="/:locale">
            <Route index element={<Home />} />
            <Route path="about" element={<About />} />
            <Route path="news" element={<News />} />
            <Route path="*" element={<NotFound />} />
        </Route>
        <Route path="*" element={<NotFound />} />
    </Routes>
</Router>

RedirectToLocale simply redirects someone to the appropriate locale if they hit the base page.

The issue is this shows the home page for mysite.com/en (good) and mysite.com/asdf (bad). The latter should be caught by * as an error.

Previous versions of React Router had some level of RegEx support for Dynamic Segments but it seems v6 does not. Is there a way I can limit :locale to only known good strings and let the normal * match catch anything else?

I'm hoping the answer isn't "hard-code all your locales"...

dougoftheabaci
  • 665
  • 1
  • 6
  • 19

1 Answers1

2

Generally the answer is to hardcode the locales via layout routes, but if you want to render only a single layout route you can read and test the locale route path parameter in the layout component and redirect off the route if the parameter value is invalid.

Example testing for English|French locales:

console.log(/en|fr/gi.test("de"));
console.log(/en|fr/gi.test("en"));
console.log(/en|fr/gi.test("fr"));
import { Navigate, Outlet } from 'react-router-dom';

const LocaleLayout = () => {
  const { locale } = useParams();
  const isValidLocale = /en|fr/gi.test(locale);
  return isValidLocale
    ? <Outlet />
    : <Navigate to="/" replace />;
};

...

<Router>
  <Routes>
    <Route path="/" element={<RedirectToLocale />} />
    <Route path="/:locale" element={<LocaleLayout />}>
      <Route index element={<Home />} />
      <Route path="about" element={<About />} />
      <Route path="news" element={<News />} />
      <Route path="*" element={<NotFound />} />
    </Route>
    <Route path="*" element={<NotFound />} />
  </Routes>
</Router>
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • 1
    The logic for the redirect was a bit more complicated than this but it clued me in to a way of solving things. Thanks! For anyone who comes across this, I'm doing the validation based on some context where I get the total list of locales from a server. So I wait for that to populate initially and use a useEffect to manage some of my redirection logic. – dougoftheabaci Sep 16 '22 at 16:58
  • @dougoftheabaci Yes, doesn't sound much different than an implemented authentication check from a context/global state for route protection. [Same basic pattern](/a/66289280/8690857). – Drew Reese Sep 16 '22 at 17:00