Gustavo Miguel
Gustavo Miguel

Reputation: 33

Routing localization with NextJS

I'm migrating a website developed with Gatsby to NextJS, but something I could achieve using Gatsby's createPage API is localizing the app's routes, but until now I couldn't achieve this with NextJS APIs.

I'm using Next v10.0.1 for this.


As I see in other threads regarding this type of resource, this is actually kinda confusing of what it actually means, so here goes an example of what is the desired result:

User access route /my-data/1234 (where the NextJS equivalent routing would be: /my-data/[dataId].js)

User must be able to access the same page but translated in the URL /pt/meus-dados/1234 (using, for example, portuguese translation).


Some guesses on how to achieve that keeping Next's static optimizations (Static rendering and Incrementing Static Rendering)?

Upvotes: 1

Views: 1045

Answers (2)

Gustavo Miguel
Gustavo Miguel

Reputation: 33

I actually found an answer which is pretty useful for my use case, I'm using NextJS rewrites for that, maybe not the best solution, but fits my needs well.

I use a single file for each route, so the directory structure should be something like this:

pages
-- my-data
   -- [id].js

then I'll have some kind of internationalization, in my case I'm using react-i18next, won't think about the aspects of implementations for the library here, it could also be achieved with any other.

Next step is to set a translation somewhere for the pages routes, for example, add an entry for the i18next messages named routes containing a key-value pair for the routes translations. e.g (intl/pt.json):

{
  ...
  "routes": {
    "/my-data/:id": "/meus-dados/:id"
  }
  ...
}

and then use NextJS rewrites, so you will have to import the intl messages (e.g: from intl/pt.json) and map them as rewrites in next.config.js:

# next.config.js
...
async rewrites() {
  // languages here is a key-value pair object containing the structure { [language]: { routes: {...} } }
  // in my case, imported from `intl/pt.json`
  const intlRewrites = Object.entries(languages).reduce((rewrites, [ language, { routes } ]) => {
    return [
      ...rewrites,
      ...Object.entries(routes).map(([ path, translatedPath ]) => {
        const source = translatedPath
        const destination = path // here you can write a logic to add a language prefix if needed

        return { source, destination }
      })
    ]
  }, [])

  return intlRewrites
}

From my experience, optimizations like ISG work fine. Should work with SSG too, but I haven't tested it.

Upvotes: 2

Steve Vaughan
Steve Vaughan

Reputation: 2189

I've been tackling this exact problem, and whilst I don't yet have a solution that integrates directly into NextJS, this can be achieved fairly simply before your project is compiled.

If you were to organise your pages directory as follows, it should work as you expect:

// Before
pages
-- my-data
   -- [id].js

// After
pages
-- pt
   -- meus-dados
      -- [id].js
-- en
   -- my-data
      -- [id].js 

However the developer experience here isn't nice. So what I have done to solve this currently is written a simple build step that runs before next build. It takes a regular pages directory and converts it to the above format, allowing next build to run against a version that works as intended for the translated paths. This allows SSG and ISG to work as expected.

Ideally I'd like to hook into the Next ecosystem so this works seamlessly for dev and build, but I haven't yet gotten that far

Upvotes: 0

Related Questions