Implemented english, hindi and bangla language integration through i18next

This commit is contained in:
Md Asif 2024-09-29 15:40:10 +05:30
parent dc36a9c094
commit 59fa16cf2d
17 changed files with 401 additions and 47 deletions

154
package-lock.json generated
View File

@ -8,10 +8,14 @@
"name": "my-project", "name": "my-project",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"i18next": "^23.15.1",
"i18next-browser-languagedetector": "^8.0.0",
"i18next-http-backend": "^2.6.1",
"lucide-react": "^0.446.0", "lucide-react": "^0.446.0",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-i18next": "^15.0.2",
"react-router-dom": "^6.26.2" "react-router-dom": "^6.26.2"
}, },
"devDependencies": { "devDependencies": {
@ -310,6 +314,18 @@
"@babel/core": "^7.0.0-0" "@babel/core": "^7.0.0-0"
} }
}, },
"node_modules/@babel/runtime": {
"version": "7.25.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz",
"integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==",
"license": "MIT",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/template": { "node_modules/@babel/template": {
"version": "7.25.0", "version": "7.25.0",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz",
@ -1932,6 +1948,15 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/cross-fetch": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
"integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==",
"license": "MIT",
"dependencies": {
"node-fetch": "^2.6.12"
}
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.3", "version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@ -3116,6 +3141,56 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/html-parse-stringify": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
"license": "MIT",
"dependencies": {
"void-elements": "3.1.0"
}
},
"node_modules/i18next": {
"version": "23.15.1",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-23.15.1.tgz",
"integrity": "sha512-wB4abZ3uK7EWodYisHl/asf8UYEhrI/vj/8aoSsrj/ZDxj4/UXPOa1KvFt1Fq5hkUHquNqwFlDprmjZ8iySgYA==",
"funding": [
{
"type": "individual",
"url": "https://locize.com"
},
{
"type": "individual",
"url": "https://locize.com/i18next.html"
},
{
"type": "individual",
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
}
],
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.23.2"
}
},
"node_modules/i18next-browser-languagedetector": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz",
"integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.23.2"
}
},
"node_modules/i18next-http-backend": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-2.6.1.tgz",
"integrity": "sha512-rCilMAnlEQNeKOZY1+x8wLM5IpYOj10guGvEpeC59tNjj6MMreLIjIW8D1RclhD3ifLwn6d/Y9HEM1RUE6DSog==",
"license": "MIT",
"dependencies": {
"cross-fetch": "4.0.0"
}
},
"node_modules/ignore": { "node_modules/ignore": {
"version": "5.3.2", "version": "5.3.2",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
@ -3889,6 +3964,26 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-releases": { "node_modules/node-releases": {
"version": "2.0.18", "version": "2.0.18",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
@ -4458,6 +4553,28 @@
"react": "^18.3.1" "react": "^18.3.1"
} }
}, },
"node_modules/react-i18next": {
"version": "15.0.2",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.0.2.tgz",
"integrity": "sha512-z0W3/RES9Idv3MmJUcf0mDNeeMOUXe+xoL0kPfQPbDoZHmni/XsIoq5zgT2MCFUiau283GuBUK578uD/mkAbLQ==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.25.0",
"html-parse-stringify": "^3.0.1"
},
"peerDependencies": {
"i18next": ">= 23.2.3",
"react": ">= 16.8.0"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
},
"react-native": {
"optional": true
}
}
},
"node_modules/react-is": { "node_modules/react-is": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@ -4551,6 +4668,12 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
"license": "MIT"
},
"node_modules/regexp.prototype.flags": { "node_modules/regexp.prototype.flags": {
"version": "1.5.2", "version": "1.5.2",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
@ -5182,6 +5305,12 @@
"node": ">=8.0" "node": ">=8.0"
} }
}, },
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
"license": "MIT"
},
"node_modules/ts-interface-checker": { "node_modules/ts-interface-checker": {
"version": "0.1.13", "version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
@ -5403,6 +5532,31 @@
} }
} }
}, },
"node_modules/void-elements": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
"integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
"license": "BSD-2-Clause"
},
"node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"license": "MIT",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/which": { "node_modules/which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@ -10,10 +10,14 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"i18next": "^23.15.1",
"i18next-browser-languagedetector": "^8.0.0",
"i18next-http-backend": "^2.6.1",
"lucide-react": "^0.446.0", "lucide-react": "^0.446.0",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-i18next": "^15.0.2",
"react-router-dom": "^6.26.2" "react-router-dom": "^6.26.2"
}, },
"devDependencies": { "devDependencies": {

View File

@ -0,0 +1,41 @@
{
"appName": "সমন্বিত PACS কিষাণ সমাধান",
"username": "ব্যবহারকারীর নাম",
"pacsName": "PACS নাম",
"userType": "ব্যবহারকারীর ধরন",
"moduleName": "মডিউলের নাম",
"date": "তারিখ",
"home": "হোম",
"moduleList": "মডিউল তালিকা",
"enquiry": "অনুসন্ধান",
"lockerOperation": "লকার অপারেশন",
"reports": "রিপোর্ট",
"worklist": "কাজের",
"userManagement": "ব্যবহারকারী ব্যবস্থাপনা",
"logout": "প্রস্থান",
"kcc": "কেসিসি",
"trading": "বাণিজ্য",
"asset": "সম্পদ",
"locker": "লকার",
"pacsTeller": "PACS টেলার",
"authoriser": "অনুমোদনকারী",
"cashOfficer": "নগদ কর্মকর্তা",
"selfHelpGroup": "স্বনির্ভর গোষ্ঠী",
"deposit": "আমানত",
"loan": "ঋণ",
"share": "শেয়ার",
"lockerEnquiry": "লকার অনুসন্ধান",
"accountEnquiry": "অ্যাকাউন্ট অনুসন্ধান",
"accountCreation": "অ্যাকাউন্ট তৈরি",
"cabinetMaintenance": "ক্যাবিনেট রক্ষণাবেক্ষণ",
"lockerMaintenance": "লকার রক্ষণাবেক্ষণ",
"rentPenaltyCollection": "ভাড়া / জরিমানা সংগ্রহ",
"chargeManagement": "চার্জ ব্যবস্থাপনা",
"checkInOutManagement": "চেক ইন/আউট ব্যবস্থাপনা",
"accountSurrender": "অ্যাকাউন্ট সমর্পণ",
"myIntimation": "আমার বিজ্ঞপ্তি",
"changePassword": "পাসওয়ার্ড পরিবর্তন",
"resetLogin": "লগইন স্ট্যাটাস রিসেট করুন",
"currentDate" : "{{val, datetime}}"
}

View File

@ -0,0 +1,41 @@
{
"appName": "Integrated PACS Kisan Solution",
"username": "Username",
"pacsName": "PACS Name",
"userType": "User Type",
"moduleName": "Module Name",
"languageSelect": "Language",
"date": "Date",
"home": "Home",
"moduleList": "Module List",
"enquiry": "Enquiry",
"lockerOperation": "Locker Operation",
"reports": "Reports",
"worklist": "Worklist",
"userManagement": "User Management",
"logout": "Logout",
"kcc": "KCCP",
"trading": "Trading",
"asset": "Asset",
"selfHelpGroup": "Self Help Group",
"deposit": "Deposit",
"loan": "Loan",
"share": "Share",
"locker": "Locker",
"pacsTeller": "PACS Teller",
"authoriser": "Authoriser",
"cashOfficer": "Cash Officer",
"lockerEnquiry": "Locker Enquiry",
"accountEnquiry": "Account Enquiry",
"accountCreation": "Account Creation",
"cabinetMaintenance": "Cabinet Maintenance",
"lockerMaintenance": "Locker Maintenance",
"rentPenaltyCollection": "Rent / Penalty Collection",
"chargeManagement": "Charge Management",
"checkInOutManagement": "Check in/out Management",
"accountSurrender": "Account Surrender",
"myIntimation": "My Intimation",
"changePassword": "Change Password",
"resetLogin": "Reset Login Status",
"currentDate" : "{{val, datetime}}"
}

View File

@ -0,0 +1,41 @@
{
"appName": "समन्वित PACS किसान समाधान",
"username": "उपयोगकर्ता नाम",
"pacsName": "PACS नाम",
"userType": "उपयोगकर्ता प्रकार",
"moduleName": "मॉड्यूल नाम",
"languageSelect": "भाषा",
"date": "तारीख",
"home": "होम",
"moduleList": "मॉड्यूल सूची",
"enquiry": "पूछताछ",
"lockerOperation": "लॉकर ऑपरेशन",
"reports": "रिपोर्ट",
"worklist": "कार्य सूची",
"userManagement": "उपयोगकर्ता प्रबंधन",
"logout": "लॉगआउट",
"kcc": "केसीसी",
"trading": "व्यापार",
"asset": "संपत्ति",
"selfHelpGroup": "स्वयं सहायता समूह",
"deposit": "जमा",
"loan": "ऋण",
"share": "शेयर",
"locker": "लॉकर",
"pacsTeller": "PACS टेलर",
"authoriser": "PACS अधिकृत",
"cashOfficer": "कैश अधिकारी",
"lockerEnquiry": "लॉकर पूछताछ",
"accountEnquiry": "खाता पूछताछ",
"accountCreation": "खाता निर्माण",
"cabinetMaintenance": "कैबिनेट रखरखाव",
"lockerMaintenance": "लॉकर रखरखाव",
"rentPenaltyCollection": "किराया / जुर्माना संग्रह",
"chargeManagement": "शुल्क प्रबंधन",
"checkInOutManagement": "चेक इन/आउट प्रबंधन",
"accountSurrender": "खाता समर्पण",
"myIntimation": "मेरा सूचितकरण",
"changePassword": "पासवर्ड बदलें",
"resetLogin": "लॉगिन स्थिति रीसेट करें",
"currentDate" : "{{val, datetime}}"
}

View File

@ -1,5 +1,6 @@
import { Outlet } from "react-router-dom" import { Outlet } from "react-router-dom"
import Header from "./components/Header" import Header from "./components/Header"
import Footer from "./components/Footer"
function App() { function App() {
return <div className="flex flex-col min-h-screen"> return <div className="flex flex-col min-h-screen">
@ -7,6 +8,7 @@ function App() {
<main className="transition-color-mode px-7 flex-grow bg-surface dark:bg-surface-dark"> <main className="transition-color-mode px-7 flex-grow bg-surface dark:bg-surface-dark">
<Outlet /> <Outlet />
</main> </main>
<Footer />
</div> </div>
} }

View File

@ -1,14 +1,21 @@
import IpksLogo from '../assets/ipks_logo.svg'; import IpksLogo from '../assets/ipks_logo.svg';
import DarkModeToggle from './DarkModeToggle'; import DarkModeToggle from './DarkModeToggle';
import LanguageSelector from './LanguageSelector';
import { useTranslation } from 'react-i18next';
function AppTitle() { function AppTitle() {
const { t } = useTranslation();
return ( return (
<div className='flex items-center justify-between pt-3 pb-5'> <div className='flex items-center justify-between pt-3 pb-5'>
<div className='flex gap-5 items-center'> <div className='flex gap-5 items-center'>
<img src={IpksLogo} alt="IPKS Logo" className="h-16" /> <img src={IpksLogo} alt="IPKS Logo" className="h-16" />
<h1 className="text-title font-display font-bold">Integrated PACS Kisan Solution</h1> <h1 className="text-title font-display font-bold">{t('appName')}</h1>
</div>
<div className='flex items-center gap-2'>
<DarkModeToggle />
<LanguageSelector />
</div> </div>
<DarkModeToggle />
</div> </div>
); );
} }

View File

@ -1,12 +1,22 @@
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import BannerInfoElement from "./BannerInfoElement"; import BannerInfoElement from "./BannerInfoElement";
import { useTranslation } from "react-i18next";
function BannerInfo({info}) { function BannerInfo({info}) {
const date = new Date().toLocaleDateString('en-IN', {month: 'long', day: '2-digit', year: 'numeric'}).split(" "); const {t} = useTranslation();
const infoElements = Object.keys(info).map((key) => ( const infoElements = Object.keys(info).map((key) => (
<BannerInfoElement key={key} title={key} description={info[key]} /> <BannerInfoElement key={key} title={t(key)} description={t(info[key])} />
)) ))
infoElements.push(<BannerInfoElement key="date" title="Date" description={date.join(" ")} />); infoElements.push(
<BannerInfoElement
key="date"
title={t('date')}
description={t('currentDate',{val: new Date(), formatParams: {
val: { month: 'long', day: '2-digit', year: 'numeric'},
},})}
/>
);
return ( return (
<div className="flex justify-between pb-1"> <div className="flex justify-between pb-1">
{infoElements} {infoElements}

View File

@ -0,0 +1,9 @@
function Footer() {
return (
<footer>
<p>© 2021</p>
</footer>
);
}
export default Footer;

View File

@ -7,48 +7,38 @@ import Separator from "./Separator";
function Header() { function Header() {
const userInfo = getUserInfoFromSession(); const userInfo = getUserInfoFromSession();
const menuItems = [ const menuItems = [
{ name: "Home", submenu: [], path: "/" }, { name: "home", submenu: [], path: "/" },
{ {
name: "Module List", name: "moduleList",
submenu: [ submenu: [
{name: "KCC", path: "kcc"}, {name: "kcc", path: "kcc"},
{name: "Trading", path: "trading"}, {name: "trading", path: "trading"},
{name: "Asset", path: "asset"}, {name: "asset", path: "asset"},
{name: "Self Help Group", path: "shg"}, {name: "selfHelpGroup", path: "shg"},
{name: "Deposit", path: "deposit"}, {name: "deposit", path: "deposit"},
{name: "Loan", path: "loan"}, {name: "loan", path: "loan"},
{name: "Share", path: "share"}, {name: "share", path: "share"},
], ],
}, },
{ name: "Enquiry", submenu: [{name: "Locker Enquiry", path: "locker-enquiry"}, {name: "Account Enquiry", path: "account-enquiry"}] }, { name: "enquiry", submenu: [{name: "lockerEnquiry", path: "locker-enquiry"}, {name: "accountEnquiry", path: "account-enquiry"}] },
{ {
name: "Locker Operation", name: "lockerOperation",
submenu: [ submenu: [
{name: "Account Creation", path: "account-creation"}, {name: "accountCreation", path: "account-creation"},
{name: "Cabinet Maintenance", path: "cabinet-maintenance"}, {name: "cabinetMaintenance", path: "cabinet-maintenance"},
{name: "Locker Maintenance", path: "locker-maintenance"}, {name: "lockerMaintenance", path: "locker-maintenance"},
{name: "Rent/Penalty Collection", path: "rent-collection"}, {name: "rentPenaltyCollection", path: "rent-collection"},
{name: "Charge Management", path: "charge-management"}, {name: "chargeManagement", path: "charge-management"},
{name: "Check in/out Management", path: "check-in-out"}, {name: "checkInOutManagement", path: "check-in-out"},
{name: "Account Surrender", path: "account-surrender"} {name: "accountSurrender", path: "account-surrender"}
], ],
}, },
{ name: "worklist", submenu: [{name:"myIntimation", path: "my-intimation"}] },
{ {
name: "Reports", name: "userManagement",
submenu: [ submenu: [{name: "resetLogin", path: "reset-login"}, {name: "changePassword", path: "change-password"}],
{name: "Deposit Report", path: "deposit-report"},
{name: "Trial Balance Report", path: "trial-report"},
{name: "Deposit Return Report", path: "deposit-return-report"},
{name: "Account Statement Reports", path: "account-statement-report"},
{name: "Audit Reports", path: "audit-reports"}
],
}, },
{ name: "Worklist", submenu: [{name:"My Intimation", path: "my-intimation"}] }, { name: "logout", submenu: [] },
{
name: "User Management",
submenu: [{name: "Reset Loggen In Status", path: "reset-login"}, {name: "Change Password", path: "change-password"}],
},
{ name: "Log Out", submenu: [] },
]; ];
return ( return (

View File

@ -0,0 +1,21 @@
import { useTranslation } from 'react-i18next';
const LanguageSelector = () => {
const { i18n } = useTranslation();
const changeLanguage = (event) => {
i18n.changeLanguage(event.target.value);
};
return (
<div>
<select className='rounded-md bg-secondary dark:bg-secondary-dark focus:outline-none' id="language-select" onChange={changeLanguage} value={i18n.language}>
<option value="en">English</option>
<option value="bn"></option>
<option value="hi">ि</option>
</select>
</div>
);
};
export default LanguageSelector;

View File

@ -1,15 +1,17 @@
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";
const SubMenu = ({ items }) => { const SubMenu = ({ items }) => {
const {t} = useTranslation();
return ( return (
<div className=" <div className="
hidden absolute top-full left-0 border-t-3 border-primary dark:border-primary-dark bg-secondary hidden absolute top-full left-0 border-t-3 border-primary dark:border-primary-dark bg-secondary
dark:bg-secondary-dark rounded-2xl shadow-sm shadow-surface-variant-dark dark:shadow-primary group-hover:block z-10" dark:bg-secondary-dark rounded-2xl shadow-sm shadow-surface-variant-dark dark:shadow-primary group-hover:block z-10"
> >
{items.map((subItem, index) => ( {items.map((subItem, index) => (
<div key={index} className="px-6 py-2 text-nowrap hover:bg-white dark:hover:bg-secondary-variant-dark cursor-pointer first:rounded-t-2xl last:rounded-b-2xl first:pt-4 last:pb-4"> <div key={index} className="px-6 py-2 text-nowrap hover:bg-white dark:hover:bg-secondary-variant-dark cursor-pointer first:rounded-t-2xl second-last:rounded-b-2xl first:pt-4 last:pb-4">
<Link to={subItem.path}>{subItem.name}</Link> <Link to={subItem.path}>{t(subItem.name)}</Link>
</div> </div>
))} ))}
<svg className="absolute top-0 left-6 mt-[-13px] fill-primary dark:fill-primary-dark" width="16" height="13" viewBox="0 0 16 13" xmlns="http://www.w3.org/2000/svg"> <svg className="absolute top-0 left-6 mt-[-13px] fill-primary dark:fill-primary-dark" width="16" height="13" viewBox="0 0 16 13" xmlns="http://www.w3.org/2000/svg">
@ -20,11 +22,12 @@ const SubMenu = ({ items }) => {
}; };
function MenuBar({ menuItems }) { function MenuBar({ menuItems }) {
const {t} = useTranslation();
return ( return (
<div className="flex justify-between text-base pt-5 pb-2 font-body"> <div className="flex justify-between text-base pt-5 pb-2 font-body">
{menuItems.map((item, index) => {menuItems.map((item, index) =>
<div key={index} className="group relative pb-3 cursor-pointer"> <div key={index} className="group relative pb-3 cursor-pointer">
{item.name} {t(item.name)}
{item.submenu.length > 0 && <SubMenu items={item.submenu} />} {item.submenu.length > 0 && <SubMenu items={item.submenu} />}
</div> </div>
)} )}

19
src/i18n.js Normal file
View File

@ -0,0 +1,19 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import Backend from 'i18next-http-backend';
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
fallbackLng: 'en',
interpolation: { escapeValue: false},
debug: true,
backend: {
loadPath: '/locales/{{lng}}/{{ns}}.json',
},
});
export default i18n;

View File

@ -1,4 +1,5 @@
@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&family=Rubik:ital,wght@0,300..900;1,300..900&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&family=Rubik:ital,wght@0,300..900;1,300..900&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+Bengali:wght@100..900&family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap');
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
@ -17,4 +18,10 @@
transition-property: background-color, color, border-color; transition-property: background-color, color, border-color;
transition-duration: var(--transition-duration); transition-duration: var(--transition-duration);
} }
} }
@layer utilities {
.second-last-child {
@apply nth-last-child(2);
}
}

View File

@ -2,6 +2,7 @@ import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client' import { createRoot } from 'react-dom/client'
import App from './App.jsx' import App from './App.jsx'
import './index.css' import './index.css'
import './i18n'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'; import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import Placeholder from './pages/Placeholder.jsx'; import Placeholder from './pages/Placeholder.jsx';

View File

@ -1,9 +1,9 @@
const getUserInfoFromSession = () => { const getUserInfoFromSession = () => {
return { return {
"User Name": "Rajesh Kumar", username: "Rajesh Kumar",
"PACS / Bank Name": "Demo SKUS Ltd.", pacsName: "Demo SKUS Ltd.",
"User Type": "PACS Teller", userType: "pacsTeller",
"Module Name": "Locker", moduleName: "locker",
} }
} }

View File

@ -28,7 +28,7 @@ export default {
}, },
fontFamily: { fontFamily: {
display: ['Montserrat', 'sans-serif'], display: ['Montserrat', 'sans-serif'],
body: ['Rubik', 'sans-serif'], body: ['Rubik', 'Noto Sans','Noto Sans Bengali', 'sans-serif'],
}, },
extend: { extend: {
borderWidth: { borderWidth: {
@ -39,6 +39,10 @@ export default {
}, },
}, },
}, },
plugins: [], plugins: [
function ({ addVariant }) {
addVariant('second-last', '&:nth-last-child(2)');
},
],
} }