2

I am trying to add multi-language to this gatsbyjs template using the gatsby-plugin-intl.

Field level translation: Each field marked by translatable will have a translation and you have a single content item for all translations.

Multi-tree translation: Each translation will have it's own content item and the translations are saved in different folders.

The pages in the pages folder use Field level translation and work completely as should. The pages in the content folder uses Multi-tree translation using markdown files, but do not work entirely as desired/ should. Their routing is off.

Basically I would like to have these pages follow this routing:

  • /en/mypage/ should give english version
  • /ko/mypage/ should give korean version

However I now get for the markdown source pages following:

  • /en/mypage/en/ and /ko/mypage/en/ give english version
  • /en/mypage/ko/ and /ko/mypage/ko/ give korean version

I tried renaming of the slug in one of the hooks (onCreatePage, onCreateNode, createPages), but no success so far. When trying it seems one of the versions (en/ko) gets overwritten so then you end up with just one language for both routes. How to solve this?

E.g. amsterdamfurniturelab.nl/en/bear-desk/en turns into amsterdamfurniturelab.nl/nl/bear-desk/en but does not show nl-translation.

musicformellons
  • 12,283
  • 4
  • 51
  • 86
  • Do you have any source to see your `gatsby-config.js`? The repository you've provided doesn't have the gatsby-intl plugin installed. I've recently added internationalization in one of my projects and maybe I can find something missing there. – Ferran Buireu Mar 30 '20 at 19:05
  • @FerranBuireu I added the repo and also the live site which shows the issue. – musicformellons Mar 31 '20 at 21:01
  • It seems that the site you provided is working, isn't it? https://amsterdam-furniture-lab.netlify.com/nl/concept is in Dutch, and https://amsterdam-furniture-lab.netlify.com/en/concept is in English. Am I missing something? – Robin Métral Apr 01 '20 at 10:19
  • @RobinMétral That's right! The links at the top work as should (uses field level translation). To see the problem (multi tree translation), click one of the pictures at the homepage, e.g. at https://amsterdamfurniturelab.nl/en/bear-desk/en/ which turns into https://amsterdamfurniturelab.nl/nl/bear-desk/en/ but does not switch to nl translation... – musicformellons Apr 01 '20 at 10:30
  • Ah yes, I see. Thanks for clarifying! I'll take a look and see if I can help :) – Robin Métral Apr 01 '20 at 12:12
  • @musicformellons it looks like `gatsby-plugin-intl` only supports field-level translations: `you don't have to create separate pages such as pages/en/index.js or pages/ko/index.js` [...] `the plugin will create static pages for every language.` Basically when you get a URL like `/en/your-page/en`, the first `en` is generated by the plugin, and the second by Gatsby (because your md file is named `en.md`. You would basically need to ignore the plugin from being triggered for your markdown pages – Robin Métral Apr 01 '20 at 17:20

1 Answers1

2

gatsby-plugin-intl only supports field-level translations, passing JSON translation keys via Context.

From the plugin's README:

you don't have to create separate pages such as pages/en/index.js or pages/ko/index.js [...] the plugin will create static pages for every language

So if you have 2 languages, say NL and EN, the plugin will generate 3 pages for each slug. So if you have a /bear-desk/ page, you will get:

"/en/bear-desk/" <-- EN locale
"/nl/bear-desk/" <-- NL locale
"/bear-desk/" <-- default: either redirects or renders the default locale based on plugin settings

In the repo you provided, you're using both gatsby-plugin-intl and "manual" translations using two separate pages.

Since /bear-desk/en/ and /bear-desk/nl/ are seen as two different pages by the plugin, you're actually generating 6 pages for each slug:

For your /bear-desk/en/ page (no JSON translations found, all will be in EN)
"/en/bear-desk/en/"
"/nl/bear-desk/en/"
"/bear-desk/en/"

For your /bear-desk/nl/ page (no JSON translations found, all will be in NL)
"/en/bear-desk/nl/"
"/nl/bear-desk/nl/"
"/bear-desk/nl/"

If you wanted to change this behavior, you would create pages manually using Gatsby's createPage API in gatsby-node.js and make sure that you're creating the right pages at the right URLs.

There are multiple ways to do this. If you need inspiration, one example that seems close to your case is described in Building a multi-lingual static site with Gatsby on Hiddentao.

If other issues come up during your implementation, feel free to open a new question and I'll be happy to help!

 Update

I've been able to create the right URLs in the onCreatePage API:

/*
here's what we want to do:
 - for /nl/<slug>/nl/ create both /<slug>/ and /nl/<slug>/
 - for /en/<slug>/en/ create /en/<slug>/
 - for the rest of pages including <slug>, delete
*/

// note: optimally you would grab slugs from the fs or via graphql
const slugs = ["bear-desk", "cnc-explained"]

exports.onCreatePage = async ({
  page,
  actions: { createPage, deletePage },
}) => {
  slugs.forEach(slug => {
    if (page.path === `/nl/${slug}/nl/`) {
      // create page in the default language (NL) at /slug
      const defaultPage = { ...page, path: `/${slug}/` }
      createPage(defaultPage)
      console.log(`Created default page in NL at ${defaultPage.path}`)

      // create a page for /nl/slug
      const nlPage = { ...page, path: `/nl/${slug}/` }
      createPage(nlPage)
      console.log(`Created NL page at ${nlPage.path}`)

      // delete the page with duplicate locale
      deletePage(page)
      console.log(`Deleted ${page.path}`)
    }

    else if (page.path === `/en/${slug}/en/`) {
      // create a page for /en/slug
      const enPage = { ...page, path: `/en/${slug}/` }
      createPage(enPage)
      console.log(`Created EN page at ${enPage.path}`)

      // delete the page with duplicate locale
      deletePage(page)
      console.log(`Deleted ${page.path}`)
    }

    else if (page.path.includes(slug)) {
      // delete all other pages with that slug
      deletePage(page)
      console.log(`Deleted ${page.path}`)
    }
  })
}

You'll get the routes you want:

"/en/<slug>/" <-- EN locale
"/nl/<slug>/" <-- NL locale
"/<slug>/" <-- default (NL locale in your case)

Although this creates the correct pages at the right routes, there is a major limitation: gatsby-plugin-intl is not aware of it. This means that you need to manually implement language switching and linking to the right locale.

This is obviously not the best solution, but since the plugin doesn't support this type of localization, I'm not sure there's a more integrated way to do this (maybe others will have better ideas).

One more thing I would suggest is to make a feature request on the repo. Good luck!

Community
  • 1
  • 1
Robin Métral
  • 3,099
  • 3
  • 17
  • 32
  • Thanks, your analysis is sound. However, I had already seen the Hiddentoa blog, I installed the repo and noted that although it pretends to deal with this, it does not... Exact same problem there (difficult to find, since it hardly uses any multi-tree-translation...). Could you maybe look into the slimmed down repo I added and see if you can make the ```createPage``` work? I tried, but did not manage. – musicformellons Apr 01 '20 at 20:56
  • I'll take a look, thanks for the minimal reproducible example :) – Robin Métral Apr 02 '20 at 07:00
  • @musicformellons you can fix the routes fairly easily using `onCreatePage` (cf. the update in my answer), but it creates other issues with localization (the language toggle won't work out of the box, nor will links). You can implement them manually, but I would actually recommend taking this to the plugin's maintainers and see what they think (or fork the plugin and make your own [local version of it](https://www.gatsbyjs.org/docs/creating-a-local-plugin/) tailored to your needs). – Robin Métral Apr 02 '20 at 12:59