Forem

Cover image for Building Next.js app in 7 different languages ๐Ÿ‡ซ๐Ÿ‡ท ๐Ÿ‡ฉ๐Ÿ‡ช๐Ÿ‡ง๐Ÿ‡ท with i18n. Open Source.
Iuliia Shnai
Iuliia Shnai

Posted on

30 5 2 2 5

Building Next.js app in 7 different languages ๐Ÿ‡ซ๐Ÿ‡ท ๐Ÿ‡ฉ๐Ÿ‡ช๐Ÿ‡ง๐Ÿ‡ท with i18n. Open Source.

Languages

Localisation is one of the ways how to make your project open and accessible for more users.

So I decided to add different languages to my app.

Project I am working on

Post Generator - Linkedin Post Generator I wrote full story how I started it (Open Source)

You can fork it here https://github.com/shnai0/linkedin-post-generator

Translations

Resources I used to build it?

Using ChatGPT
Using next-i18next
https://github.com/i18next/next-i18next

Image description

What you will find in this article?

  1. How install and select localisation library?

  2. How I create each common.js file

  3. Adding dropdown for languages

Step 1. Select library and install

There were two which ChatGpt recommend me. I selected i18next. No big clue why, but it works well with my pages directory.

I installed it here:

npm install i18next
npm install react-i18next

Enter fullscreen mode Exit fullscreen mode

Step 2.Create next-18next.config.js and next.config.js

next-18next.config.js

module.exports = {
  debug: process.env.NODE_ENV === "development",
  i18n: {
    locales: ["en", "de", "pt", "es", "ch", "fr", "it"],
    defaultLocale: "en",
  },
  localePath:
    typeof window === "undefined"
      ? require("path").resolve("./public/locales")
      : "/locales",

  reloadOnPrerender: process.env.NODE_ENV === "development",
};

Enter fullscreen mode Exit fullscreen mode

next.config.js

/** @type {import('next').NextConfig} */

const { i18n } = require("./next-i18next.config.js");
const nextConfig = {
  i18n,
  reactStrictMode: true,
};

module.exports = nextConfig;

Enter fullscreen mode Exit fullscreen mode

Step 3. Create locales structure

Image description

locales

Step 4. Add variables in each common.js file

After that I had all variables I asked chat

