How to setup getStaticPaths of multi-locale dynamic pages in Next.js
Asked Answered
B

3

15

Today, in my side-project, I got a problem relate to setup getStaticPaths of multi-locale dynamic pages in Next.js. I researched and find out that there are so many people stuck in this problems.

I have created a dynamic page [slug].js to handle all dynamic datas I got from a database. And my website I was working on is also multi-language website which is using next-translate for handle i18n.

In [slug].js, we have to setup a function getStaticPaths to handle all static url. It will be more easier if the website got 1 language, but with more than 2 languages we have to loop it.

Brachiopod answered 1/6, 2021 at 19:8 Comment(0)
B
22

Here is the code I have been used to handle it, I was working with Notion API and use it as a database for a multi-language website:

export async function getStaticPaths({ locales }) {
  const notion = new Client({ auth: process.env.NOTION_API_OFFICIAL_KEYS });

  const databaseId = process.env.NOTION_PAGE_ID_EMBVN_DATABASE_PAGE;
  const response = await notion.databases.query({
    database_id: databaseId,
  });

  let paths = [];

  response.results.forEach((block) => {
    for (const locale of locales) {
      paths.push({
        params: {
          slug: block.properties.embcode.title[0].plain_text.toString(),
        },
        locale,
      });
    }
  });

  return {
    paths,
    fallback: false,
  };
}

With forEach, we will add every pathName of each locale to paths array to return it in the final result of getStaticPaths.

Brachiopod answered 1/6, 2021 at 19:8 Comment(4)
When returning in paths objects containing both params and locale I have found there is no difference if you include locale than if you do not. Would you care explaining why you added locale to paths?Junko
@Junko When using website with 2 or more languages with Next.js and using dynamic url, if we don't create a loop for locale so that getStaticPaths can generate both url types for locale, 404 error will occur when the user goes directly to the url of the 2nd locale. We can still load pages from the default language, switch them back and forth without reloading via NextLink. However, if the user goes directly to or reloads the page in the 2nd locale, a 404 error will occur because Next.js has not created a static path.Niemeyer
Amazing, thanks for the insight! One last question if I may: where would I find this in the documentation, or is this knowledge that can/should be inferred from somewhere else? I couldn't find it around... and mention to locale or any other optional keys is not there.Junko
@Junko I'm just a junior developer in Next.js now. I faced this problem a long time ago and find everywhere in the internet even the document of Next.js but could not find any solution. Luckily, one of my friend is a full stack developer in Javascript and he explained it to me and help me to fix this. I think I should share it again for someone else in the future.Niemeyer
M
5

If the answer help someone, I have reshaped a little the answer of Huu Phong First i get all my post from sanity API then i map on it to get each element , then i map on each element to get only the slug and add on each slug a locale key

export async function getStaticPaths({ locales }) {
  const query = encodeURIComponent(`{
      "posts": *[_type == "post"]  {
        ...,
        categories[]->
      }}
    `)

  const url = `https://${process.env.NEXT_PUBLIC_PROJECT_API}.api.sanity.io/v1/data/query/production?query=${query}`
  const result = await fetch(url).then((res) => res.json())

  const paths = []
  result.result.posts.map((element) => {
    return locales.map((locale) => {
      return paths.push({
        params: { slug: `${element.slug.current}` },
        locale,
      })
    })
  })

  console.log("***---paths---***", paths)

  return {
    paths,
    fallback: true,
  }
}
Mussolini answered 3/5, 2022 at 15:20 Comment(0)
G
0

I did initialize getStaticPaths with multiple locales by getting all the posts slug property with their specified locale in a single fetch request.

The response was like this:

{ 
        "1": {
            "en": "Discover-the-Art-of-Culinary",
            "fa": "کشف-هنر-آشپزی"
        },
        "2": {
            "en": "Embrace-Wellness",
            "fa": "آغوش-سلامت"
        },
        "3": {
            "en": "Innovation-in-Technology",
            "fa": "نوآوری-در-فناوری"
        },
        "4": {
            "en": "Journey-Through-History",
            "fa": "سفری-از-میان-تاریخ"
        },
        "5": {
            "en": "The-Art-of-Photography",
            "fa": "هنر-عکاسی"
        }
}

Then I pushed each of them to the paths variable inside the locales loop like this:

export const getStaticPaths: GetStaticPaths = async ({ locales }) => {
  const paths: {
    params: {
      slug: string;
    };
    locale: string;
  }[] = [];

  let postSlugs;
  try {
    const { data } = await axios.get("/posts");
    postSlugs = data.data;
  } catch (e) {
    postSlugs = null;
  }

  locales?.forEach((locale: string) => {
    Object.keys(postSlugs).forEach((eachSlug) => {
      paths.push({
        params: {
          slug: postSlugs[eachSlug][locale],
        },
        locale,
      });
    });
  });

  return {
    paths,
    fallback: false,
  };
};

Finally I got the slug from getStaticProps function and fetched the exact post like this:

export const getStaticProps: GetStaticProps = async ({ locale, params }) => {
  const slug = params?.slug;

  let blogPost;
  try {
    const { data } = await axios.get(`/${locale}/posts/${slug}`);
    blogPost = data.data;
  } catch (e) {
    blogPost = null;
  }

  return {
    props: { blogPost, slug },
    revalidate: 1,
  };
};
Gyral answered 28/7 at 6:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.