diff --git a/Frontend/package.json b/Frontend/package.json index 04f0317..9d6339a 100644 --- a/Frontend/package.json +++ b/Frontend/package.json @@ -13,10 +13,12 @@ "@reduxjs/toolkit": "^2.6.0", "@tailwindcss/vite": "^4.0.9", "axios": "^1.8.4", + "i18next": "^25.2.1", "lucide-react": "^0.476.0", "react": "^19.0.0", "react-dom": "^19.0.0", "react-hot-toast": "^2.5.2", + "react-i18next": "^15.5.3", "react-icons": "^5.5.0", "react-redux": "^9.2.0", "react-router-dom": "^7.2.0" diff --git a/Frontend/src/App.jsx b/Frontend/src/App.jsx index beaa1ba..f82225c 100644 --- a/Frontend/src/App.jsx +++ b/Frontend/src/App.jsx @@ -1,5 +1,6 @@ import "./App.css"; 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 SignUp from "./pages/Authentication/SignUp"; import DrivethruLandingPage from "./pages/UserPages/DrivethruLandingPage"; @@ -9,6 +10,7 @@ import NotFoundPage from "./pages/UserPages/NotFoundPage"; function App() { return ( + } /> } /> diff --git a/Frontend/src/TRANSLATION.md b/Frontend/src/TRANSLATION.md new file mode 100644 index 0000000..bd76ec9 --- /dev/null +++ b/Frontend/src/TRANSLATION.md @@ -0,0 +1,78 @@ +# TRANSLATION + +This is a comprehensive guide for translation for those who wish to contribute in any language. + +--- + +## 1. Add Your Language JSON File + +- Go to the `Frontend/src/locales/` directory. +- Copy an existing language file (e.g., `en.json`) and rename it to your language code (e.g., `es.json` for Spanish, `de.json` for German). +- Translate all the key-value pairs in your new file. + +**Example:** + +```shell +cp Frontend/src/locales/en.json Frontend/src/locales/es.json +``` + +```json +{ + "skycrate": "Skycrate", + "hero_subtitle": "Store, Access & Share Your Files — Anytime, Anywhere!", +} +``` + +## 2. Register the Language in `Frontend/src/i18n.js` + +- Open `Frontend/src/i18n.js`. +- Import your new JSON file: + +```js +import en from './locales/en.json'; +import fr from './locales/fr.json'; +// import more languages as needed +import es from './locales/es.json'; // <-- Add this line + +const resources = { + en: { translation: en }, + fr: { translation: fr }, + // add other languages here + es: { translation: es }, // <-- Add this line +}; +``` + +## 3. Update the Language Switcher + +- Open `Frontend/src/components/LanguageSwitcher.jsx`. +- Add your language to the `languages` array: + + +```js +const languages = [ + { code: 'en', label: 'English' }, + { code: 'fr', label: 'Français' }, + // Add more languages as needed + { code: 'es', label: 'Spanish' }, // <-- Add this line +]; +``` + +## 4. Test Your Translation + +- Start the app. +- Use the language switcher to select your new language. +- Check all pages for missing or untranslated keys. +- If you see a key instead of a translation, add it to your JSON file. + +## 5. Submit Your Contribution + +- Double-check your translations for accuracy and completeness. +- Commit your changes to: +- `Frontend/src/locales/.json` +- `Frontend/src/i18n.js` +- `Frontend/src/components/LanguageSwitcher.jsx` +- Open a pull request with a description of your contribution. + +--- + +## Thank you for making Skycrate accessible to more people! diff --git a/Frontend/src/components/Footer.jsx b/Frontend/src/components/Footer.jsx index 528c0c5..82a7ae0 100644 --- a/Frontend/src/components/Footer.jsx +++ b/Frontend/src/components/Footer.jsx @@ -8,15 +8,17 @@ import { Phone, MapPin, } from "lucide-react"; +import { useTranslation } from "react-i18next"; // for multilinguality const Footer = () => { + const { t } = useTranslation(); // for multilinguality const [email, setEmail] = useState(""); //Currently storing user email in localstorage const handleSubscribe = () => { if (email.trim() !== "") { localStorage.setItem("subscribedEmail", email); - alert("You have successfully subscribed!"); + alert(t("subscribe_success")); setEmail(""); } }; @@ -42,10 +44,10 @@ const Footer = () => { /> -

Skycrate

+

{t("footer_brand")}

- Your secure cloud storage solution for all your digital needs. + {t("footer_tagline")}

