CiptoHartanto

Workaround of Getting Locale (i18n) Feature of next.js on a Static Web Server

Published on Apr 19, 2024
  • Next.js
  • i18n

Background

LandPress Deploy (web server) where I host most of my recent projects is simply a static web server. In these projects, planning teams required localization as one of the many features. The usual required languages are English, Korean, Japanese, and Traditional Chinese.

As a web developer, updating content can be very tedious. Fortunately, LandPress also comes with LandPress Content v2. LandPress Content V2 is a headless CMS service. Since updating content can be very time consuming, I utilize this service in hopes that I won't be updating XLTs all the time. An XLT is a translation set of a page which will be read through JavaScript and compiled to the HTML.

Next.js supports internationalization (i18n) which makes routing to the appropriate url really easy. However, i18n feature is not available on a static web server like LandPress Deploy. As the reference states, API routes, Redirects, Internationalization routing, etc., are only available within a Node.js server.

Inspecting the getStaticPaths()

Let's say we would like to generate a very simple website with only one index.tsx and its corresponding file compiled under [locale/] as following.

1web-project/
2├─ src/
3   ├─ pages/
4      ├─ index.tsx //main index file
5         ├─ [locale]/
6            ├─ index.tsx // index file under [locale]
7

getStaticProps() is defined as a function which Next.js runs to statically pre-render all the paths specified in it. The typical pattern of it is as follows.

1import type {
2  GetStaticPaths,
3} from 'next'
4 
5export const getStaticPaths = (async () => {
6  return {
7    paths: [
8      {
9        params: {
10          name: 'next.js', // <-- point of interest is here
11        },
12      }, 
13    ],
14    fallback: true, // false or "blocking"
15  }
16}) satisfies GetStaticPaths
17
18

Anything inside params will be passed into the dynamic segments. In many examples, [slug] and [id] are the popular names for the dynamic segment. We have to remember that Next.js will look up folders with brackets and replace them with all values of each object inside params. With that in mind, how about we update that name (check the <-- point of interest is here) object to be locale?

Workaround

Well, I found out that the following setup would help getting us closer to the desired results!

Create a constant, const LOCALES, which is an array of {locale: string}

Previously, I mentioned LandPress Content V2 as the content management system. It does provide API endpoints for different locales. The locale values are in the example below. If your project uses different locale values, please adjust accordingly.

1 // locales/index.ts
2type LocaleProps = {
3  locale: string
4}
5const LOCALES: LocaleProps[] = [
6   // {locale: 'en_US'}, // we don't need to add this default locale
7   {locale: 'ko_KR'},
8   {locale: 'ja_JP'},
9   {locale: 'zh_TW'},
10]
11         
12export default LOCALES
13

Then, map through LOCALES and return it within the param object from running getStaticPaths().

1import type {
2   GetStaticPaths,
3} from 'next'
4       
5import LOCALES from 
6
7export const getStaticPaths = (async () => {
8   const paths = LOCALES.map((item) => {
9      return {
10          params: {
11             locale: item.locale
12          }
13      }
14   })
15   return {
16       paths,
17       fallback: false
18   }
19}) satisfies GetStaticPaths
20

Results

Here is the result of running next build. Please read this documentation on static exports as well.

1out/
2├─ index.html
3  ├─ ko_KR/
4    ├─ index.html
5  ├─ ja_JP/
6    ├─ index.html
7  ├─ zh_TW/
8    ├─ index.html
9

With these compiled files, when the user accesses project.me/ko_KR/, they will see the content in Korean. The root index.html file is the default language, which is in English.

Considerations

  • This solution may work if you have some kind of API endpoints that support localization which will be the reference values of locale. These values will then be used to compile subfolders of the project.
  • There will be no automatic redirection to the proper locale url as offered by Next.js. However, we could still check browser language by referencing navigator.language and making a redirection with useEffect() (if you work with React.js . Please read Navigator: languages property by MDN.