Sitemap
KudoAI

Bringing cutting-edge AI to the masses

i18n the Easy Way: React, Vite, and JSON Locale Files

5 min readAug 2, 2025

--

Press enter or click to view image in full size
Thumbnail AI Generated

Adding Multi-Language Support to React + Vite with i18next

Adding a multi-language option to your React application has never been easier. Using i18next makes it simple, and when combined with the speed of Vite - you will be up and running within minutes! In this blog we will go through how to add internationalization (i18n) to a Vite powered React App, using external JSON locale files and react-i18next.

Step 1: Create a new React + Vite project.

npm create vite@latest my-i18n-app -- --template react
cd my-i18n-app
npm install

output :

Press enter or click to view image in full size
output for the above command

Step 2: Install Required Packages
We are going to need 3 main packages:

i18next: the core i18n engine
react-i18next: react bindings for i18next
i18next-browser-languagedetector: detect user's browser language
i18next-http-backend: to load translations from external JSON files

npm install i18next react-i18next i18next-browser-languagedetector i18next-http-backend

Step 3: Project Structure Setup

Create a locales folder inside the public directory

public/
└── locales/
├── en.json
├── hi.json
├── de.json
└── fr.json

folder structure

Sample en.json

{
"home": {
"title": "Home",
"description": "Welcome to the home page"
},
"about": {
"title": "About Us",
"description": "Learn more about us on this page"
},
"common": {
"language": "Language",
"switch": "Switch"
}
}

sample de.json

{
"home": {
"title": "Willkommen auf unserer Website",
"description": "Dies ist die Startseite unserer mehrsprachigen Website."
},
"about": {
"title": "Über uns",
"description": "Hier erfahren Sie mehr über uns."
},
"common": {
"language": "Sprache",
"switch": "Wechseln"
}
}

sample hi.json

{
"home": {
"title": "मुखपृष्ठ",
"description": "मुखपृष्ठ पर आपका स्वागत है"
},
"about": {
"title": "हमारे बारे में",
"description": "इस पृष्ठ पर हमारे बारे में अधिक जानें"
},
"common": {
"language": "भाषा",
"switch": "स्विच करें"
}
}

sample fr.json

{
"home": {
"welcome": "Bienvenue",
"description": "Ceci est une démo"
},
"about": {
"title": "À propos de nous",
"description": "En savoir plus sur nous sur cette page"
},
"common": {
"language": "Langue",
"switch": "Changer"
}
}

Step 4: Configure i18n

Create a new file src/i18n.js and configure i18next:

import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import httpBackend from "i18next-http-backend";
i18n
.use(httpBackend)
.use(LanguageDetector) // detects browser language
.use(initReactI18next)
.init({
fallbackLng: "en", //fallback language
debug: true,
interpolation: {
escapeValue: false,
},
backend: {
loadPath: `/locales/{{lng}}.json`, //path of the languages
},
});

Step 5: Initialize i18n in App.jsx

Update your main.jsx file to include the i18n config:

import { useState } from "react";
import reactLogo from "./assets/react.svg";
import viteLogo from "/vite.svg";
import "./App.css";
import { Route, BrowserRouter as Router, Routes } from "react-router-dom";
import Home from "./Pages/Home";
import About from "./Pages/About";
import Layout from "./Pages/Layout";
import "../src/in8"; //path for in8

function App() {
const [count, setCount] = useState(0);

return (
<>
<Router>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="*" element={<div>404 Not Found</div>} />
</Route>
</Routes>
</Router>
</>
);
}

export default App;

Step 6: Use Translations in Components

Inside Home.jsx or any component:

import React from "react";
import { useTranslation } from "react-i18next";

const Home = () => {
const { t, i18n } = useTranslation();
return (
<div>
<h1>{t("home.title")}</h1>
<p>{t("home.description")}</p>
</div>
);
};

export default Home;

Now for About.jsx

import React, { use } from "react";
import { useTranslation } from "react-i18next";

