Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way for internationalization with Gatsby and Strapi

In my company, we are building a static website using Gatsby framework and the Strapi headless CMS.

My question is how to deal with i18n?

First, I know that is a difficult question and there is not one answer, but different answers depending of the context. So, I will resume you my research, and I hope you will help me to close this topic. :)

First idea, the most easy one, let's search a plugin!

There is one : gatsby-source-strapi-localized

Unfortunately, it is not maintained, so, I will not use it. :'(

Ok, second things, lets see what Strapi suggests!

Strapi does not have an i18n feature for now, it is planned for the end of 2020 on the roadmap.

But there is a work around, using suffix at the end of the fields: medium article (With the same idea, you can also suffix your Types directly)

So, now we got suffix on fields or types, let's go to the third part, Gatsby !

And it's a nightmare. XD

Actually, there is different solutions to solve that, but I did not find mine. :'(

I found this article, about the new i18n gatsby theme. I download the starter to try to understand how it works. What I understand is that pages for blog are generated automatically in 2 different languages, thank to the createPage function. 2 mdx files are created to store the data and the LocalizedLink component are used for redirections.

It is interesting, but it does not fit my problem well. So, let's tell you what I thought:

Spoiler alert ! : I am not familiar with the React packages for i18n, I just discover them this morning, it's why maybe I don't see the answer ^^'

First thing is "How to create the good url? " To do that, I have to choices :

  1. Create 2 folders in my page section, one FR and one EN, it will be added in my URL (mySite.org/FR)
  2. use gatsby-plugin-i18n, which allow you to create a index.fr.js and index.en.js to generate mySite.org/fr or mySite.org/en

After that, in each files, I can customize my query to ask the data in the good language:

allStrapiHomePage {
  edges {
    node {
      mainBanner {
        title_lang
      }
    }
  }
}

Or :

allStrapiHomePage_lang {
  edges {
    node {
      mainBanner {
        title
      }
    }
  }
}

For redirections, I can check the context to know in which page I am.

The things that I don't like, it's that I will have 2 files per pages, only for the query, the rest of the page is the same :/

So, the question is : How can I generate 2 pages per page with the good URL and the good query ? (you've got 2 hours è__é.... XD)

The createPage function allow you to pass variables in context, which could help me for the query. I can modify the path too, that can help me for the URL. But the folder pages are already processed by Gatsby... I can't modify the process.

Does anybody have an idea to clarify this topic? :)

like image 383
juliensl Avatar asked Aug 07 '20 12:08

juliensl


1 Answers

I see that this topic is a little bit popular, and I never write the answer, let's fix that !

I don't know how it works with the new versions of strapi, but there is our solution for strapi 3.0.1 :

Each pages have two single types in strapi :

  • Homepage
  • Homepage_En
  • About
  • About_En
  • ...

They have, of course, the same schema.

In my gatsby pages folder, we created two sub-folders :

  • fr
  • en

In each folder, you have all pages, but, the trick is : they are here only to get the correct data from strapi, let's see an example :

fr/about.js :

import React from "react"
import { graphql } from "gatsby"
import _get from "lodash/get"
import AboutPage from "../../components/pageComponents/About.js"

export default function About({ data }) {
  const BannerAbout = _get(
    data,
    "allStrapiAbout.edges[0].node.Banner.BackgroundImage.childImageSharp.fluid"
  )
  const TitleBannerAbout = _get(
    data,
    "allStrapiAbout.edges[0].node.Banner.Title"
  )
  const DescriptionBannerAbout = _get(
    data,
    "allStrapiAbout.edges[0].node.Banner.Description"
  )

  return (
    <AboutPage
      BannerAbout={BannerAbout}
      TitleBannerAbout={TitleBannerAbout}
      DescriptionBannerAbout={DescriptionBannerAbout}
    />
  )
}

export const query = () => graphql`
  query {
    allStrapiAbout {
      edges {
        node {
          Banner {
            Title
            Description
            BackgroundImage {
              childImageSharp {
                fluid(maxWidth: 1920) {
                  ...GatsbyImageSharpFluid_withWebp_tracedSVG
                }
              }
            }
          }
        }
      }
    }
  }
`

And the same idea for the english part :

en/about.js :

import React from "react"
import { graphql } from "gatsby"
import _get from "lodash/get"
import AboutPage from "../../components/pageComponents/About.js"

export default function About({ data }) {
  const BannerAbout = _get(
    data,
    "allStrapiAboutEn.edges[0].node.Banner.BackgroundImage.childImageSharp.fluid"
  )
  const TitleBannerAbout = _get(
    data,
    "allStrapiAboutEn.edges[0].node.Banner.Title"
  )
  const DescriptionBannerAbout = _get(
    data,
    "allStrapiAboutEn.edges[0].node.Banner.Description"
  )

  return (
    <AboutPage
      BannerAbout={BannerAbout}
      TitleBannerAbout={TitleBannerAbout}
      DescriptionBannerAbout={DescriptionBannerAbout}

    />
  )
}

export const query = () => graphql`
  query {
    allStrapiAboutEn {
      edges {
        node {
          Banner {
            Title
            Description
            BackgroundImage {
              childImageSharp {
                fluid(maxWidth: 1920) {
                  ...GatsbyImageSharpFluid_withWebp_tracedSVG
                }
              }
            }
          }
        }
      }
    }
  }
`

As you can see, they are calling the same React component , wich is a component for the full About page (with lots of sub-components of course), in the components folder.

So, after that, you just have to write your code once, with the correct props.

It's not perfect, but it works for me, and we don't have a duplication of the logical code :)

One more tips : be careful with your arrays of images, there are frequently the same between 2 languages, it could be interesting to use collection types for this rather than upload them twice.

If other people have ideas, don't hesitate to write your tips ;)

Have a good day everybody, don't worry, code happy !

like image 113
juliensl Avatar answered Sep 30 '22 01:09

juliensl