microapps / gatsby-plugin-react-i18next

Easily translate your Gatsby website into multiple languages
MIT License
121 stars 72 forks source link

Doesn't work together with client routes and reach router #69

Open Lillvik opened 3 years ago

Lillvik commented 3 years ago

I'm using client routes in Gatsby together with gatsby-plugin-react-i18next. When I'm trying to access one of the client routes while not using the default language, e.g. the url is prefixed with /sv, then I get that the route doesn't exists. If I add the prefix /sv to the router basepath, the Default component/path is working but not the Profile component/path.

While using the default language without the /sv prefix, everything is working as expected.

src/pages/account.tsx

<Router basepath={'/account'}>
  <AccountRoute path="/profile" component={Profile} />
  <Default path="/" />
</Router>

gatsby-node.js

exports.onCreatePage = async ({ page, actions }) => {
  const { createPage } = actions
  if (page.path.match(/^\/account/)) {
    page.matchPath = "/account/*"

    createPage(page)
  }
}

I've also tried to add the prefix /sv to the matchPath in gatsby-node.js but then I'm redirected to double prefixes /sv/sv route that doesn't exists. If I tell gatsby-plugin-react-i18next to not generate language pages for the account pages, I get the same result.

gatsby-config.js

{
  resolve: `gatsby-plugin-react-i18next`,
  options: {
    ...
  },
  pages: [
    {
      matchPath: '/:lang?/account/(.*)',
      getLanguageFromPath: true
    },
  ]
}
ozburo commented 3 years ago

I've just been bitten by this too and went down the matchPath Page options rabbit hole...

It seems that the problem is that this plugin hasn't been updated to handle the new Gatsby File System Routes API, so no amount of hacking the Page options is gonna help us.

However, I think I've got a working solution. The problem seems to be that the plugin doesn't set/update its additional languages pages (onCreatePage.ts) for these "wildcard" routes that have a defined matchPath -- you can see how the plugin does this for the builtin "404" wildcard path.

You can use/reference my fork with the change made at this commit.

If you want to try it for yourself, you can also use my fork in your package.json with "gatsby-plugin-react-i18next": "github:ozburo/gatsby-plugin-react-i18next#master",.

I'll be happy to submit a PR if this seems to be a good working fix for all concerned.

Lillvik commented 3 years ago

Unfortunately I couldn't get it to work. How did you construct your onCreatePage and Reach Router in your Application and how did you configure the plugin in gatsby-config.js?

ozburo commented 3 years ago

My gatsby-plugin-react-i18next config is the same as in the docs, and I'm just using a [...].js catch-all route in my app, i'm not implementing anything w/ Reach Router.

Essentially, in my case, I need the plugin to create all the langs prefixes, i.e. /fr/* for my /* catch-all, which is what that page's matchPath is.

I figured this might be a fix that only works in my case, but I'll thought I'd share since there doesn't seem to be much action around here.

I had to fork and hack around with the plugin locally in my Gatsby project to find some kinda solution.

ozburo commented 3 years ago

This is getting interesting...

I just had a little play around, i.e. using Reach Router in your Client-Only route (like they show in the Gatsby docs), instead of just using a conditional render in my [...].js file based on the incoming props.

It looks like there's a limitation w/ Reach Router, i.e. "No complex routes" which we need so we can catch the lang partial provided by this plugin, i.e. /fr/app/profile

What I did then is simply doubled up the Router component to catch both routes with and without the language prefix.

This is my test /app/[...].js file:

import React from "react"
import { graphql } from "gatsby"
import { Router } from "@reach/router"
import Layout from "../../components/layout"

const App = () => {
  return (
    <Layout>
      <Router basepath="/:lang/app">
        <Profile path="/profile" />
        <Details path="/details" />
        <Login path="/login" />
        <Default path="/" />
      </Router>
      <Router basepath="/app">
        <Profile path="/profile" />
        <Details path="/details" />
        <Login path="/login" />
        <Default path="/" />
      </Router>
    </Layout>
  )
}

export const query = graphql`
  query($language: String!) {
    locales: allLocale(filter: { language: { eq: $language } }) {
      edges {
        node {
          ns
          data
          language
        }
      }
    }
  }
`

export default App

const Profile = () => {
  return <div>PROFILE</div>
}

const Details = () => {
  return <div>DETAILS</div>
}

const Login = () => {
  return <div>LOGIN</div>
}

const Default = () => {
  return <div>DEFAULT</div>
}

This seems to work for me, using my fork/fix.

Hope that helps some.

Lillvik commented 3 years ago

Thanks, it's really good to here that you've managed to get it to work. Unfortunately, I've tried a similar approach before and tried your example now in my solution but I still get "NOT FOUND", hence there must be something that I'm doing different. Do you have a repository with your solution that you can share?

bebbi commented 3 years ago

Does this help? (no custom plugin) https://stackoverflow.com/questions/67242212/gatsby-cant-find-client-routes-when-using-gatsby-plugin-react-i18next/69905274#69905274

nithyananthan-s02 commented 2 years ago

Am facing the same issue. I tried the approaches specified above however, unfortunately, it is not working. Am getting route NOT FOUND error. Any updates on this ?

c0necto commented 1 year ago

In case anyone else is still struggling with this: Try adding your custom route to the pages config option like so (de is the default language in my case):


pages: [
    {
        matchPath: '/:lang?/client-route/:someParameter',
        getLanguageFromPath: true,
        languages: ['de', 'en'],
    }
]
ChiuMungZitAlexander commented 1 year ago
pages: [
    {
        matchPath: '/:lang?/client-route/:someParameter',
        getLanguageFromPath: true,
        languages: ['de', 'en'],
    }
]

unfortunately, this won't work