Added the foundation for making the frontend multilingual. Now only need to import useTranslation and use t('key') for all user-facing text for all pages (+add key:value pairs in src/locales for each language ofc)
- package.json -> Imported packages i18next & react-i18next for multilingual functionality. - src/App.jsx -> Imported LanguageSwitcher from ./components/LanguageSwitcher and added <LanguageSwitcher /> component at the beginning of layout so it's always visible. - src/components/LanguageSwitcher.jsx -> LanguageSwitcher component, consists of a dropdown menu that always appears at top right corner for choosing language. - src/i18n.js -> Initialize and configure i18next for app-wide multilingual support. - src/locales/en.json + src/locales/fr.json -> Empty json files that will soon contain translation key:value pairs for each page. - src/main.jsx -> Imported src/i18n.js for multilingual functionality.
This commit is contained in:
@@ -13,10 +13,12 @@
|
|||||||
"@reduxjs/toolkit": "^2.6.0",
|
"@reduxjs/toolkit": "^2.6.0",
|
||||||
"@tailwindcss/vite": "^4.0.9",
|
"@tailwindcss/vite": "^4.0.9",
|
||||||
"axios": "^1.8.4",
|
"axios": "^1.8.4",
|
||||||
|
"i18next": "^25.2.1",
|
||||||
"lucide-react": "^0.476.0",
|
"lucide-react": "^0.476.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-hot-toast": "^2.5.2",
|
"react-hot-toast": "^2.5.2",
|
||||||
|
"react-i18next": "^15.5.3",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-redux": "^9.2.0",
|
"react-redux": "^9.2.0",
|
||||||
"react-router-dom": "^7.2.0"
|
"react-router-dom": "^7.2.0"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import "./App.css";
|
import "./App.css";
|
||||||
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
||||||
|
import LanguageSwitcher from './components/LanguageSwitcher'; // Language switcher dropdown menu
|
||||||
import Login from "./pages/Authentication/Login";
|
import Login from "./pages/Authentication/Login";
|
||||||
import SignUp from "./pages/Authentication/SignUp";
|
import SignUp from "./pages/Authentication/SignUp";
|
||||||
import DrivethruLandingPage from "./pages/UserPages/DrivethruLandingPage";
|
import DrivethruLandingPage from "./pages/UserPages/DrivethruLandingPage";
|
||||||
@@ -9,6 +10,7 @@ import NotFoundPage from "./pages/UserPages/NotFoundPage";
|
|||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
|
<LanguageSwitcher />
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<DrivethruLandingPage />} />
|
<Route path="/" element={<DrivethruLandingPage />} />
|
||||||
<Route path="/login" element={<Login />} />
|
<Route path="/login" element={<Login />} />
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
|
const languages = [
|
||||||
|
{ code: 'en', label: 'English' },
|
||||||
|
{ code: 'fr', label: 'Français' },
|
||||||
|
// Add more languages as needed
|
||||||
|
];
|
||||||
|
|
||||||
|
function LanguageSwitcher() {
|
||||||
|
const { i18n } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '1rem',
|
||||||
|
right: '1rem',
|
||||||
|
zIndex: 1000,
|
||||||
|
background: 'rgba(255,255,255,0.95)',
|
||||||
|
borderRadius: '4px',
|
||||||
|
padding: '0.25em 0.5em',
|
||||||
|
boxShadow: '0 2px 8px rgba(0,0,0,0.05)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<select
|
||||||
|
value={i18n.language}
|
||||||
|
onChange={e => i18n.changeLanguage(e.target.value)}
|
||||||
|
style={{
|
||||||
|
border: '1px solid #ccc',
|
||||||
|
borderRadius: '4px',
|
||||||
|
padding: '0.25em 2em 0.25em 0.5em', // More right padding for arrow
|
||||||
|
minWidth: '100px',
|
||||||
|
appearance: 'auto', // Use browser default arrow
|
||||||
|
background: '#fff',
|
||||||
|
}}
|
||||||
|
|
||||||
|
aria-label="Select language"
|
||||||
|
>
|
||||||
|
{languages.map(lang => (
|
||||||
|
<option key={lang.code} value={lang.code}>
|
||||||
|
{lang.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LanguageSwitcher;
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import i18n from 'i18next';
|
||||||
|
import { initReactI18next } from 'react-i18next';
|
||||||
|
|
||||||
|
import en from './locales/en.json';
|
||||||
|
import fr from './locales/fr.json';
|
||||||
|
// import more languages as needed
|
||||||
|
|
||||||
|
const resources = {
|
||||||
|
en: { translation: en },
|
||||||
|
fr: { translation: fr },
|
||||||
|
// add other languages here
|
||||||
|
};
|
||||||
|
|
||||||
|
i18n
|
||||||
|
.use(initReactI18next)
|
||||||
|
.init({
|
||||||
|
resources,
|
||||||
|
lng: 'en', // default language
|
||||||
|
fallbackLng: 'en',
|
||||||
|
//interpolation: {
|
||||||
|
// escapeValue: false, // not needed for React
|
||||||
|
//},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default i18n;
|
||||||
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import './i18n'; // for multilingual functionality
|
||||||
|
|
||||||
import { StrictMode } from "react";
|
import { StrictMode } from "react";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
|
|||||||
Reference in New Issue
Block a user