{
  "title": "Linkedin Post Generator ๐Ÿš€",
  "posts_generated": "50.000 amazing posts generated ๐Ÿ’ซ",
  "subtitle": "Generate high quality posts with AI like top LinkedIn creators. Time to go viral.",
  "inside_post": "Type or copy your post here",
  "submit_button": "Generate your post",
  "generated_post": "Your generated post",
  "post copied": "Post copied to clipboard",

  "prompts.story": "prompt",
  "prompts.crisp": "prompt",
  "prompts.list": "prompt",
  "prompts.unpopular_opinion": "prompt",

  "meta.viewport": "width=device-width, initial-scale=1",
  "meta.favicon": "๐Ÿ‘ฉโ€๐Ÿ’ผ",
  "meta.description": "Meta.",
  "meta.og.title": "LinkedIn Viral Post Generator with AI",
  "meta.og.type": "website",
  "meta.og.image": "https://postgenerator.app/cover.png",

  "vibes.story": "Story",
  "vibes.crisp": "Crisp",
  "vibes.list": "List",
  "vibes.unpopular_opinion": "Unpopular opinion",
  "vibes.case_study": "Case Study"
Enter fullscreen mode Exit fullscreen mode

Step 4. Replace hard coded code in index

In your JavaScript/TypeScript code, you would then import the relevant locale file based on the user's chosen language.

First imports use translations.

import { useTranslation, Trans } from "next-i18next";
Enter fullscreen mode Exit fullscreen mode

๐Ÿ’ก Prompts, if your application using OpenAI can be also variables.

You would replace all the hard-coded text in your application with the respective keys from the locale files.

<button className="bg-blue-700 font-medium rounded-md w-full text-white px-4 py-2 hover:bg-blue-600 disabled:bg-blue-800">
  {loading && <LoadingDots color="white" style="large" />}
  {!loading && `Generate new post `}
</button>
Enter fullscreen mode Exit fullscreen mode

Instead I use this- as I am adding variable

<button className="bg-blue-700 font-medium rounded-md w-full text-white px-4 py-2 hover:bg-blue-600 disabled:bg-blue-800">
  {loading && <LoadingDots color="white" style="large" />}
  {!loading && locale.submit_button }
</button>
Enter fullscreen mode Exit fullscreen mode

Step 5. Create menu in NavBar to connect different languages

const languages = [
    { name: "English", flag: "๐Ÿ‡ฌ๐Ÿ‡ง", code: "en" },
    { name: "Deutsch", flag: "๐Ÿ‡ฉ๐Ÿ‡ช", code: "de" },
    { name: "Portuguรชs", flag: "๐Ÿ‡ง๐Ÿ‡ท", code: "pt" },
    { name: "Franรงais", flag: "๐Ÿ‡ซ๐Ÿ‡ท", code: "fr" },
    { name: "Espaรฑol", flag: "๐Ÿ‡ช๐Ÿ‡ธ", code: "es" },
    { name: "ไธญๆ–‡", flag: "๐Ÿ‡จ๐Ÿ‡ณ", code: "ch" },
    { name: "Italiano", flag: "๐Ÿ‡ฎ๐Ÿ‡น", code: "it" },
    // add more languages as needed
  ];

  const currentLanguage =
    languages.find((language) => i18n.language === language.code) ||
    languages[0];

  console.log("currentlanguages", currentLanguage);

  const [isOpen, setIsOpen] = React.useState(false);
  const toggle = () => setIsOpen(!isOpen);

Enter fullscreen mode Exit fullscreen mode

NavBAr

What am I doing now?

I am building different micro-tools for LinkedIn and actively develop Post generator https://www.postgenerator.app

If you like this article and would like to support me on my coding journey, here one of the open source project I am on.

Papermark.io - open source alternative to Docsend. Check it โญ๏ธ

Stars

If you are building something in Open Source, share, I am curious to fork it ๐Ÿ‘€

Follow my journey, more micro-projects here https://linktr.ee/shnai

My Twitter https://twitter.com/shnai0

Image of Timescale

๐Ÿš€ pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applicationsโ€”without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post โ†’

Top comments (23)

Collapse
 
mateusabelli profile image
Mateus Abelli โ€ข

I like i18n although I don't implement it too often in projects I enjoyed reading your process to add such feature.

I have a question, with this setup, is it possible to have next.js figure out the user's preferred language and automatically render the matching language?

Collapse
 
shnai0 profile image
Iuliia Shnai โ€ข

Thanks Mateus!

It is actually a good questions. I actually have no idea. I did not build it or did not try. But understand what you mean.

I build just standard always users get on the English page.

Collapse
 
mateusabelli profile image
Mateus Abelli โ€ข

Oh that's cool, thanks for replying!

Collapse
 
juanfrank77 profile image
Juan F Gonzalez โ€ข

Great stuff here! Love to see you building cool stuff with Next.js.

Collapse
 
shnai0 profile image
Iuliia Shnai โ€ข

Thanks Juan. Are you building smth at the moment?

Collapse
 
juanfrank77 profile image
Juan F Gonzalez โ€ข

Not anything code related atm. ๐Ÿ˜…
But building content for folks in SaaS.

Thread Thread
 
shnai0 profile image
Iuliia Shnai โ€ข

That is great! Which type of content? For website or social?

Thread Thread
 
juanfrank77 profile image
Juan F Gonzalez โ€ข

Mostly for websites. Blog content that can then be used for social media and to get more organic traffic. ๐Ÿ˜€

Collapse
 
aydrian profile image
Aydrian โ€ข

This is great. Where did you source all your translations? I'm also starting to build a lot using i18next.
I also created a i18next Backend Plugin for those who want to store their translations in a database using Prisma ORM.

Collapse
 
shnai0 profile image
Iuliia Shnai โ€ข

Sourcing is all from ChatGPT:)

Collapse
 
mfts profile image
Marc Seitz โ€ข

๐Ÿ’ช Great job!

Collapse
 
aibryx profile image
Alim Dzhanibekov โ€ข

+

Collapse
 
aibryx profile image
Alim Dzhanibekov โ€ข

++

Thread Thread
 
aibryx profile image
Alim Dzhanibekov โ€ข

+++

Collapse
 
softwaresennin profile image
Lionelโ™พ๏ธโ˜๏ธ โ€ข

Awesome job @shnai0 awesome job indeed!!

with this ... i am seeing that i really need to learn NextJS once i am done with python and done with JS. Wooow ... still got a roads to go.

Collapse
 
shnai0 profile image
Iuliia Shnai โ€ข

Thanks Lionel!

It seems that it pretty simple language and very clear one.

I donโ€™t know python:) maybe I should also look into it:)

Collapse
 
ldnovaes profile image
Leandro Duarte โ€ข

AWESOME!

Collapse
 
shnai0 profile image
Iuliia Shnai โ€ข

Thanks Leandro ๐Ÿ˜Š

Collapse
 
gutem profile image
Gutem โ€ข

ch == Switzerland (derived from Confoederatio Helvetica)
cn == China

Collapse
 
shnai0 profile image
Iuliia Shnai โ€ข

Omg

Thank you for noticing that Gutem. I was kind of confident it is like that. Need to push update for it.

Collapse
 
ahmadessam profile image
Ahmad Essam โ€ข

Nice work

Collapse
 
shnai0 profile image
Iuliia Shnai โ€ข

Thank you Ahmad!

Collapse
 
tommyleong profile image
TommyLeong โ€ข

Hello Iuliia. By any chance did you explore how i18n could pull latest translation content from an API? Not just on first launch, but on subsequent navigation or page refresh to always refer to latest translated content from backend.

Image of Docusign

๐Ÿ› ๏ธ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more