Skip to content

Commit 572d410

Browse files
committed
add translation
1 parent 5c25c0f commit 572d410

File tree

16 files changed

+1015
-290
lines changed

16 files changed

+1015
-290
lines changed

examples/ecommerce-jewellery-store/src/App.tsx

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,36 @@ import { ProductDetails } from "./pages/ProductsDetails";
1414
import { CartProvider } from "./helpers/CartContext";
1515
import { AdminProvider } from './helpers/AdminContext';
1616
import { CategoriesProvider } from './helpers/CategoriesContext';
17-
import { ShoppingCartList } from "./components/ShoppingCartList"; // Adjust path if necessary
17+
import { ShoppingCartList } from "./components/ShoppingCartList";
18+
import { LanguageProvider } from "./helpers/LanguageContext";
1819

1920
function App() {
2021
return (
21-
<CartProvider>
22-
<AdminProvider>
23-
<CategoriesProvider>
24-
<Router basename="/kendo-react/ecommerce-jewellery-store">
25-
<Header />
26-
<SizedParent>
27-
<Routes>
28-
<Route path="/" element={<Home />} />
29-
<Route path="/paymentdetails" element={<PaymentDetails />} />
30-
<Route path="/thankyou" element={<ThankYou />} />
31-
<Route path="/contacts" element={<Contacts />} />
32-
<Route path="/products" element={<AllProductsListView />} />
33-
<Route path="/category" element={<DetailedCategory />} />
34-
<Route path="/product/:id" element={<ProductDetails />} />
35-
<Route path="/shoppingcart" element={<ShoppingCartList />} />
36-
</Routes>
37-
</SizedParent>
38-
<Footer />
39-
</Router>
40-
</CategoriesProvider>
41-
</AdminProvider>
42-
</CartProvider>
22+
<LanguageProvider>
23+
<CartProvider>
24+
<AdminProvider>
25+
<CategoriesProvider>
26+
<Router basename="/kendo-react/ecommerce-jewellery-store">
27+
<Header />
28+
<SizedParent>
29+
<Routes>
30+
<Route path="/" element={<Home />} />
31+
<Route path="/paymentdetails" element={<PaymentDetails />} />
32+
<Route path="/thankyou" element={<ThankYou />} />
33+
<Route path="/contacts" element={<Contacts />} />
34+
<Route path="/products" element={<AllProductsListView />} />
35+
<Route path="/category" element={<DetailedCategory />} />
36+
<Route path="/product/:id" element={<ProductDetails />} />
37+
<Route path="/shoppingcart" element={<ShoppingCartList />} />
38+
</Routes>
39+
</SizedParent>
40+
<Footer />
41+
</Router>
42+
</CategoriesProvider>
43+
</AdminProvider>
44+
</CartProvider>
45+
</LanguageProvider>
4346
);
4447
}
4548

46-
export default App;
49+
export default App;

examples/ecommerce-jewellery-store/src/components/FilterComponent.tsx

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,19 @@ import { SvgIcon } from "@progress/kendo-react-common";
44
import { filterIcon, sortAscIcon } from "@progress/kendo-svg-icons";
55
import { FilterDescriptor, SortDescriptor, State } from "@progress/kendo-data-query";
66
import { useCategoriesContext } from "../helpers/CategoriesContext";
7+
import { useLanguageContext } from "../helpers/LanguageContext";
78

