javascriptreactjsreact-routerreact-i18nextnested-routes

React Router V6 nested Routes with i18n


I have a question about React Router V6 nested with i18n.

This is my first multi-language service.

const MainPage:React.FC = () => {

  const lang = i18n.language;

  return (
    <>
      <Wrapper>
        <Routes>
          {/* Main */}
          <Route path={`/`} element={<Home />}>
            <Route path={`${lang}`}>
              <Route path={`service`}>
                <Route path={'slack'} element={<Slack />} />
              </Route>
            </Route>
            {/* <Route path={`service/dooray`}element={<Dooray />} /> */}
            {/* <Route path={`contact`} element={<Contact />} /> */}

            {/* <Route path={`app/sign-in`} element={<SignIn />} /> */}
            {/* <Route path={`app/sign-up`} element={<SignUp />} /> */}
            {/* <Route path={`app/mail-code`} element={<MailCode />} /> */}
            {/* <Route path={`app/password/reset`} element={<PwdReset />} /> */}

            {/* <Route path={`policies/privac`} element={<Privacy />} /> */}
            {/* <Route path={`policies/terms`} element={<Terms />} /> */}
          </Route>
          {/* <Route path={`*`} element={<>NOT FOUND</>} /> */}
          {/* test */}
        </Routes>
      </Wrapper>
      <ParentModal />
    </>

If I enter localhost:3000/en, there is an error 'This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.'

How can I fix it..

I want /en => go to english page, /jp => go to japanese page


const MainPage:React.FC =() => {

...

<Route path={`/`} element={<Home />}>
    <Route path={`/${lang}/*`}>
       <Route path={`service`}>
           <Route path="slack" element={<Slack />} />
       </Route>
    </Route>
</Route>
}
const Home:React.FC = () => {

 return (
 <>
   ... UI, JSX
   <Outlet />
 </>
 )
}

I add a <Outlet />. But if I entered '/ko/service/slack', render <Home /> now


<Route path={`/`} element={<Home />}>
    <Route path="service">
       <Route path="slack" element={<Slack />} />
       <Route path="dooray" element={<Dooray />} />
    </Route>
</Route>

nested-routes doesn't work.. :(


Solution

  • I had the exact same useCase (localize react router v6) and came up with the following LangRouter repository link:

    const LangRouter = () => {
      const { i18n } = useTranslation(),
        { pathname, search, hash } = useLocation(),
        navigate = useNavigate(),
        availableLocales = ['en', 'ar'],
        defaultLocale = (
          getDefaultLanguage() === 'en' || getDefaultLanguage() === 'ar' ? getDefaultLanguage() : 'en'
        ) as string,
        pathnameLocale = pathname.substring(1, 3).toLowerCase(),
        [locale, setLocale] = useState(defaultLocale),
        loaderTimerRef = useRef<any>(),
        [isLoading, setIsLoading] = useState(true);
    
      useEffect(() => {
        loaderTimerRef.current = setTimeout(() => {
          setIsLoading(false);
          clearTimeout(loaderTimerRef.current);
        }, 300);
      }, []);
    
      useEffect(() => {
        if (availableLocales.includes(pathnameLocale)) {
          updateLocale(pathnameLocale);
        } else if (pathname === '/') {
          updateLocale(defaultLocale);
        }
        // eslint-disable-next-line
      }, [pathname]);
    
      useEffect(() => {
        let lang = defaultLocale;
    
        if (availableLocales.includes(pathnameLocale)) {
          lang = pathnameLocale;
          setLanguageHandler(lang);
        } else if (pathname === '/') {
          setLanguageHandler(lang);
        }
        // eslint-disable-next-line
      }, [locale]);
    
      const setLanguageHandler = (lang: string) => {
        if (lang === 'en') {
          i18n.changeLanguage('en-US');
        } else {
          i18n.changeLanguage('ar-SA');
        }
      };
    
      const updateLocale = (newLocale: string) => {
        const newPath = `/${newLocale}` + pathname.substring(3);
    
        if (locale !== newLocale) {
          if (newPath === `/${newLocale}/` || newPath === `/${newLocale}` || pathname === '/') {
            navigate(getHomePageUrl(newLocale));
          } else {
            navigate(`${newPath}${hash}${search}`);
          }
          setLocale(newLocale);
        } else if (newPath === `/${newLocale}/` || newPath === `/${newLocale}` || pathname === '/') {
          if (isAuthenticated()) {
            navigate(getHomePageUrl(newLocale));
          } else {
            navigate(getLoginPageUrl(newLocale));
          }
        }
      };
    
      if (isLoading) {
        return (
          <div className="loader-wrapper">
            <LoadingIcon />
          </div>
        );
      }
    
      return (
        <LocaleContext.Provider value={{ locale, setLocale: updateLocale }}>
          <Routes>
            <Route path={`/${locale}`} element={<App />}>
              {publicRoutes.map((el, i) => (
                <Route
                  key={i}
                  path={el.path(locale)}
                  element={
                    <PublicRouteGuard
                      restricted={el.restricted}
                      redirect={el.redirect ? el.redirect(locale) : undefined}
                    >
                      {el.element}
                    </PublicRouteGuard>
                  }
                />
              ))}
    
              {privateRoutes.map((el, i) => (
                <Route
                  key={i}
                  path={el.path(locale)}
                  element={
                    el.permissions ? (
                      <RestrictedRouteGuard requiredPermissions={el.permissions}>
                        {el.element}
                      </RestrictedRouteGuard>
                    ) : (
                      <PrivateRouteGuard>{el.element}</PrivateRouteGuard>
                    )
                  }
                >
                  {el.children &&
                    el.children.map((innerEl, innerI) => (
                      <Route key={innerI} path={innerEl.path(locale)} element={innerEl.element} />
                    ))}
                </Route>
              ))}
            </Route>
            <Route path="*" element={<NotFoundPage />} />
          </Routes>
        </LocaleContext.Provider>
      );
    };
    
    export default LangRouter;