{ {/* Quick Links */}
-

Quick Links

+

{t("footer_quick_links")}

  • - About Us + {t("footer_about_us")}
  • @@ -96,7 +98,7 @@ const Footer = () => { href="#features" className="text-white/90 hover:text-white transition-all duration-200 hover:translate-x-1 inline-block" > - Features + {t("footer_features")}
  • @@ -104,7 +106,7 @@ const Footer = () => { href="#howItWorks" className="text-white/90 hover:text-white transition-all duration-200 hover:translate-x-1 inline-block" > - How It Works + {t("footer_how_it_works")}
@@ -112,43 +114,42 @@ const Footer = () => { {/* Contact Info */}
-

Contact

+

{t("footer_contact")}

  • - support@drivethru.com + {t("footer_email")}
  • - +91 3628206234 + {t("footer_phone")}
  • - 123 Cloud Street, Digital City + {t("footer_address")}
{/* Newsletter */}
-

Stay Updated

+

{t("footer_newsletter_title")}

- Get exclusive tips, updates on new features, and special offers - directly in your inbox. + {t("footer_newsletter_desc")}

setEmail(e.target.value)} - placeholder="Enter your email" + placeholder={t("footer_newsletter_placeholder")} className="w-full px-4 py-2 rounded-md bg-white/10 border border-white/20 text-white placeholder:text-white/50 focus:bg-white/20 transition-all duration-200 outline-none focus:ring-2 focus:ring-white/30" />
@@ -158,25 +159,25 @@ const Footer = () => { {/* Bottom Section */}
-

© {new Date().getFullYear()} Skycrate. All rights reserved.

+

© {new Date().getFullYear()} {t("footer_brand")}. {t("footer_rights")}

diff --git a/Frontend/src/components/LanguageSwitcher.jsx b/Frontend/src/components/LanguageSwitcher.jsx new file mode 100644 index 0000000..75d0498 --- /dev/null +++ b/Frontend/src/components/LanguageSwitcher.jsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +const languages = [ + { code: 'en', label: 'English' }, + { code: 'hi', label: 'Hindi (हिंदी)' }, + { code: 'mr', label: 'Marathi (मराठी)' }, + { code: 'fr', label: 'French (Français)' }, + // Add more languages as needed +]; + +function LanguageSwitcher() { + const { i18n } = useTranslation(); + + return ( +
+ +
+ ); +} + +export default LanguageSwitcher; + diff --git a/Frontend/src/components/Sidebar.jsx b/Frontend/src/components/Sidebar.jsx index 540fe82..50c2b8c 100644 --- a/Frontend/src/components/Sidebar.jsx +++ b/Frontend/src/components/Sidebar.jsx @@ -1,15 +1,17 @@ import { useState, useEffect, useRef } from "react"; import { Link, useNavigate } from "react-router-dom"; import { toast } from "react-hot-toast"; +import { useTranslation } from "react-i18next"; // for multilinguality const Sidebar = () => { + const { t } = useTranslation(); // for multilinguality const navigate = useNavigate(); // Hook for programmatic navigation const [userMenuOpen, setUserMenuOpen] = useState(false); const menuRef = useRef(); // Show loading toast and perform logout const handleLogout = () => { - const loadingToast = toast.loading("Logging out..."); + const loadingToast = toast.loading(t("sidebar_logging_out")); // Simulate a delay (for example, network request) setTimeout(() => { @@ -23,7 +25,7 @@ const Sidebar = () => { // Show success toast after logout toast.update(loadingToast, { - render: "Logged out successfully!", + render: t("sidebar_logged_out"), type: "success", isLoading: false, autoClose: 2000, @@ -55,7 +57,7 @@ const Sidebar = () => { type="button" className="inline-flex items-center p-2 text-lg text-white rounded-lg sm:hidden hover:bg-[#37A0EA] focus:outline-none" > - Open sidebar + {t("sidebar_open_sidebar")} { Skycrate Logo - Skycrate + {t("sidebar_brand")}
@@ -84,11 +86,11 @@ const Sidebar = () => { onClick={() => setUserMenuOpen((o) => !o)} className="flex text-lg bg-gray-800 rounded-full focus:ring-4 focus:ring-gray-300" > - Open user menu + {t("sidebar_open_user_menu")} User Photo @@ -109,7 +111,7 @@ const Sidebar = () => { className="w-full text-left px-4 py-2 text-lg text-white hover:bg-[#37A0EA]" role="menuitem" > - Log out + {t("sidebar_logout")} @@ -139,7 +141,7 @@ const Sidebar = () => { > - Starred + {t("sidebar_starred")} {/* ...additional sidebar items... */} diff --git a/Frontend/src/i18n.js b/Frontend/src/i18n.js new file mode 100644 index 0000000..28018a3 --- /dev/null +++ b/Frontend/src/i18n.js @@ -0,0 +1,30 @@ +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; + +import en from './locales/en.json'; +import hi from './locales/hi.json'; +import mr from './locales/mr.json'; +import fr from './locales/fr.json'; +// import more languages as needed + +const resources = { + en: { translation: en }, + hi: { translation: hi }, + mr: { translation: mr }, + 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; + diff --git a/Frontend/src/locales/en.json b/Frontend/src/locales/en.json new file mode 100644 index 0000000..63f52f9 --- /dev/null +++ b/Frontend/src/locales/en.json @@ -0,0 +1,94 @@ +{ + "dashboard": "Dashboard", + "failed_to_load_files": "Failed to load files. Please try again later.", + + "skycrate": "Skycrate", + "hero_subtitle": "Store, Access & Share Your Files — Anytime, Anywhere!", + "hero_desc": "A simple, secure, and fast cloud storage solution for all your files. Upload, organize, and access with ease.", + "get_started": "Get Started", + "login": "Login", + "key_features": "Key Features", + "feature_easy_upload_title": "Easy Upload & Access", + "feature_easy_upload_desc": "Drag & drop, instant access.", + "feature_secure_title": "Secure & Private", + "feature_secure_desc": "End-to-end encryption.", + "feature_sharing_title": "Seamless Sharing", + "feature_sharing_desc": "Share files with one click.", + "feature_access_anywhere_title": "Access Anywhere", + "feature_access_anywhere_desc": "Works on all devices.", + "how_it_works": "How It Works", + "how_create_account_title": "Create an account", + "how_create_account_desc": "Sign up in seconds.", + "how_upload_files_title": "Upload files", + "how_upload_files_desc": "Drag & drop or select from your device.", + "how_manage_files_title": "Manage files", + "how_manage_files_desc": "Rename, move, or delete easily.", + "how_access_anytime_title": "Access anytime", + "how_access_anytime_desc": "Open files from any device.", + + "not_found_title": "Page Not Found", + "not_found_description": "Sorry, we couldn't find the page you were looking for. It may have been moved or deleted.", + "go_home": "Go Home", + + "login_title": "Log in", + "email_placeholder": "Enter your email", + "password_placeholder": "Enter your password", + "forgot_password": "Forgot password?", + "logging_in": "Logging In...", + "login": "Login", + "dont_have_account": "Don’t have an account?", + "sign_up": "Sign up", + "login_successful": "Login successful!", + "login_failed": "Login failed.", + "an_error_occurred": "An error occurred. Please try again.", + "logging_in_toast": "Logging in...", + + "signup_title": "Sign Up", + "first_name": "First Name", + "last_name": "Last Name", + "email_placeholder": "Enter your email", + "password_placeholder": "Enter your password", + "confirm_password_placeholder": "Confirm your password", + "signing_up": "Signing Up...", + "sign_up": "Sign Up", + "already_have_account": "Already have an account?", + "login": "Login", + "passwords_do_not_match": "Passwords do not match.", + "registering": "Registering...", + "signup_failed": "Signup failed.", + "folder_creation_failed": "Failed to create user folder.", + "signup_success": "Successfully registered and folder created!", + "an_error_occurred": "An error occurred. Please try again.", + + "footer_brand": "Skycrate", + "footer_tagline": "Your secure cloud storage solution for all your digital needs.", + "footer_quick_links": "Quick Links", + "footer_about_us": "About Us", + "footer_features": "Features", + "footer_how_it_works": "How It Works", + "footer_contact": "Contact", + "footer_email": "support@drivethru.com", + "footer_phone": "+91 3628206234", + "footer_address": "123 Cloud Street, Digital City", + "footer_newsletter_title": "Stay Updated", + "footer_newsletter_desc": "Get exclusive tips, updates on new features, and special offers directly in your inbox.", + "footer_newsletter_placeholder": "Enter your email", + "footer_newsletter_button": "Subscribe to Newsletter", + "subscribe_success": "You have successfully subscribed!", + "footer_rights": "All rights reserved.", + "footer_privacy_policy": "Privacy Policy", + "footer_terms_of_service": "Terms of Service", + "footer_cookie_policy": "Cookie Policy", + + "sidebar_logging_out": "Logging out...", + "sidebar_logged_out": "Logged out successfully!", + "sidebar_open_sidebar": "Open sidebar", + "sidebar_brand": "Skycrate", + "sidebar_open_user_menu": "Open user menu", + "sidebar_user_photo": "User Photo", + "sidebar_logout": "Log out", + "sidebar_starred": "Starred" + + +} + diff --git a/Frontend/src/locales/fr.json b/Frontend/src/locales/fr.json new file mode 100644 index 0000000..ea88722 --- /dev/null +++ b/Frontend/src/locales/fr.json @@ -0,0 +1,92 @@ +{ + "dashboard": "Tableau de bord", + "failed_to_load_files": "Échec du chargement des fichiers. Veuillez réessayer plus tard.", + + "skycrate": "Skycrate", + "hero_subtitle": "Stockez, accédez et partagez vos fichiers — à tout moment, partout !", + "hero_desc": "Une solution de stockage cloud simple, sécurisée et rapide pour tous vos fichiers. Téléchargez, organisez et accédez facilement.", + "get_started": "Commencer", + "login": "Connexion", + "key_features": "Fonctionnalités clés", + "feature_easy_upload_title": "Téléversement et accès faciles", + "feature_easy_upload_desc": "Glissez-déposez, accès instantané.", + "feature_secure_title": "Sécurisé et privé", + "feature_secure_desc": "Chiffrement de bout en bout.", + "feature_sharing_title": "Partage sans effort", + "feature_sharing_desc": "Partagez des fichiers en un clic.", + "feature_access_anywhere_title": "Accès partout", + "feature_access_anywhere_desc": "Fonctionne sur tous les appareils.", + "how_it_works": "Comment ça marche", + "how_create_account_title": "Créer un compte", + "how_create_account_desc": "Inscrivez-vous en quelques secondes.", + "how_upload_files_title": "Téléverser des fichiers", + "how_upload_files_desc": "Glissez-déposez ou sélectionnez depuis votre appareil.", + "how_manage_files_title": "Gérer les fichiers", + "how_manage_files_desc": "Renommez, déplacez ou supprimez facilement.", + "how_access_anytime_title": "Accès à tout moment", + "how_access_anytime_desc": "Ouvrez des fichiers depuis n'importe quel appareil.", + + "not_found_title": "Page non trouvée", + "not_found_description": "Désolé, nous n'avons pas pu trouver la page que vous cherchiez. Elle a peut-être été déplacée ou supprimée.", + "go_home": "Accueil", + + "login_title": "Connexion", + "email_placeholder": "Entrez votre e-mail", + "password_placeholder": "Entrez votre mot de passe", + "forgot_password": "Mot de passe oublié ?", + "logging_in": "Connexion...", + "login": "Connexion", + "dont_have_account": "Vous n'avez pas de compte ?", + "sign_up": "S'inscrire", + "login_successful": "Connexion réussie !", + "login_failed": "Échec de la connexion.", + "an_error_occurred": "Une erreur s'est produite. Veuillez réessayer.", + "logging_in_toast": "Connexion en cours...", + + "sign_up": "S'inscrire", + "first_name": "Prénom", + "last_name": "Nom de famille", + "email_placeholder": "Entrez votre e-mail", + "password_placeholder": "Entrez votre mot de passe", + "confirm_password_placeholder": "Confirmez votre mot de passe", + "already_have_account": "Vous avez déjà un compte ?", + "login": "Connexion", + "signing_up": "Inscription...", + "passwords_do_not_match": "Les mots de passe ne correspondent pas.", + "registering": "Enregistrement...", + "signup_failed": "Échec de l'inscription.", + "failed_create_folder": "Échec de la création du dossier utilisateur.", + "signup_success": "Inscription réussie et dossier créé !", + "an_error_occurred": "Une erreur s'est produite. Veuillez réessayer.", + + "footer_brand": "Skycrate", + "footer_tagline": "Votre solution de stockage cloud sécurisée pour tous vos besoins numériques.", + "footer_quick_links": "Liens rapides", + "footer_about_us": "À propos", + "footer_features": "Fonctionnalités", + "footer_how_it_works": "Comment ça marche", + "footer_contact": "Contact", + "footer_email": "support@drivethru.com", + "footer_phone": "+91 3628206234", + "footer_address": "123 Rue du Cloud, Ville Digitale", + "footer_newsletter_title": "Restez informé", + "footer_newsletter_desc": "Recevez des conseils exclusifs, des mises à jour sur les nouvelles fonctionnalités et des offres spéciales directement dans votre boîte de réception.", + "footer_newsletter_placeholder": "Entrez votre e-mail", + "footer_newsletter_button": "S'abonner à la newsletter", + "subscribe_success": "Vous vous êtes abonné avec succès !", + "footer_rights": "Tous droits réservés.", + "footer_privacy_policy": "Politique de confidentialité", + "footer_terms_of_service": "Conditions d'utilisation", + "footer_cookie_policy": "Politique relative aux cookies", + + "sidebar_logging_out": "Déconnexion...", + "sidebar_logged_out": "Déconnecté avec succès !", + "sidebar_open_sidebar": "Ouvrir la barre latérale", + "sidebar_brand": "Skycrate", + "sidebar_open_user_menu": "Ouvrir le menu utilisateur", + "sidebar_user_photo": "Photo de l'utilisateur", + "sidebar_logout": "Se déconnecter", + "sidebar_starred": "Favoris" + + +} diff --git a/Frontend/src/locales/hi.json b/Frontend/src/locales/hi.json new file mode 100644 index 0000000..afcaa92 --- /dev/null +++ b/Frontend/src/locales/hi.json @@ -0,0 +1,92 @@ +{ + "dashboard": "डैशबोर्ड", + "failed_to_load_files": "फ़ाइलें लोड करने में विफल। कृपया बाद में पुनः प्रयास करें।", + + "skycrate": "Skycrate", + "hero_subtitle": "अपनी फ़ाइलें संग्रहित करें, एक्सेस करें और साझा करें — कभी भी, कहीं भी!", + "hero_desc": "आपकी सभी फ़ाइलों के लिए एक सरल, सुरक्षित और तेज़ क्लाउड स्टोरेज समाधान। अपलोड करें, व्यवस्थित करें और आसानी से एक्सेस करें।", + "get_started": "शुरू करें", + "login": "लॉगिन", + "key_features": "मुख्य विशेषताएं", + "feature_easy_upload_title": "सरल अपलोड और एक्सेस", + "feature_easy_upload_desc": "ड्रैग और ड्रॉप करें, त्वरित एक्सेस पाएं।", + "feature_secure_title": "सुरक्षित और निजी", + "feature_secure_desc": "एंड-टू-एंड एन्क्रिप्शन।", + "feature_sharing_title": "बिना रुकावट साझाकरण", + "feature_sharing_desc": "एक क्लिक में फ़ाइलें साझा करें।", + "feature_access_anywhere_title": "कहीं से भी एक्सेस करें", + "feature_access_anywhere_desc": "सभी डिवाइस पर कार्य करता है।", + + "how_it_works": "यह कैसे कार्य करता है", + "how_create_account_title": "खाता बनाएं", + "how_create_account_desc": "कुछ ही सेकंड में साइन अप करें।", + "how_upload_files_title": "फ़ाइलें अपलोड करें", + "how_upload_files_desc": "ड्रैग और ड्रॉप करें या डिवाइस से चुनें।", + "how_manage_files_title": "फ़ाइलें प्रबंधित करें", + "how_manage_files_desc": "आसानी से नाम बदलें, स्थानांतरित करें या हटाएं।", + "how_access_anytime_title": "कभी भी एक्सेस करें", + "how_access_anytime_desc": "किसी भी डिवाइस से फ़ाइलें खोलें।", + + "not_found_title": "पृष्ठ नहीं मिला", + "not_found_description": "क्षमा करें, हम वह पृष्ठ नहीं ढूंढ सके जिसे आप खोज रहे थे। यह हटाया गया हो सकता है या स्थानांतरित कर दिया गया हो।", + "go_home": "मुख्य पृष्ठ पर जाएं", + + "login_title": "लॉग इन करें", + "email_placeholder": "अपना ईमेल दर्ज करें", + "password_placeholder": "अपना पासवर्ड दर्ज करें", + "forgot_password": "पासवर्ड भूल गए?", + "logging_in": "लॉग इन किया जा रहा है...", + "login": "लॉगिन", + "dont_have_account": "कोई खाता नहीं है?", + "sign_up": "साइन अप करें", + "login_successful": "सफलतापूर्वक लॉगिन हुआ!", + "login_failed": "लॉगिन विफल रहा।", + "an_error_occurred": "एक त्रुटि हुई। कृपया पुनः प्रयास करें।", + "logging_in_toast": "लॉग इन किया जा रहा है...", + + "signup_title": "साइन अप करें", + "first_name": "पहला नाम", + "last_name": "अंतिम नाम", + "email_placeholder": "अपना ईमेल दर्ज करें", + "password_placeholder": "अपना पासवर्ड दर्ज करें", + "confirm_password_placeholder": "अपना पासवर्ड पुष्टि करें", + "signing_up": "साइन अप किया जा रहा है...", + "sign_up": "साइन अप करें", + "already_have_account": "पहले से ही खाता है?", + "login": "लॉगिन", + "passwords_do_not_match": "पासवर्ड मेल नहीं खा रहे हैं।", + "registering": "पंजीकरण किया जा रहा है...", + "signup_failed": "साइन अप विफल रहा।", + "folder_creation_failed": "यूज़र फ़ोल्डर बनाने में विफल।", + "signup_success": "सफलतापूर्वक पंजीकरण हुआ और फ़ोल्डर बनाया गया!", + "an_error_occurred": "एक त्रुटि हुई। कृपया पुनः प्रयास करें।", + + "footer_brand": "Skycrate", + "footer_tagline": "आपकी सभी डिजिटल आवश्यकताओं के लिए सुरक्षित क्लाउड स्टोरेज समाधान।", + "footer_quick_links": "त्वरित लिंक", + "footer_about_us": "हमारे बारे में", + "footer_features": "विशेषताएं", + "footer_how_it_works": "यह कैसे कार्य करता है", + "footer_contact": "संपर्क करें", + "footer_email": "support@drivethru.com", + "footer_phone": "+91 3628206234", + "footer_address": "123 क्लाउड स्ट्रीट, डिजिटल सिटी", + "footer_newsletter_title": "अपडेट प्राप्त करें", + "footer_newsletter_desc": "विशेष सुझाव, नई सुविधाओं के अपडेट और ऑफ़र सीधे अपने इनबॉक्स में पाएं।", + "footer_newsletter_placeholder": "अपना ईमेल दर्ज करें", + "footer_newsletter_button": "न्यूज़लेटर की सदस्यता लें", + "subscribe_success": "आपने सफलतापूर्वक सदस्यता ली है!", + "footer_rights": "सभी अधिकार सुरक्षित।", + "footer_privacy_policy": "गोपनीयता नीति", + "footer_terms_of_service": "सेवा की शर्तें", + "footer_cookie_policy": "कुकी नीति", + + "sidebar_logging_out": "लॉग आउट किया जा रहा है...", + "sidebar_logged_out": "सफलतापूर्वक लॉग आउट हुआ!", + "sidebar_open_sidebar": "साइडबार खोलें", + "sidebar_brand": "Skycrate", + "sidebar_open_user_menu": "उपयोगकर्ता मेनू खोलें", + "sidebar_user_photo": "उपयोगकर्ता फोटो", + "sidebar_logout": "लॉग आउट", + "sidebar_starred": "चिह्नित" +} diff --git a/Frontend/src/locales/mr.json b/Frontend/src/locales/mr.json new file mode 100644 index 0000000..c590a98 --- /dev/null +++ b/Frontend/src/locales/mr.json @@ -0,0 +1,92 @@ +{ + "dashboard": "डॅशबोर्ड", + "failed_to_load_files": "फायली लोड करण्यात अयशस्वी. कृपया नंतर पुन्हा प्रयत्न करा.", + + "skycrate": "Skycrate", + "hero_subtitle": "तुमच्या फायली साठवा, प्रवेश मिळवा आणि शेअर करा — कधीही, कुठेही!", + "hero_desc": "सर्व फायलींसाठी एक साधे, सुरक्षित आणि जलद क्लाऊड स्टोरेज सोल्यूशन. अपलोड करा, व्यवस्थापित करा आणि सहजपणे वापरा.", + "get_started": "सुरुवात करा", + "login": "लॉगिन", + "key_features": "मुख्य वैशिष्ट्ये", + "feature_easy_upload_title": "सोपे अपलोड आणि प्रवेश", + "feature_easy_upload_desc": "ड्रॅग आणि ड्रॉप, त्वरित प्रवेश.", + "feature_secure_title": "सुरक्षित आणि खाजगी", + "feature_secure_desc": "संपूर्ण एन्क्रिप्शन.", + "feature_sharing_title": "सुलभ शेअरिंग", + "feature_sharing_desc": "एक क्लिकमध्ये फायली शेअर करा.", + "feature_access_anywhere_title": "कोठूनही प्रवेश", + "feature_access_anywhere_desc": "सर्व डिव्हाइसेसवर कार्यरत.", + + "how_it_works": "हे कसे कार्य करते", + "how_create_account_title": "खाते तयार करा", + "how_create_account_desc": "काही सेकंदांत साइन अप करा.", + "how_upload_files_title": "फायली अपलोड करा", + "how_upload_files_desc": "ड्रॅग आणि ड्रॉप करा किंवा तुमच्या डिव्हाइसमधून निवडा.", + "how_manage_files_title": "फायली व्यवस्थापित करा", + "how_manage_files_desc": "नाव बदला, हलवा किंवा हटवा.", + "how_access_anytime_title": "कधीही प्रवेश करा", + "how_access_anytime_desc": "कोणत्याही डिव्हाइसवरून फायली उघडा.", + + "not_found_title": "पृष्ठ सापडले नाही", + "not_found_description": "क्षमस्व, तुम्ही शोधत असलेले पृष्ठ आम्हाला सापडले नाही. कदाचित ते हलवले गेले असेल किंवा हटवले गेले असेल.", + "go_home": "मुख्य पृष्ठावर जा", + + "login_title": "लॉग इन करा", + "email_placeholder": "तुमचा ईमेल टाका", + "password_placeholder": "तुमचा पासवर्ड टाका", + "forgot_password": "पासवर्ड विसरलात?", + "logging_in": "लॉग इन करत आहे...", + "login": "लॉग इन", + "dont_have_account": "अजून खाते नाही?", + "sign_up": "साइन अप", + "login_successful": "यशस्वीरित्या लॉग इन झाले!", + "login_failed": "लॉग इन अयशस्वी.", + "an_error_occurred": "त्रुटी आली. कृपया पुन्हा प्रयत्न करा.", + "logging_in_toast": "लॉग इन होत आहे...", + + "signup_title": "साइन अप करा", + "first_name": "पहिले नाव", + "last_name": "आडनाव", + "email_placeholder": "तुमचा ईमेल टाका", + "password_placeholder": "तुमचा पासवर्ड टाका", + "confirm_password_placeholder": "तुमचा पासवर्ड पुन्हा टाका", + "signing_up": "साइन अप करत आहे...", + "sign_up": "साइन अप", + "already_have_account": "आधीच खाते आहे?", + "login": "लॉग इन", + "passwords_do_not_match": "पासवर्ड जुळत नाहीत.", + "registering": "नोंदणी करत आहे...", + "signup_failed": "साइन अप अयशस्वी.", + "folder_creation_failed": "वापरकर्त्याची फोल्डर तयार करण्यात अयशस्वी.", + "signup_success": "यशस्वीरित्या नोंदणी झाली आणि फोल्डर तयार झाला!", + "an_error_occurred": "त्रुटी आली. कृपया पुन्हा प्रयत्न करा.", + + "footer_brand": "Skycrate", + "footer_tagline": "तुमच्या सर्व डिजिटल गरजांसाठी सुरक्षित क्लाऊड स्टोरेज सोल्यूशन.", + "footer_quick_links": "त्वरित दुवे", + "footer_about_us": "आमच्याबद्दल", + "footer_features": "वैशिष्ट्ये", + "footer_how_it_works": "हे कसे कार्य करते", + "footer_contact": "संपर्क", + "footer_email": "support@drivethru.com", + "footer_phone": "+९१ ३६२८२०६२३४", + "footer_address": "१२३ क्लाऊड स्ट्रीट, डिजिटल सिटी", + "footer_newsletter_title": "अपडेट मिळवा", + "footer_newsletter_desc": "विशेष टिप्स, नवीन वैशिष्ट्यांवरील अपडेट्स आणि खास ऑफर्स तुमच्या इनबॉक्समध्ये मिळवा.", + "footer_newsletter_placeholder": "तुमचा ईमेल टाका", + "footer_newsletter_button": "न्यूजलेटरची सदस्यता घ्या", + "subscribe_success": "तुमची सदस्यता यशस्वीरित्या घेतली गेली आहे!", + "footer_rights": "सर्व हक्क राखीव.", + "footer_privacy_policy": "गोपनीयता धोरण", + "footer_terms_of_service": "सेवेच्या अटी", + "footer_cookie_policy": "कुकी धोरण", + + "sidebar_logging_out": "लॉग आउट करत आहे...", + "sidebar_logged_out": "यशस्वीरित्या लॉग आउट झाले!", + "sidebar_open_sidebar": "साइडबार उघडा", + "sidebar_brand": "Skycrate", + "sidebar_open_user_menu": "वापरकर्ता मेनू उघडा", + "sidebar_user_photo": "वापरकर्त्याचा फोटो", + "sidebar_logout": "लॉग आउट", + "sidebar_starred": "आवडते" +} diff --git a/Frontend/src/main.jsx b/Frontend/src/main.jsx index 2439a22..bde4c3a 100644 --- a/Frontend/src/main.jsx +++ b/Frontend/src/main.jsx @@ -1,3 +1,5 @@ +import './i18n'; // for multilingual functionality + import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import "./index.css"; diff --git a/Frontend/src/pages/Authentication/Login.jsx b/Frontend/src/pages/Authentication/Login.jsx index 9fa60e0..20a8476 100644 --- a/Frontend/src/pages/Authentication/Login.jsx +++ b/Frontend/src/pages/Authentication/Login.jsx @@ -2,10 +2,12 @@ import { useState, useEffect } from "react"; import { FiEye, FiEyeOff } from "react-icons/fi"; import { Link, useNavigate } from "react-router-dom"; import toast from "react-hot-toast"; // Import React Hot Toast +import { useTranslation } from "react-i18next"; // for multilinguality const API_URL = import.meta.env.VITE_API_URL; // Using .env variable const Login = () => { + const { t } = useTranslation(); // for multilinguality const [showPassword, setShowPassword] = useState(false); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); @@ -28,7 +30,7 @@ const Login = () => { setLoading(true); // Show loading toast - const toastId = toast.loading("Logging in..."); + const toastId = toast.loading(t("logging_in_toast")); try { const response = await fetch(`${API_URL}/api/login`, { @@ -61,18 +63,17 @@ const Login = () => { }); // Show success toast - toast.success("Login successful!"); - + toast.success(t("login_successful")); // Redirect to Dashboard navigate("/dashboard"); } else { // Show error toast if login fails - toast.error(data.message || "Login failed."); + toast.error(data.message || t("login_failed")); } } catch (error) { // Dismiss the loading toast and show error toast.dismiss(toastId); - toast.error("An error occurred. Please try again.", error); + toast.error(t("an_error_occurred")); } finally { setLoading(false); } @@ -82,7 +83,7 @@ const Login = () => {

- Log in + {t("login_title")}

@@ -91,7 +92,7 @@ const Login = () => { setEmail(e.target.value)} @@ -104,7 +105,7 @@ const Login = () => { setPassword(e.target.value)} @@ -124,7 +125,7 @@ const Login = () => { to="#!" className="text-sm text-blue-600 hover:underline inline-block" > - Forgot password? + {t("forgot_password")}

- Don’t have an account?{" "} + {t("dont_have_account")}{" "} - Sign up + {t("sign_up")}

diff --git a/Frontend/src/pages/Authentication/SignUp.jsx b/Frontend/src/pages/Authentication/SignUp.jsx index 3c75291..77849e6 100644 --- a/Frontend/src/pages/Authentication/SignUp.jsx +++ b/Frontend/src/pages/Authentication/SignUp.jsx @@ -2,10 +2,12 @@ import { useState } from "react"; import { FiEye, FiEyeOff } from "react-icons/fi"; import { Link, useNavigate } from "react-router-dom"; import toast, { Toaster } from "react-hot-toast"; +import { useTranslation } from "react-i18next"; // for multilinguality const API_URL = import.meta.env.VITE_API_URL; const SignUp = () => { + const { t } = useTranslation(); // for multilinguality const navigate = useNavigate(); const [formData, setFormData] = useState({ @@ -30,12 +32,12 @@ const SignUp = () => { e.preventDefault(); if (formData.password !== formData.confirmPassword) { - toast.error("Passwords do not match."); + toast.error(t("passwords_do_not_match")); return; } setLoading(true); - const toastId = toast.loading("Registering..."); + const toastId = toast.loading(t("registering")); try { // 1️⃣ Sign up the user @@ -52,7 +54,7 @@ const SignUp = () => { const signupData = await signupRes.json(); if (!signupRes.ok) { - toast.error(signupData.message || "Signup failed.", { id: toastId }); + toast.error(signupData.message || t("signup_failed"), { id: toastId }); return; } @@ -66,11 +68,9 @@ const SignUp = () => { if (!folderRes.ok) { // you might choose to roll back user creation or just notify - toast.error("Failed to create user folder.", { id: toastId }); + toast.error(t("failed_create_folder"), { id: toastId }); } else { - toast.success("Successfully registered and folder created!", { - id: toastId, - }); + toast.success(t("signup_success"), { id: toastId }); } // 3️⃣ Redirect to login after a short delay @@ -79,7 +79,7 @@ const SignUp = () => { }, 1500); } catch (error) { console.error(error); - toast.error("An error occurred. Please try again.", { id: toastId }); + toast.error(t("an_error_occurred"), { id: toastId }); } finally { setLoading(false); } @@ -89,12 +89,12 @@ const SignUp = () => {
-

Sign Up

+

{t("sign_up")}

{ { { { { : "bg-gradient-to-r from-[#10B981] to-[#07533A] hover:from-[#0E458C] hover:to-[#1877F2]" } text-white font-semibold rounded-lg shadow-md transition duration-300`} > - {loading ? "Signing Up..." : "Sign Up"} + {loading ? t("signing_up") : t("sign_up")}
{/* Redirect to Login */}

- Already have an account?{" "} + {t("already_have_account")}{" "} - Login + {t("login")}

diff --git a/Frontend/src/pages/UserPages/Dashboard.jsx b/Frontend/src/pages/UserPages/Dashboard.jsx index 7d8ff46..50a6e92 100644 --- a/Frontend/src/pages/UserPages/Dashboard.jsx +++ b/Frontend/src/pages/UserPages/Dashboard.jsx @@ -1,16 +1,19 @@ import { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; +import { useTranslation } from "react-i18next"; // for multilinguality import Sidebar from "../../components/Sidebar"; import FileList from "../../components/FileList"; import FileUploadModal from "../../components/FileUploadModal"; import { FiPlus } from "react-icons/fi"; const Dashboard = () => { + const { t } = useTranslation(); // for multilinguality const [files, setFiles] = useState([]); const [isUploadModalOpen, setIsUploadModalOpen] = useState(false); const [error, setError] = useState(""); const navigate = useNavigate(); const API_URL = import.meta.env.VITE_API_URL; + const isUserLoggedIn = () => { const token = localStorage.getItem("token"); const username = localStorage.getItem("username"); @@ -36,7 +39,7 @@ const Dashboard = () => { setFiles(data); } catch (error) { console.error("Failed to fetch files:", error); - setError("Failed to load files. Please try again later."); + setError(t("failed_to_load_files")); } }; @@ -46,6 +49,7 @@ const Dashboard = () => { } else { fetchFiles(); } + // eslint-disable-next-line }, [navigate]); return ( @@ -54,7 +58,7 @@ const Dashboard = () => {
-

Dashboard

+

{t("dashboard")}

- Skycrate + {t("skycrate")}

- Store, Access & Share Your Files — Anytime, Anywhere! + {t("hero_subtitle")}

- A simple, secure, and fast cloud storage solution for all your - files. Upload, organize, and access with ease. + {t("hero_desc")}

{/* Buttons */} @@ -253,13 +255,13 @@ const DrivethruLandingPage = () => { to="/signup" className="bg-emerald-500 hover:bg-emerald-600 text-white font-medium rounded-full px-6 py-4 md:px-8 md:py-6 transform hover:scale-105 transition-all duration-300 shadow-lg hover:shadow-xl" > - Get Started + {t("get_started")} - Login + {t("login")}
@@ -283,7 +285,7 @@ const DrivethruLandingPage = () => { id="features" className="w-full max-w-5xl mx-auto p-6 sm:p-8 bg-gray-100 rounded-lg shadow-lg" > -

Key Features

+

{t("key_features")}

{/* Left Side - Image */}
@@ -328,7 +330,7 @@ const DrivethruLandingPage = () => { id="howItWorks" className="w-full max-w-5xl mx-auto p-6 sm:p-8 bg-gray-100 rounded-lg shadow-lg" > -

How It Works

+

{t("how_it_works")}

{/* Left Side - Feature List */}
diff --git a/Frontend/src/pages/UserPages/NotFoundPage.jsx b/Frontend/src/pages/UserPages/NotFoundPage.jsx index 546de5c..75d60f3 100644 --- a/Frontend/src/pages/UserPages/NotFoundPage.jsx +++ b/Frontend/src/pages/UserPages/NotFoundPage.jsx @@ -1,29 +1,25 @@ import { Link } from "react-router-dom"; +import { useTranslation } from "react-i18next"; // for multilinguality const NotFoundPage = () => { + const { t } = useTranslation(); // for multilinguality + return (
- {/* Placeholder SVG - Replace this with your SVG */} 404 Not Found - {/* Page number and title */} -

Page Not Found

- - {/* Description text */} + /> +

{t("not_found_title")}

- Sorry, we couldn't find the page you were looking for. It may have - been moved or deleted. + {t("not_found_description")}

- - {/* Call-to-action button */} - Go Home + {t("go_home")}
);