Next.js 12 introduced middleware for handling logic at the CDN level (sometimes called an edge function) before a page loads. This is incredibly powerful and unlocks the potential for static pages to have limited server-side logic. There are lots of examples of this but one compelling use case I recently used it for is advanced internationalization and content localization.
Be forewarned that code samples in this article are rather large, it may be easier to just browse the GitHub repo linked above.
User story
Before we dive into the code let’s take a step back and talk about the user experience we want to achieve. Imagine we have an international e-commerce store based in both North America and Europe; this means we also need to worry about GDPR and cookie legislation as well. On the surface this may seem simple enough but it is worth breaking the logic down.
We are going to support the following locales, you should be able to easily add more or less based on the pattern and code here.
en-gb, English-Great Britain
en-ca, English-Canada
fr-fr, French-France
fr-be, French-Belgium
fr-ca, French-Canada
fr, French language fallback
en, English as the final default locale fallback
Let’s say we have a new user visiting the website from France for the first time:
They should be redirected to www.mysite.com/fr-fr/
They should be shown a cookie banner
Now let’s say this same user is curious about prices in the UK and visits www.mysite.com/en-us/store
They should still be able to view this address without being redirected back to the France website
This shouldn’t affect the locale they are shown on a return visit
Next this user realizes that they are on the website for France, but they actually live in Belgium and want to see content relevant to their own country.
They should be able to change their locale to fr-be
If they have accepted the cookie notice we should also set a cookie so that this locale preference is saved for any return visits. Now if they come back to the site they will always be shown the French-Belgium version, instead of the French-France version.
This same user, being security concious now starts using a VPN and is redirecting their locale through the United States. They are also browsing in private mode (any previous cookies are ignored). However, their operating system language is set to French.
They should be shown the fr fallback
Now imagine an entirely different user living abroad in Japan visits the site. We don’t support their country or language and there are no previous cookies set.
They should be shown the en fallback
Finally if a user has set a cookie for their language preference we should always respect this choice.
Whew! See it starts to get a bit tricky as you think through the various edge cases that can come up beyond just detecting a country and language.
Next.js Config
Next.js has an i18n config option which can be set in the next.config.js file. The two things to note here is that we set a locale of default which we also specify as the defaultLocale and that we set localeDetection: false. We turn off Next.js locale detection because we are going to handle that ourselves in the middleware.
Middleware code
Now we get into the fun bits! Here is what that user experience we described above looks like in code. Note that we return early for public files, like images and we return early for api routes.
Your middleware.ts file should be located inside of the root project
directory or inside the src folder if you are using it. During the beta
release the middleware file was located inside of the pages folder and also
had an _ in front of it. Double check to make sure you have the middleware
file in the right location and with the right name!
Language selector and cookies
Next up we need a language selector so the user can change their language. In the project demo I am using Radix-UI and react-cookie-consent to help abstract some accessibility concerns and actually setting the cookie consent, but you don’t need to use these packages.
Next steps
Hopefully this gets you started in your journey with Next.js and internationalization. There are lots of complexities to consider and Next.js has an article on the topic that covers a few other topic areas.