Skip to content

Commit

Permalink
Merge pull request #50 from fe-may23-dreamTeam/localization-jsons
Browse files Browse the repository at this point in the history
Localization jsons
  • Loading branch information
olena-ole authored Sep 21, 2023
2 parents bc2789f + e4f76cc commit ec20345
Show file tree
Hide file tree
Showing 20 changed files with 372 additions and 87 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
"@types/react-dom": "^18.2.7",
"axios": "^1.5.0",
"classnames": "^2.3.2",
"i18next": "^23.4.6",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.1",
"react-i18next": "^13.2.2",
"react-icons": "^4.10.1",
"react-redux": "^8.1.2",
"react-router-dom": "^6.15.0",
Expand Down
18 changes: 10 additions & 8 deletions src/components/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import classNames from 'classnames';
import { useState } from 'react';
import { FiHeart } from 'react-icons/fi';
import toast from 'react-hot-toast';
import { useTranslation } from 'react-i18next';
import { FaHeart } from 'react-icons/fa';
import { FiHeart } from 'react-icons/fi';
import { NavLink } from 'react-router-dom';
import {
addItemToCart,
useAppDispatch,
toggleFavourite,
useAppDispatch,
useAppSelector,
} from '../redux';
import { IProduct } from '../types/Product';
import { Button } from './Button';
import { ProductProperties } from './ProductProperties';
import { IProduct } from '../types/Product';
import toast from 'react-hot-toast';
import { NavLink } from 'react-router-dom';

