From 8f52988b6caa408a6c2ea5449bc0c9280c5cef93 Mon Sep 17 00:00:00 2001 From: BunyodL Date: Sat, 26 Apr 2025 18:58:50 +0500 Subject: [PATCH 1/6] update: add language-switcher --- src/shared/language/ui/language-switcher.tsx | 44 ++++++++++++++++++++ src/widgets/header/ui/desktop-nav.tsx | 2 +- src/widgets/header/ui/index.tsx | 12 ++++-- src/widgets/header/ui/mobile-nav.tsx | 2 +- 4 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 src/shared/language/ui/language-switcher.tsx diff --git a/src/shared/language/ui/language-switcher.tsx b/src/shared/language/ui/language-switcher.tsx new file mode 100644 index 0000000..0de4ed5 --- /dev/null +++ b/src/shared/language/ui/language-switcher.tsx @@ -0,0 +1,44 @@ +'use client'; + +import { Check, Globe } from 'lucide-react'; +import { useState } from 'react'; + +import { type Language, languages, useLanguage } from '@/shared/language'; +import { Button } from '@/shared/shadcn-ui/button'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from '@/shared/shadcn-ui/dropdown-menu'; + +export function LanguageSwitcher() { + const { language, setLanguage } = useLanguage(); + const [open, setOpen] = useState(false); + + return ( + + + + + + {Object.entries(languages).map(([code, { name, flag }]) => ( + { + setLanguage(code as Language); + setOpen(false); + }} + > + {flag} + {name} + {code === language && } + + ))} + + + ); +} diff --git a/src/widgets/header/ui/desktop-nav.tsx b/src/widgets/header/ui/desktop-nav.tsx index d08b2fb..b58db02 100644 --- a/src/widgets/header/ui/desktop-nav.tsx +++ b/src/widgets/header/ui/desktop-nav.tsx @@ -14,7 +14,7 @@ import { export function DesktopNav() { return ( - + diff --git a/src/widgets/header/ui/index.tsx b/src/widgets/header/ui/index.tsx index 020facc..464f14d 100644 --- a/src/widgets/header/ui/index.tsx +++ b/src/widgets/header/ui/index.tsx @@ -1,6 +1,7 @@ import Link from 'next/link'; import { Logo } from '@/shared/assets/logo'; +import { LanguageSwitcher } from '@/shared/language/ui/language-switcher'; import { Button } from '@/shared/shadcn-ui/button'; import { DesktopNav } from './desktop-nav'; @@ -12,11 +13,14 @@ export function Header() {
-
+
- - - +
+ + + + +
diff --git a/src/widgets/header/ui/mobile-nav.tsx b/src/widgets/header/ui/mobile-nav.tsx index 1fdd863..1e47b65 100644 --- a/src/widgets/header/ui/mobile-nav.tsx +++ b/src/widgets/header/ui/mobile-nav.tsx @@ -19,7 +19,7 @@ export function MobileNav() { return ( - From 6810f1c8441a282a06dcd7c628dd234bef279e60 Mon Sep 17 00:00:00 2001 From: BunyodL Date: Sat, 26 Apr 2025 19:11:31 +0500 Subject: [PATCH 2/6] refactor: divide language parts to separate folders --- .../language-provider.tsx} | 29 +++---------------- src/shared/language/hooks/use-language.ts | 18 ++++++++++++ src/shared/language/index.ts | 6 ++++ src/shared/providers/providers.tsx | 2 +- 4 files changed, 29 insertions(+), 26 deletions(-) rename src/shared/language/{index.tsx => context/language-provider.tsx} (73%) create mode 100644 src/shared/language/hooks/use-language.ts create mode 100644 src/shared/language/index.ts diff --git a/src/shared/language/index.tsx b/src/shared/language/context/language-provider.tsx similarity index 73% rename from src/shared/language/index.tsx rename to src/shared/language/context/language-provider.tsx index b2daf9c..ebf9db9 100644 --- a/src/shared/language/index.tsx +++ b/src/shared/language/context/language-provider.tsx @@ -1,16 +1,9 @@ 'use client'; -import { Loader } from 'lucide-react'; -import { - createContext, - type ReactNode, - useContext, - useEffect, - useState, -} from 'react'; +import { createContext, type ReactNode, useEffect, useState } from 'react'; -import enTranslations from './locales/en.json'; -import ruTranslations from './locales/ru.json'; +import enTranslations from '../locales/en.json'; +import ruTranslations from '../locales/ru.json'; // Define available languages export const languages = { @@ -36,7 +29,7 @@ type LanguageContextType = { t: (key: string) => string; }; -const LanguageContext = createContext( +export const LanguageContext = createContext( undefined, ); @@ -80,17 +73,3 @@ export function LanguageProvider({ children }: { children: ReactNode }) { ); } - -// Create hook -export function useLanguage() { - const context = useContext(LanguageContext); - if (context === undefined) { - throw new Error('useLanguage must be used within a LanguageProvider'); - } - - if (typeof context.t !== 'function') { - throw new Error('Translation function (t) is not available'); - } - - return context; -} diff --git a/src/shared/language/hooks/use-language.ts b/src/shared/language/hooks/use-language.ts new file mode 100644 index 0000000..6473281 --- /dev/null +++ b/src/shared/language/hooks/use-language.ts @@ -0,0 +1,18 @@ +'use client'; + +import { useContext } from 'react'; + +import { LanguageContext } from '../context/language-provider'; + +export function useLanguage() { + const context = useContext(LanguageContext); + if (context === undefined) { + throw new Error('useLanguage must be used within a LanguageProvider'); + } + + if (typeof context.t !== 'function') { + throw new Error('Translation function (t) is not available'); + } + + return context; +} diff --git a/src/shared/language/index.ts b/src/shared/language/index.ts new file mode 100644 index 0000000..35d8d88 --- /dev/null +++ b/src/shared/language/index.ts @@ -0,0 +1,6 @@ +export { + LanguageProvider, + languages, + type Language, +} from './context/language-provider'; +export { useLanguage } from './hooks/use-language'; diff --git a/src/shared/providers/providers.tsx b/src/shared/providers/providers.tsx index d4fa91b..f2c02cd 100644 --- a/src/shared/providers/providers.tsx +++ b/src/shared/providers/providers.tsx @@ -2,11 +2,11 @@ import { Provider } from 'react-redux'; +import { LanguageProvider } from '../language'; import { store } from '../store'; import { ThemeProvider } from '../theme/theme-provider'; import { AosProvider } from './aos-provider'; import { Toaster } from './toaster'; -import { LanguageProvider } from '../language'; type ProvidersProps = { children: React.ReactNode; From 2e22b4a51365e784a203d431c52e89b75edaa66e Mon Sep 17 00:00:00 2001 From: BunyodL Date: Sat, 26 Apr 2025 19:32:41 +0500 Subject: [PATCH 3/6] update: use language-hook for home page --- .../language/context/language-provider.tsx | 2 - src/widgets/about-section.tsx | 42 ++++++------ src/widgets/charity-section.tsx | 32 +++++---- src/widgets/cta-section.tsx | 25 ++++--- src/widgets/footer.tsx | 65 +++++++++---------- src/widgets/header/ui/index.tsx | 11 +++- src/widgets/hero-section.tsx | 21 ++++-- src/widgets/map-section.tsx | 20 +++--- src/widgets/partners-section.tsx | 22 ++++--- src/widgets/promotions-section.tsx | 15 +++-- src/widgets/vacancies-section.tsx | 22 ++++--- 11 files changed, 152 insertions(+), 125 deletions(-) diff --git a/src/shared/language/context/language-provider.tsx b/src/shared/language/context/language-provider.tsx index ebf9db9..de3e7c9 100644 --- a/src/shared/language/context/language-provider.tsx +++ b/src/shared/language/context/language-provider.tsx @@ -37,7 +37,6 @@ export const LanguageContext = createContext( export function LanguageProvider({ children }: { children: ReactNode }) { // Default to Russian, but check localStorage on client const [language, setLanguageState] = useState('ru'); - const [isLoaded, setIsLoaded] = useState(false); useEffect(() => { // Check if we're in the browser @@ -46,7 +45,6 @@ export function LanguageProvider({ children }: { children: ReactNode }) { if (savedLanguage && languages[savedLanguage]) { setLanguageState(savedLanguage); } - setIsLoaded(true); } }, []); diff --git a/src/widgets/about-section.tsx b/src/widgets/about-section.tsx index 08455c4..6eb7bd3 100644 --- a/src/widgets/about-section.tsx +++ b/src/widgets/about-section.tsx @@ -1,30 +1,27 @@ +'use client'; + import { Users } from 'lucide-react'; import Image from 'next/image'; import AboutCounter from '@/shared/components/about-counter'; +import { useLanguage } from '@/shared/language'; export const AboutSection = () => { + const { t } = useLanguage(); + return (
-
+
-
+

- О нашей компании + {t('home.about.title')}

-

- Наша сеть заправок является одной из ведущих в Таджикистане. Мы - предоставляем качественное топливо и высокий уровень обслуживания - для наших клиентов уже более 15 лет. -

-

- Мы постоянно развиваемся, открывая новые станции и улучшая сервис - на существующих. Наша цель - сделать заправку автомобиля - максимально удобной и быстрой для каждого клиента. -

+

{t('home.about.description1')}

+

{t('home.about.description2')}

@@ -33,9 +30,11 @@ export const AboutSection = () => {
-

Качественное топливо

+

+ {t('home.about.features.quality.title')} +

- Мы гарантируем высокое качество нашего топлива + {t('home.about.features.quality.description')}

@@ -45,10 +44,10 @@ export const AboutSection = () => {

- Современное оборудование + {t('home.about.features.equipment.title')}

- Все наши станции оснащены современным оборудованием + {t('home.about.features.equipment.description')}

@@ -58,19 +57,16 @@ export const AboutSection = () => {

- Профессиональный персонал + {t('home.about.features.staff.title')}

- Наши сотрудники - профессионалы своего дела + {t('home.about.features.staff.description')}

-
+
About our company { + const { t } = useLanguage(); + return (
-
+
-
+
Charity Foundation {

- Благотворительный фонд + {t('home.charity.title')}

- Наш благотворительный фонд был создан для поддержки социально - значимых проектов в Таджикистане. Мы стремимся внести свой вклад в - развитие общества и помочь тем, кто в этом нуждается. -

-

- Основные направления деятельности нашего фонда: + {t('home.charity.description')}

+

{t('home.charity.directions')}

  • - Поддержка образовательных программ + {t('home.charity.education')}
  • - Помощь детям из малообеспеченных семей + {t('home.charity.children')}
  • - Экологические инициативы + {t('home.charity.ecology')}
  • - Поддержка спортивных мероприятий + {t('home.charity.sports')}
diff --git a/src/widgets/cta-section.tsx b/src/widgets/cta-section.tsx index 6d358e5..b18547b 100644 --- a/src/widgets/cta-section.tsx +++ b/src/widgets/cta-section.tsx @@ -1,21 +1,28 @@ +'use client'; + +import { useLanguage } from '@/shared/language'; import { Button } from '@/shared/shadcn-ui/button'; export const CtaSection = () => { + const { t } = useLanguage(); + return (
-
+

- Присоединяйтесь к нам + {t('home.cta.title')}

-

- Станьте частью нашей сети. Получайте специальные предложения, бонусы - и скидки. -

+

{t('home.cta.description')}

- - +
diff --git a/src/widgets/footer.tsx b/src/widgets/footer.tsx index b7ab63a..c41624f 100644 --- a/src/widgets/footer.tsx +++ b/src/widgets/footer.tsx @@ -1,22 +1,24 @@ +'use client'; + import { Fuel, Mail, MapPin, Phone } from 'lucide-react'; import Link from 'next/link'; +import { useLanguage } from '@/shared/language'; import { Button } from '@/shared/shadcn-ui/button'; export const Footer = () => { + const { t } = useLanguage(); + return (