const About = () => {
const { t } = useTranslation();
return (
<>
<div>
<h1>{t("about.title")}</h1> <p>{t("about.description")}</p>
</div>
</>
);
};

export default About;

src/Pages/Layout.jsx

import React, { use } from "react";
import { Outlet } from "react-router-dom";
import LanguageSwitcher from "../components/LanguageSwitcher";
import { useTranslation } from "react-i18next";

const navStyle = {
display: "flex",
gap: "1.5rem",
background: "#222",
padding: "1rem",
};

const linkStyle = {
color: "#fff",
textDecoration: "none",
fontWeight: "bold",
fontSize: "1.1rem",
};

const Layout = ({ children }) => {
const { t } = useTranslation();
return (
<div>
<header>
<nav style={navStyle}>
<a href="/" style={linkStyle}>
{t("home.title")}
</a>
<a href="/about" style={linkStyle}>
{t("about.title")}
</a>
<LanguageSwitcher />
</nav>
</header>
<main>
{children}

<Outlet />
</main>
</div>
);
};

export default Layout;

Step 7: Language Switcher src/components/LanguageSwitcher.jsx

import React from "react";
import { useTranslation } from "react-i18next";

const languages = [
{ code: "en", name: "English", native: "English", emoji: "🌍" },
{ code: "fr", name: "French", native: "Français", emoji: "🌎" },
{ code: "hi", name: "Hindi", native: "हिन्दी", emoji: "🌏" },
{ code: "de", name: "German", native: "Deutsch", emoji: "🌐" },
];

const LanguageSwitcher = ({ darkMode = false }) => {
const { i18n } = useTranslation();

const styles = {
container: {
display: "flex",
alignItems: "center",
gap: "0.5rem",
background: darkMode ? "#222" : "#f5f5f5",
color: darkMode ? "#f5f5f5" : "#222",
padding: "0.75rem 1rem",
borderRadius: "8px",
boxShadow: darkMode
? "0 2px 8px rgba(0,0,0,0.35)"
: "0 2px 8px rgba(0,0,0,0.07)",
},
select: {
padding: "0.5rem",
borderRadius: "6px",
border: "1px solid #444",
fontSize: "1rem",
background: darkMode ? "#333" : "#fff",
color: darkMode ? "#f5f5f5" : "#222",
},
icon: {
fontSize: "1.5rem",
},
};

return (
<>
<select
onChange={(e) => i18n.changeLanguage(e.target.value)}
value={i18n.language}
style={styles.select}
>
{languages.map((lang) => (
<option key={lang.code} value={lang.code}>
{lang.emoji} {lang.native} ({lang.name})
</option>
))}
</select>
</>
);
};

export default LanguageSwitcher;

Step 8: start your application

npm run dev

Final Output

You are now a owner of a fully functional, multilingual React + Vite app utilizing a separate JSON locale files.

Get R Tarunnayaka’s stories in your inbox

Join Medium for free to get updates from this writer.

Try changing the language and then watch the UI text change in real-time!

Final Output

Some Bonus Tips

You can use namespaces like {{lng}}/{{ns}}.json to modularize translating files.

You should store the user language choice of preference in localStorage or cookies.

You can use the useEffect hook to set the default language based on the logic in your app.

Conclusion

Internationalization is vital for creating apps that are globally accessible. Now that you have the power of react, vite, and i18next, you can integrate multiple languages into your apps quickly and cleanly.

If you have any questions or suggestions, leave a comment or check out the i18next documentation.

Bonus: Connect with Me

linkedin : https://www.linkedin.com/in/tarun-nayaka-r-28612a27a/

If you found this useful or faced any issue, feel free to reach out!

Happy Deploying! 🚀

About the Authors

Tarun Nayaka — A Tech Enthusiast and Top Voice Awardee!

Tarun Nayaka, a passionate learner and recipient of the Top Voice accolade in Web Applications and Web Design, is on a journey of mastering technology one challenge at a time. With expertise ranging from web development to AI, Tarun is dedicated to sharing knowledge and empowering communities. Join him in exploring the vast possibilities of the tech world!

--