type Props = {
product: IProduct;
Expand All @@ -24,6 +25,7 @@ export const Card = ({ product, isFetching }: Props) => {
const { items } = useAppSelector((state) => state.cart);
const dispatch = useAppDispatch();
const [favorite, setFavorite] = useState(false);
const { t } = useTranslation();

const isFavourite = (id: string) =>
favouriteItems.some((item) => item._id === id);
Expand Down Expand Up @@ -52,7 +54,7 @@ export const Card = ({ product, isFetching }: Props) => {

const handleAddToCart = () => {
if (items.some(({ id }) => id === product._id)) {
toast.error('This product is already in your cart');
toast.error(t('toTheCartError'));

return;
}
Expand All @@ -69,7 +71,7 @@ export const Card = ({ product, isFetching }: Props) => {
};

dispatch(addItemToCart(itemData));
toast.success('Successfully added to your cart!');
toast.success(t('toTheCart'));
};

return (
Expand Down Expand Up @@ -116,7 +118,7 @@ export const Card = ({ product, isFetching }: Props) => {
<ProductProperties properties={productProps} />
<div className="flex justify-between gap-x-[8px]">
<Button onClick={handleAddToCart} outline={!!isAddedToCart}>
{isAddedToCart ? 'Added to cart' : 'Add to cart'}
{isAddedToCart ? t('addedToCart') : t('addToCart')}
</Button>
<button
className={classNames([
Expand Down
8 changes: 5 additions & 3 deletions src/components/CategoryCard.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { NavLink } from 'react-router-dom';
import { useGetProductsByCategoryQuery } from '../redux/api/productApi';
import { useTranslation } from 'react-i18next';

type Props = {
type: string;
image: string;
};

const CategoryCard = ({ type, image }: Props) => {
const { t } = useTranslation();
const normalizedType = type.toLowerCase();
const { data } = useGetProductsByCategoryQuery(normalizedType);
const modelCounter =
data?.totalProducts === 1
? `${data?.totalProducts} model`
: `${data?.totalProducts} models`;
? `${data?.totalProducts} ${t('model')}`
: `${data?.totalProducts} ${t('models')}`;

return (
<NavLink
Expand All @@ -25,7 +27,7 @@ const CategoryCard = ({ type, image }: Props) => {
className="w-full h-4/5 border-0 box-border rounded-lg"
/>
<p className="font-mont font-bold text-[22px] mt-[24px] text-primary-light dark:text-primary-dark">
{type}
{t(normalizedType)}
</p>
<p className="font-mont font-semibold text-[14px] text-secondary dark:text-secondary-dark">
{modelCounter}
Expand Down
12 changes: 7 additions & 5 deletions src/components/CheckoutModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { FiSmile, FiX } from 'react-icons/fi';
import { useNavigate } from 'react-router-dom';
import { FiX, FiSmile } from 'react-icons/fi';
import { Button } from './Button';

type Props = {
Expand All @@ -10,6 +11,7 @@ type Props = {

export const CheckoutModal: React.FC<Props> = ({ showModal, onCloseModal }) => {
const navigate = useNavigate();
const { t } = useTranslation();

function handlebackToHome() {
navigate('/');
Expand All @@ -30,20 +32,20 @@ export const CheckoutModal: React.FC<Props> = ({ showModal, onCloseModal }) => {
</button>
<div className="relative p-4 flex-auto">
<h3 className="flex justify-center items-center font-Mont text-primary-light dark:text-primary-dark text-2xl">
Your payment was successfull
{t('successfulPayment')}
</h3>
<p className="pt-8 flex items-center justify-center font-Mont text-secondary-light dark:text-secondary-dark gap-2">
Thank you for shopping with us!
{t('thanksForOrder')}
<span className="flex items-center">
<FiSmile className="text-accent-light dark:text-accent-dark mb-1" />
</span>
</p>
<p className="pt-2 flex justify-center font-Mont text-secondary">
Your order has been placed
{t('orderPlaced')}
</p>
</div>
<div className="flex justify-around p-6 rounded-b w-full max-w-xs m-auto">
<Button onClick={handlebackToHome}>Back to Home</Button>
<Button onClick={handlebackToHome}>{t('backHome')}</Button>
</div>
</div>
)}
Expand Down
13 changes: 8 additions & 5 deletions src/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { useTranslation } from 'react-i18next';
import { FiChevronUp } from 'react-icons/fi';
import { NavLink } from 'react-router-dom';
import logo from '../assets/images/logo.svg';
import { FiChevronUp } from 'react-icons/fi';

export const Footer = () => {
const { t } = useTranslation();

const handleClickToTop = () => {
window.scrollTo({
top: 0,
Expand All @@ -29,7 +32,7 @@ export const Footer = () => {
className="duration-150 select-none uppercase text-secondary-light dark:text-secondary-dark font-extrabold text-xs hover:text-primary-light dark:hover:text-primary-dark active:text-primary-light dark:active:text-primary-dark focus:text-primary-light dark:focus:text-primary-dark font-Mont"
href="#"
>
Github
GitHub
</a>
</li>

Expand All @@ -38,7 +41,7 @@ export const Footer = () => {
className="duration-150 select-none uppercase text-secondary-light dark:text-secondary-dark font-extrabold text-xs hover:text-primary-light dark:hover:text-primary-dark active:text-primary-light dark:active:text-primary-dark focus:text-primary-light dark:focus:text-primary-dark font-Mont"
to="/contacts"
>
Contacts
{t('contacts')}
</NavLink>
</li>

Expand All @@ -47,7 +50,7 @@ export const Footer = () => {
className="duration-150 select-none uppercase text-secondary-light dark:text-secondary-dark font-extrabold text-xs hover:text-primary-light dark:hover:text-primary-dark active:text-primary-light dark:active:text-primary-dark focus:text-primary-light dark:focus:text-primary-dark font-Mont"
href="#"
>
Rights
{t('rights')}
</a>
</li>
</ul>
Expand All @@ -56,7 +59,7 @@ export const Footer = () => {

<div className="flex justify-center tablet:justify-center items-center space-x-4 mt-4 tablet:mt-0 ">
<p className="select-none text-secondary-light dark:text-secondary-dark font-bold text-xs whitespace-nowrap tablet:pl-24">
Back to top
{t('backToTop')}
</p>
<div
onClick={handleClickToTop}
Expand Down
18 changes: 11 additions & 7 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
import classNames from 'classnames';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { FiHeart, FiMenu, FiShoppingBag, FiX } from 'react-icons/fi';
import { NavLink, useLocation } from 'react-router-dom';
import logo from '../assets/images/logo.svg';
import BurgerMenu from '../pages/BurgerMenu';
import { useAppSelector } from '../redux';
import { ItemCounter } from './ItemCounter';
import ThemeToggle from './ThemeToggle';

const navLinks = [
{ name: 'Home', path: '/' },
{ name: 'Phones', path: 'phones' },
{ name: 'Tablets', path: 'tablets' },
{ name: 'Accessories', path: 'accessories' },
];
import LanguageSelector from './LanguageSelector';

export const Header: React.FC = () => {
const { favouriteItems } = useAppSelector((state) => state.favourites);
const { items } = useAppSelector((state) => state.cart);
const { pathname } = useLocation();
const [menuIsOpen, setMenuIsOpen] = useState(false);
const iconColor = classNames('dark:text-primary-dark');
const { t } = useTranslation();

const navLinks = [
{ name: t('home'), path: '/' },
{ name: t('phones'), path: 'phones' },
{ name: t('tablets'), path: 'tablets' },
{ name: t('accessories'), path: 'accessories' },
];

const handleOpenMenu = () => setMenuIsOpen((prev) => !prev);

Expand Down Expand Up @@ -58,6 +61,7 @@ export const Header: React.FC = () => {
</div>

<div className="flex items-center justify-end">
<LanguageSelector />
<ThemeToggle />
<div className="border-l border-elements-light dark:border-elements-dark box-border">
<NavLink
Expand Down
50 changes: 50 additions & 0 deletions src/components/LanguageSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { FiGlobe } from 'react-icons/fi';

const LanguageSelector = () => {
const { i18n } = useTranslation();
const [isMenuOpen, setIsMenuOpen] = useState(false);

const toggleMenu = () => {
setIsMenuOpen(!isMenuOpen);
};

const changeLanguage = (language: string | undefined) => {
i18n.changeLanguage(language);
setIsMenuOpen(false);
};

const languageCodes = ['en', 'uk', 'ja'];

return (
<div
onClick={toggleMenu}
className="cursor-pointer relative hover:shadow-lg dark:hover:shadow-custom-dark duration-200 p-4 tablet:p-6 flex border-x border-elements-light dark:border-elements-dark"
>
<button
type="button"
className="text-sm font-semibold text-gray-900 dark:text-white-light items-center justify-center h-4 w-4"
>
<FiGlobe className="h-4 w-4" />
</button>
{isMenuOpen && (
<div className="absolute left-0 mt-9 tablet:mt-11 flex justify-center mb-2">
<div className="flex border rounded-lg shadow-md desktop:flex-col flex-row">
{languageCodes.map((code, index) => (
<button
key={index}
onClick={() => changeLanguage(code)}
className={`px-3 py-1 tablet:px-4 tablet:py-2 desktop:px-7 text-sm text-gray-900 text-center dark:text-white-light`}
>
{code.toUpperCase()}
</button>
))}
</div>
</div>
)}
</div>
);
};

export default LanguageSelector;
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Provider } from 'react-redux';
import './index.css';
import { Root } from './Root';
import { store } from './redux';
import './localization/i18n';

const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement,
Expand Down
27 changes: 27 additions & 0 deletions src/localization/i18n.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';

import translationEN from './locales/en.json';
import translationUK from './locales/uk.json';
import translationJA from './locales/ja.json';

i18n.use(initReactI18next).init({
resources: {
en: {
translation: translationEN,
},
uk: {
translation: translationUK,
},
ja: {
translation: translationJA,
},
},
lng: 'en',
fallbackLng: 'en',
interpolation: {
escapeValue: false,
},
});

export default i18n;
54 changes: 54 additions & 0 deletions src/localization/locales/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"home": "Home",
"phones": "Phones",
"tablets": "Tablets",
"accessories": "Accessories",
"title": "Welcome to Nice Gadgets store!",
"newModels": "Brand new models",
"addToCart": "Add to cart",
"toTheCart": "Successfully added to your cart!",
"toTheCartError": "This product is already in your cart",
"addedToCart": "Added to cart",
"shopByCategory": "Shop by category",
"mobilePhones": "Mobile phones",
"hotPrices": "Hot prices",
"contacts": "Contacts",
"rights": "Rights",
"backToTop": "Back to top",
"model": "model",
"modeli": "models",
"models": "models",
"sortBy": "Sort by",
"newest": "Newest",
"oldest": "Oldest",
"itemsOnPage": "Items on page",
"runOutOfProducts": "Sorry, we ran out of these products",
"back": "Back",
"availableColors": "Available colors",
"selectCapacity": "Select capacity",
"about": "About",
"techSpecs": "Tech specs",
"recomended": "Recomended",
"favourites": "Favourites",
"noFavourites": "You don't have favourite products",
"cart": "Cart",
"emptyCart": "Your cart is empty",
"startShopping": "Start shopping now!",
"totalFor": "Total for",
"item": "item",
"itemu": "items",
"items": "items",
"checkout": "Checkout",
"successfulPayment": "Your payment was successfull",
"thanksForOrder": "Thank you for shopping with us!",
"orderPlaced": "Your order has been placed",
"backHome": "Back to Home",
"pageNotFound": "Page not found",
"movedOrDeleted": "Most likely, this page has been moved or deleted",
"addressMistake": "You may have made a mistake when entering the address",
"checkAgain": "Please check it again",
"takeMeHome": "Take me home",
"contactSupport": "Contact support",
"ourTeam": "Our Team",
"language": "Language"
}
Loading

0 comments on commit ec20345

Please sign in to comment.