8-
const chips = ["Bracelets", "Rings", "Earrings", "Watches", "Necklaces"];
9-
const statuses = ["Sale", "Recommended", "Must Have"];
10-
const materials = ["Gold", "Silver"];
11-
12-
interface FilterComponentProps {
13-
updateUI: (state: State) => void;
14-
}
15-
16-
export const FilterComponent: React.FC<FilterComponentProps> = ({ updateUI }) => {
9+
const FilterComponent: React.FC<{ updateUI: (state: State) => void }> = ({ updateUI }) => {
1710
const { selectedCategory, setSelectedCategory } = useCategoriesContext();
11+
const { t } = useLanguageContext();
12+
1813
const [categoryValue, setCategoryValue] = React.useState<string[]>([]);
19-
const [statusValue, setStatusValue] = React.useState<string>("Recommended");
20-
const [materialValue, setMaterialValue] = React.useState<string>("Material");
14+
const [statusValue, setStatusValue] = React.useState<string>(t.statusRecommended);
15+
const [materialValue, setMaterialValue] = React.useState<string>(t.materialPlaceholder);
16+
17+
const chips = t.categoriesData || [];
18+
const statuses = t.statusesData || [];
19+
const materials = t.materialsData || [];
2120

2221
useEffect(() => {
2322
if (selectedCategory) {
@@ -96,8 +95,8 @@ export const FilterComponent: React.FC<FilterComponentProps> = ({ updateUI }) =>
9695

9796
const clearFilters = () => {
9897
setCategoryValue([]);
99-
setStatusValue("Recommended");
100-
setMaterialValue("Material");
98+
setStatusValue(t.statusRecommended);
99+
setMaterialValue(t.materialPlaceholder);
101100
setSelectedCategory(null);
102101
updateUI({ filter: undefined, sort: undefined });
103102
};
@@ -106,13 +105,13 @@ export const FilterComponent: React.FC<FilterComponentProps> = ({ updateUI }) =>
106105
<section className="k-d-flex k-justify-content-between k-align-items-center">
107106
<span className="k-d-flex k-align-items-center">
108107
<span className="k-d-flex k-align-items-center k-pr-2">
109-
<SvgIcon icon={filterIcon}></SvgIcon> Filter:
108+
<SvgIcon icon={filterIcon}></SvgIcon> {t.filterLabel}
110109
</span>
111110
<span className="k-pr-2">
112111
<MultiSelect
113112
data={chips}
114113
value={categoryValue}
115-
placeholder="Category"
114+
placeholder={t.categoryPlaceholder}
116115
onChange={onCategoryChange}
117116
style={{ minWidth: "119px" }}
118117
/>
@@ -123,13 +122,15 @@ export const FilterComponent: React.FC<FilterComponentProps> = ({ updateUI }) =>
123122
</span>
124123
<span className="k-d-flex k-align-items-center">
125124
<span className="k-d-flex k-align-items-center k-pr-2">
126-
<SvgIcon icon={sortAscIcon}></SvgIcon> Sort by:
125+
<SvgIcon icon={sortAscIcon}></SvgIcon> {t.sortByLabel}
127126
</span>
128127
<span>
129128
<DropDownList data={statuses} value={statusValue} onChange={onStatusChange} />
130129
</span>
131130
</span>
132-
<button className="k-button k-button-flat" onClick={clearFilters}>Clear Filters</button>
131+
<button className="k-button k-button-flat" onClick={clearFilters}>{t.clearFiltersButton}</button>
133132
</section>
134133
);
135134
};
135+
136+
export default FilterComponent;

examples/ecommerce-jewellery-store/src/components/Footer.tsx

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,33 @@ import {
99
twitterIcon,
1010
} from '@progress/kendo-svg-icons';
1111
import viloraLogo from '@/assets/vilora-logo.png';
12+
import { useLanguageContext } from '../helpers/LanguageContext';
1213

1314
const Footer: React.FC = () => {
15+
const { t } = useLanguageContext();
16+
1417
return (
1518
<section className="k-py-10 k-px-12 header">
1619
<div className="k-d-flex k-flex-wrap k-justify-content-between k-gap-8 k-text-align-left">
17-
<div className="k-flex-basis-250 k-flex-grow-1 k-mb-4 k-mt-6" style={{marginLeft: '50px'}}>
20+
<div className="k-flex-basis-250 k-flex-grow-1 k-mb-4 k-mt-6" style={{ marginLeft: '50px' }}>
1821
<a href="#" className="k-d-block k-mb-4 k-text-align-center">
1922
<img src={viloraLogo} alt="Logo" />
2023
</a>
21-
<p className="k-m-0">We use cookies to improve your experience.</p>
22-
<p className="k-m-0">All rights reserved.</p>
23-
<p className="k-mt-4">Subscribe to our Newsletter:</p>
24-
<Label editorId="email" className="k-sr-only">Your Email</Label>
24+
<p className="k-m-0">{t.cookiesText}</p>
25+
<p className="k-m-0">{t.rightsReservedText}</p>
26+
<p className="k-mt-4">{t.subscribeText}</p>
27+
<Label editorId="email" className="k-sr-only">{t.emailPlaceholder}</Label>
2528
<TextBox
26-
placeholder="Email"
29+
placeholder={t.emailPlaceholder}
2730
className="k-w-full"
2831
suffix={() => (
2932
<InputSuffix>
3033
<InputSeparator />
31-
<Button themeColor="primary">Subscribe</Button>
34+
<Button themeColor="primary">{t.subscribeButtonText}</Button>
3235
</InputSuffix>
3336
)}
3437
/>
35-
<p className="k-mt-6">Follow us:</p>
38+
<p className="k-mt-6">{t.followUsText}</p>
3639
<div className="k-d-flex k-gap-2 k-align-items-center">
3740
<p className="k-d-flex k-align-items-center" style={{ gap: '10px' }}>
3841
<SvgIcon icon={facebookIcon} size="xlarge" /> Facebook
@@ -47,31 +50,27 @@ const Footer: React.FC = () => {
4750
</div>
4851

4952
<div className="k-flex-basis-200 k-flex-grow-1 k-d-flex k-flex-col k-gap-4 k-mt-6 k-text-align-center">
50-
<h4 className="k-color-primary k-font-bold">Customer Care</h4>
51-
<a href="#" className="k-link">Contact Us</a>
52-
<a href="#" className="k-link">Shopping Online</a>
53-
<a href="#" className="k-link">Track Your Order</a>
54-
<a href="#" className="k-link">Shipping & Delivery</a>
55-
<a href="#" className="k-link">Orders & Payment</a>
56-
<a href="#" className="k-link">Help</a>
53+
<h4 className="k-color-primary k-font-bold">{t.customerCareTitle}</h4>
54+
{Array.isArray(t.customerCareLinks) &&
55+
t.customerCareLinks.map((link: string, index: number) => (
56+
<a key={index} href="#" className="k-link">{link}</a>
57+
))}
5758
</div>
5859

5960
<div className="k-flex-basis-200 k-flex-grow-1 k-d-flex k-flex-col k-gap-4 k-mt-6 k-text-align-center">
60-
<h4 className="k-color-primary k-font-bold">Our Company</h4>
61-
<a href="#" className="k-link">Prominent Locations</a>
62-
<a href="#" className="k-link">Careers</a>
63-
<a href="#" className="k-link">Corporate Responsibility</a>
64-
<a href="#" className="k-link">Sustainability</a>
65-
<a href="#" className="k-link">Society Care</a>
61+
<h4 className="k-color-primary k-font-bold">{t.ourCompanyTitle}</h4>
62+
{Array.isArray(t.ourCompanyLinks) &&
63+
t.ourCompanyLinks.map((link: string, index: number) => (
64+
<a key={index} href="#" className="k-link">{link}</a>
65+
))}
6666
</div>
6767

68-
<div className="k-flex-basis-200 k-flex-grow-1 k-d-flex k-flex-col k-gap-4 k-mt-6 k-text-align-center" style={{marginRight: '150px'}}>
69-
<h4 className="k-color-primary k-font-bold">Legal & Privacy</h4>
70-
<a href="#" className="k-link">Terms of Use</a>
71-
<a href="#" className="k-link">Conditions of Sale</a>
72-
<a href="#" className="k-link">Return Policy</a>
73-
<a href="#" className="k-link">Privacy Policy</a>
74-
<a href="#" className="k-link">Cookie Policy</a>
68+
<div className="k-flex-basis-200 k-flex-grow-1 k-d-flex k-flex-col k-gap-4 k-mt-6 k-text-align-center" style={{ marginRight: '150px' }}>
69+
<h4 className="k-color-primary k-font-bold">{t.legalPrivacyTitle}</h4>
70+
{Array.isArray(t.legalPrivacyLinks) &&
71+
t.legalPrivacyLinks.map((link: string, index: number) => (
72+
<a key={index} href="#" className="k-link">{link}</a>
73+
))}
7574
</div>
7675
</div>
7776
</section>

examples/ecommerce-jewellery-store/src/components/Header.tsx

Lines changed: 73 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -9,83 +9,110 @@ import viloraLogo from "@/assets/vilora-logo.png";
99
import items from "../data/items";
1010
import { AppBar, AppBarSection } from "@progress/kendo-react-layout";
1111
import { useAdminContext } from "../helpers/AdminContext";
12-
import { useCategoriesContext } from "../helpers/CategoriesContext";
12+
import { useCategoriesContext } from "../helpers/CategoriesContext";
13+
import { useLanguageContext } from "../helpers/LanguageContext";
1314

1415
interface CustomMenuItemModel extends MenuItemModel {
1516
page?: string;
1617
}
1718

18-
1919
const Header: React.FC = () => {
2020
const navigate = useNavigate();
2121
const { toggleRole } = useAdminContext();
2222
const { setSelectedCategory } = useCategoriesContext();
23+
const { language, setLanguage, t } = useLanguageContext();
2324

2425
const handleCartClick = () => {
2526
navigate("/shoppingcart");
2627
};
2728

2829
const handleSwitchChange = () => {
29-
toggleRole();
30+
toggleRole();
3031
};
3132

3233
const handleMenuSelect = (event: MenuSelectEvent) => {
3334
const selectedItem: CustomMenuItemModel = event.item;
3435

36+
if (selectedItem.id?.startsWith("lang-")) {
37+
const selectedLanguage = selectedItem.id.replace("lang-", "");
38+
setLanguage(selectedLanguage);
39+
console.log(`Language chosen: ${selectedLanguage}`);
40+
return;
41+
}
42+
3543
if (selectedItem.page) {
3644
navigate(selectedItem.page);
3745
return;
3846
}
39-
47+
4048
const selectedCategory = selectedItem.text;
41-
if (selectedCategory === "All") {
42-
setSelectedCategory(null);
49+
if (selectedCategory === t.all) {
50+
setSelectedCategory(null);
4351
} else {
44-
setSelectedCategory(selectedCategory ?? null);
45-
navigate("/category");
52+
setSelectedCategory(selectedCategory ?? null);
53+
navigate("/category");
4654
}
4755
};
4856

57+
const translatedItems = items.map((item) => ({
58+
...item,
59+
text: t[`menu${item.text}`] || item.text,
60+
items: item.items?.map((subItem) => ({
61+
...subItem,
62+
text: t[`menu${subItem.text}`] || subItem.text,
63+
})),
64+
}));
65+
66+
const languageMenu = [
67+
{
68+
text: t.languageMenuTitle,
69+
items: [
70+
{ text: t.languageEnglish, id: "lang-en" },
71+
{ text: t.languageFrench, id: "lang-fr" },
72+
{ text: t.languageSpanish, id: "lang-es" },
73+
],
74+
},
75+
];
76+
4977
return (
50-
<AppBar themeColor="inherit">
51-
<AppBarSection className="k-flex-basis-0 k-flex-grow k-gap-2 k-align-items-center" style={{ paddingLeft: "50px" }}>
52-
<a href="#" className="k-d-sm-flex" style={{ marginRight: "50px" }}>
53-
<img src={viloraLogo} alt="Logo" />
54-
</a>
55-
<Menu items={items} onSelect={handleMenuSelect} />
56-
</AppBarSection>
78+
<AppBar themeColor="inherit">
79+
<AppBarSection
80+
className="k-flex-basis-0 k-flex-grow k-gap-2 k-align-items-center"
81+
style={{ paddingLeft: "50px" }}
82+
>
83+
<a href="#" className="k-d-sm-flex" style={{ marginRight: "50px" }}>
84+
<img src={viloraLogo} alt="Logo" />
85+
</a>
86+
<Menu items={translatedItems} onSelect={handleMenuSelect} />
87+
</AppBarSection>
5788

58-
<AppBarSection className="k-flex-basis-0 k-flex-grow k-justify-content-end k-gap-1.5">
59-
<TextBox
60-
placeholder="Search"
61-
prefix={() => (
62-
<>
63-
<InputPrefix orientation="horizontal">
64-
<span className="k-input-prefix-text">
65-
<SvgIcon icon={searchIcon} size="medium" />
66-
</span>
67-
</InputPrefix>
68-
<InputSeparator />
69-
</>
70-
)}
71-
style={{ width: 300 }}
72-
/>
73-
<Button svgIcon={userIcon} fillMode="flat" className="k-ml-2" />
74-
<Button
75-
svgIcon={cartIcon}
76-
fillMode="flat"
77-
className="k-ml-2"
78-
onClick={handleCartClick}
79-
/>
80-
<Switch
81-
className="switch-width"
82-
onLabel="Admin"
83-
offLabel="Client"
84-
onChange={handleSwitchChange}
85-
/>
86-
</AppBarSection>
87-
</AppBar>
89+
<AppBarSection className="k-flex-basis-0 k-flex-grow k-justify-content-end k-gap-1.5">
90+
<TextBox
91+
placeholder={t.searchPlaceholder}
92+
prefix={() => (
93+
<>
94+
<InputPrefix orientation="horizontal">
95+
<span className="k-input-prefix-text">
96+
<SvgIcon icon={searchIcon} size="medium" />
97+
</span>
98+
</InputPrefix>
99+
<InputSeparator />
100+
</>
101+
)}
102+
style={{ width: 300 }}
103+
/>
104+
<Button svgIcon={userIcon} fillMode="flat" className="k-ml-2" />
105+
<Button svgIcon={cartIcon} fillMode="flat" className="k-ml-2" onClick={handleCartClick} />
106+
<Switch
107+
className="switch-width"
108+
onLabel={t.adminLabel}
109+
offLabel={t.clientLabel}
110+
onChange={handleSwitchChange}
111+
/>
112+
<Menu items={languageMenu} onSelect={handleMenuSelect} />
113+
</AppBarSection>
114+
</AppBar>
88115
);
89116
};
90117

91-
export default Header;
118+
export default Header;

0 commit comments

Comments
 (0)