Search code examples
reactjsgatsbyreact-i18nextgatsby-plugin

Is there a way to reduce defining and exporting language queries when building pages with i18next translations?


I currently have n number of Pages.

In each of them I'm defining the following query...

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

...in each Page to fetch the translations.

It's the same query (for now), so I'd really like to be able to import just one version rather than define this in every single page.

I've tried the following:

// SomePage.tsx

export { languageQuery } from '../path/to/languageQuery';
// where languageQuery.ts is the query mentioned above

or

// languageQuery.ts

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

// SomeComponent.tsx

import { languageQueryAsAFunction } from '../path/to/languageQuery';
export const languageQuery = languageQueryAsAFunction()

But when compiling, Gatsby appears not to be able to detect the translation query.

This really doesn't feel scalable in the long term. Can anyone help with how to reduce/ remove this duplication? Am I missing something painfully obvious?

n.b. packages versions:

"gatsby-plugin-react-i18next": "^1.1.1",
"i18next-browser-languagedetector": "^6.1.2",
"i18next-http-backend": "^1.3.0",
"react-i18next": "^11.11.4",

Solution

  • Are you looking for GraphQL query fragments?

    export const query = graphql`
      fragment SiteInformation on Site {
        title
        description
      }
    `
    

    Then:

    export const pageQuery = graphql`
      query SiteQuery {
        site {
       ...SiteInformation
        }
      }
    `
    

    Fragments are exported automatically and don't need to be imported in the file where you are trying to use them. They are automatically inferred by the GraphQL schema and available in all queries in your project.

    You'll need to tweak the snippet above to adapt the dynamic $language parameter, which without having a GraphiQL is difficult to code here.

    The content of the query is irrelevant, really (It is the default, under this heading of the plugin docs). My question is concerning the neccessity of defining this variable of a graphql string ON EVERY page. Seems very cumbersome

    I do not agree with that. The content is relevant as long as it's filtered by a parameter ($language) so the workarounds to bypass the limitation you found relies on the content.

    If the content is not relevant, you can create a custom hook extending the useStaticQuery built-in hook. Keeping in mind that static queries don't accept parameters (hence the name). So, you can create something like:

    import { useStaticQuery, graphql } from "gatsby"
    export const useLocales = () => {
      const { locales } = useStaticQuery(
        graphql`
        query {
            locales: allLocale{
                edges {
                    node {
                        ns
                        data
                        language
                    }
                }
            }
        }
    `
      )
      return locales.edges
    }
    

    Then in your component (can be a page or a single component):

    export default function Home() {
      const yourLanguages = useLocales()
      console.log(yourLanguages);
    
      return <h1>welcome</h1>
    }