create-magic-storefront 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template/.claude/skills/storefront-design/SKILL.md +10 -3
- package/template/.claude/skills/storefront-verify/SKILL.md +85 -0
- package/template/.claude/skills/vercel-react-best-practices/AGENTS.md +3810 -0
- package/template/.claude/skills/vercel-react-best-practices/README.md +123 -0
- package/template/.claude/skills/vercel-react-best-practices/SKILL.md +149 -0
- package/template/.claude/skills/vercel-react-best-practices/SOURCE.md +7 -0
- package/template/.claude/skills/vercel-react-best-practices/metadata.json +15 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/_sections.md +46 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/_template.md +28 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/advanced-effect-event-deps.md +56 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/async-defer-await.md +82 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/bundle-analyzable-paths.md +63 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +60 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/js-flatmap-filter.md +60 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/js-request-idle-callback.md +105 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rendering-resource-hints.md +85 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +68 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +82 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rerender-use-deferred-value.md +59 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/server-hoist-static-io.md +149 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/server-no-shared-module-state.md +50 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/server-parallel-nested-fetching.md +34 -0
- package/template/.claude/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/template/.claude/skills/web-interface-guidelines/LICENSE +21 -0
- package/template/.claude/skills/web-interface-guidelines/SKILL.md +40 -0
- package/template/.claude/skills/web-interface-guidelines/SOURCE.md +9 -0
- package/template/.claude/skills/web-interface-guidelines/guidelines.md +155 -0
- package/template/AGENTS.md +7 -0
- package/template/PAGES.md +7 -2
- package/template/_gitignore +1 -0
- package/template/app/account/page.tsx +31 -11
- package/template/app/cart/page.tsx +50 -54
- package/template/app/checkout/page.tsx +86 -38
- package/template/app/collections/[handle]/page.tsx +3 -2
- package/template/app/error.tsx +6 -4
- package/template/app/globals.css +29 -0
- package/template/app/layout.tsx +4 -2
- package/template/app/not-found.tsx +5 -2
- package/template/app/pages/[handle]/page.tsx +3 -2
- package/template/app/search/page.tsx +11 -6
- package/template/components/buy-box.tsx +7 -4
- package/template/components/cart-link.tsx +8 -2
- package/template/components/pager.tsx +3 -1
- package/template/components/product-grid.tsx +9 -5
- package/template/components/sections/banner.tsx +7 -1
- package/template/components/sections/deal-of-day.tsx +16 -5
- package/template/components/sections/product-shelves.tsx +8 -7
- package/template/components/sections/store-reviews.tsx +7 -5
- package/template/lib/errors.ts +1 -4
- package/template/lib/i18n.ts +315 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import type { Schema } from '@magicstoreai/storefront-client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The storefront's own words, per language. Everything the merchant wrote (product titles,
|
|
5
|
+
* section titles, pages) comes translated from the API; only the interface is translated here.
|
|
6
|
+
* Server components pass `locale` from `lib/api.ts`, client components `useMagicStore().locale`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
type OrderStatus = Schema<'Order'>['status'];
|
|
10
|
+
|
|
11
|
+
function plural(
|
|
12
|
+
locale: string,
|
|
13
|
+
count: number,
|
|
14
|
+
forms: Partial<Record<Intl.LDMLPluralRule, string>> & { other: string },
|
|
15
|
+
): string {
|
|
16
|
+
return forms[new Intl.PluralRules(locale).select(count)] ?? forms.other;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const en = {
|
|
20
|
+
// Navigation and shared
|
|
21
|
+
search: 'Search',
|
|
22
|
+
account: 'Account',
|
|
23
|
+
cart: 'Cart',
|
|
24
|
+
home: 'Home',
|
|
25
|
+
pages: 'Pages',
|
|
26
|
+
backToShop: 'Back to the shop',
|
|
27
|
+
continueShopping: 'Continue shopping',
|
|
28
|
+
seeAll: 'See all',
|
|
29
|
+
total: 'Total',
|
|
30
|
+
subtotal: 'Subtotal',
|
|
31
|
+
discount: 'Discount',
|
|
32
|
+
updating: 'Updating…',
|
|
33
|
+
// Errors
|
|
34
|
+
somethingWentWrong: 'Something went wrong',
|
|
35
|
+
tryAgainLater: 'Something went wrong. Please try again.',
|
|
36
|
+
tryAgain: 'Try again',
|
|
37
|
+
shopClosed: 'The shop is temporarily closed',
|
|
38
|
+
notFound: 'Page not found',
|
|
39
|
+
// Catalog
|
|
40
|
+
nothingHere: 'Nothing here yet.',
|
|
41
|
+
soldOut: 'Sold out',
|
|
42
|
+
preOrder: 'Pre-order',
|
|
43
|
+
sale: 'Sale',
|
|
44
|
+
isNew: 'New',
|
|
45
|
+
searchPlaceholder: 'What are you looking for?',
|
|
46
|
+
found: (count: number) => `${count} found`,
|
|
47
|
+
// Home sections
|
|
48
|
+
newArrivals: 'New arrivals',
|
|
49
|
+
onSale: 'On sale',
|
|
50
|
+
trending: 'Trending',
|
|
51
|
+
bestsellers: 'Bestsellers',
|
|
52
|
+
banner: 'Banner',
|
|
53
|
+
stockLeft: (remaining: number, initial: number) => `${remaining} of ${initial} left`,
|
|
54
|
+
endsAt: 'Ends',
|
|
55
|
+
customersSay: 'What our customers say',
|
|
56
|
+
reviewsCount: (count: number) =>
|
|
57
|
+
`${count} ${plural('en', count, { one: 'review', other: 'reviews' })}`,
|
|
58
|
+
recommendUs: (percent: number) => `${percent}% recommend us`,
|
|
59
|
+
leaveReview: 'Leave a review',
|
|
60
|
+
// Product
|
|
61
|
+
addToCart: 'Add to cart',
|
|
62
|
+
addedToCart: 'Added to cart.',
|
|
63
|
+
couldNotAdd: 'Could not add to cart.',
|
|
64
|
+
save: 'Save',
|
|
65
|
+
saved: 'Saved',
|
|
66
|
+
// Cart
|
|
67
|
+
cartEmpty: 'Your cart is empty',
|
|
68
|
+
loadingCart: 'Loading your cart…',
|
|
69
|
+
quantity: 'Quantity',
|
|
70
|
+
remove: 'Remove',
|
|
71
|
+
notAvailable: 'Not available any more',
|
|
72
|
+
discountCode: 'Discount code',
|
|
73
|
+
apply: 'Apply',
|
|
74
|
+
codeApplied: 'applied',
|
|
75
|
+
codeNotApplied: 'not applied',
|
|
76
|
+
checkout: 'Checkout',
|
|
77
|
+
// Checkout
|
|
78
|
+
checkoutTitle: 'Checkout',
|
|
79
|
+
preparingCheckout: 'Preparing checkout…',
|
|
80
|
+
contact: 'Contact',
|
|
81
|
+
name: 'Name',
|
|
82
|
+
phone: 'Phone',
|
|
83
|
+
saveContact: 'Save contact',
|
|
84
|
+
delivery: 'Delivery',
|
|
85
|
+
pickUp: 'Pick up',
|
|
86
|
+
orDeliverTo: 'Or deliver to',
|
|
87
|
+
deliverTo: 'Deliver to',
|
|
88
|
+
street: 'Street, house',
|
|
89
|
+
city: 'City',
|
|
90
|
+
latitude: 'Latitude',
|
|
91
|
+
longitude: 'Longitude',
|
|
92
|
+
useMyLocation: 'Use my location',
|
|
93
|
+
showDeliveryOptions: 'Show delivery options',
|
|
94
|
+
free: 'free',
|
|
95
|
+
payment: 'Payment',
|
|
96
|
+
placeOrder: 'Place order',
|
|
97
|
+
thankYou: 'Thank you!',
|
|
98
|
+
order: 'Order',
|
|
99
|
+
payNow: 'Pay now',
|
|
100
|
+
// Account
|
|
101
|
+
signIn: 'Sign in',
|
|
102
|
+
sendCode: 'Send code',
|
|
103
|
+
smsCode: 'Code from the SMS',
|
|
104
|
+
signOut: 'Sign out',
|
|
105
|
+
orders: 'Orders',
|
|
106
|
+
loadingOrders: 'Loading orders…',
|
|
107
|
+
noOrders: 'No orders yet.',
|
|
108
|
+
savedProducts: 'Saved products',
|
|
109
|
+
orderStatus: {
|
|
110
|
+
NEW: 'New',
|
|
111
|
+
ACCEPTED: 'Accepted',
|
|
112
|
+
PROCESSED: 'Processing',
|
|
113
|
+
ASSEMBLED: 'Packed',
|
|
114
|
+
DELIVERING: 'On the way',
|
|
115
|
+
DELIVERED: 'Delivered',
|
|
116
|
+
CANCELLED: 'Cancelled',
|
|
117
|
+
} satisfies Record<OrderStatus, string>,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
export type Messages = typeof en;
|
|
121
|
+
|
|
122
|
+
const ru: Messages = {
|
|
123
|
+
search: 'Поиск',
|
|
124
|
+
account: 'Кабинет',
|
|
125
|
+
cart: 'Корзина',
|
|
126
|
+
home: 'Главная',
|
|
127
|
+
pages: 'Страницы',
|
|
128
|
+
backToShop: 'Вернуться в магазин',
|
|
129
|
+
continueShopping: 'Продолжить покупки',
|
|
130
|
+
seeAll: 'Смотреть все',
|
|
131
|
+
total: 'Итого',
|
|
132
|
+
subtotal: 'Товары',
|
|
133
|
+
discount: 'Скидка',
|
|
134
|
+
updating: 'Обновляем…',
|
|
135
|
+
somethingWentWrong: 'Что-то пошло не так',
|
|
136
|
+
tryAgainLater: 'Что-то пошло не так. Попробуйте ещё раз.',
|
|
137
|
+
tryAgain: 'Попробовать снова',
|
|
138
|
+
shopClosed: 'Магазин временно закрыт',
|
|
139
|
+
notFound: 'Страница не найдена',
|
|
140
|
+
nothingHere: 'Здесь пока ничего нет.',
|
|
141
|
+
soldOut: 'Нет в наличии',
|
|
142
|
+
preOrder: 'Предзаказ',
|
|
143
|
+
sale: 'Скидка',
|
|
144
|
+
isNew: 'Новинка',
|
|
145
|
+
searchPlaceholder: 'Что вы ищете?',
|
|
146
|
+
found: (count) => `Найдено: ${count}`,
|
|
147
|
+
newArrivals: 'Новинки',
|
|
148
|
+
onSale: 'Со скидкой',
|
|
149
|
+
trending: 'Популярное',
|
|
150
|
+
bestsellers: 'Хиты продаж',
|
|
151
|
+
banner: 'Баннер',
|
|
152
|
+
stockLeft: (remaining, initial) => `Осталось ${remaining} из ${initial}`,
|
|
153
|
+
endsAt: 'Закончится',
|
|
154
|
+
customersSay: 'Что говорят покупатели',
|
|
155
|
+
reviewsCount: (count) =>
|
|
156
|
+
`${count} ${plural('ru', count, { one: 'отзыв', few: 'отзыва', other: 'отзывов' })}`,
|
|
157
|
+
recommendUs: (percent) => `${percent}% рекомендуют нас`,
|
|
158
|
+
leaveReview: 'Оставить отзыв',
|
|
159
|
+
addToCart: 'В корзину',
|
|
160
|
+
addedToCart: 'Добавлено в корзину.',
|
|
161
|
+
couldNotAdd: 'Не удалось добавить в корзину.',
|
|
162
|
+
save: 'В избранное',
|
|
163
|
+
saved: 'В избранном',
|
|
164
|
+
cartEmpty: 'Корзина пуста',
|
|
165
|
+
loadingCart: 'Загружаем корзину…',
|
|
166
|
+
quantity: 'Количество',
|
|
167
|
+
remove: 'Удалить',
|
|
168
|
+
notAvailable: 'Больше недоступен',
|
|
169
|
+
discountCode: 'Промокод',
|
|
170
|
+
apply: 'Применить',
|
|
171
|
+
codeApplied: 'применён',
|
|
172
|
+
codeNotApplied: 'не применён',
|
|
173
|
+
checkout: 'Оформить заказ',
|
|
174
|
+
checkoutTitle: 'Оформление заказа',
|
|
175
|
+
preparingCheckout: 'Готовим оформление…',
|
|
176
|
+
contact: 'Контакты',
|
|
177
|
+
name: 'Имя',
|
|
178
|
+
phone: 'Телефон',
|
|
179
|
+
saveContact: 'Сохранить контакты',
|
|
180
|
+
delivery: 'Доставка',
|
|
181
|
+
pickUp: 'Самовывоз',
|
|
182
|
+
orDeliverTo: 'Или доставка по адресу',
|
|
183
|
+
deliverTo: 'Доставка по адресу',
|
|
184
|
+
street: 'Улица, дом',
|
|
185
|
+
city: 'Город',
|
|
186
|
+
latitude: 'Широта',
|
|
187
|
+
longitude: 'Долгота',
|
|
188
|
+
useMyLocation: 'Моё местоположение',
|
|
189
|
+
showDeliveryOptions: 'Показать способы доставки',
|
|
190
|
+
free: 'бесплатно',
|
|
191
|
+
payment: 'Оплата',
|
|
192
|
+
placeOrder: 'Подтвердить заказ',
|
|
193
|
+
thankYou: 'Спасибо!',
|
|
194
|
+
order: 'Заказ',
|
|
195
|
+
payNow: 'Оплатить',
|
|
196
|
+
signIn: 'Войти',
|
|
197
|
+
sendCode: 'Получить код',
|
|
198
|
+
smsCode: 'Код из SMS',
|
|
199
|
+
signOut: 'Выйти',
|
|
200
|
+
orders: 'Заказы',
|
|
201
|
+
loadingOrders: 'Загружаем заказы…',
|
|
202
|
+
noOrders: 'Заказов пока нет.',
|
|
203
|
+
savedProducts: 'Избранное',
|
|
204
|
+
orderStatus: {
|
|
205
|
+
NEW: 'Новый',
|
|
206
|
+
ACCEPTED: 'Принят',
|
|
207
|
+
PROCESSED: 'В обработке',
|
|
208
|
+
ASSEMBLED: 'Собран',
|
|
209
|
+
DELIVERING: 'В пути',
|
|
210
|
+
DELIVERED: 'Доставлен',
|
|
211
|
+
CANCELLED: 'Отменён',
|
|
212
|
+
},
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const uz: Messages = {
|
|
216
|
+
search: 'Qidiruv',
|
|
217
|
+
account: 'Kabinet',
|
|
218
|
+
cart: 'Savat',
|
|
219
|
+
home: 'Bosh sahifa',
|
|
220
|
+
pages: 'Sahifalar',
|
|
221
|
+
backToShop: "Do'konga qaytish",
|
|
222
|
+
continueShopping: 'Xaridni davom ettirish',
|
|
223
|
+
seeAll: 'Barchasi',
|
|
224
|
+
total: 'Jami',
|
|
225
|
+
subtotal: 'Mahsulotlar',
|
|
226
|
+
discount: 'Chegirma',
|
|
227
|
+
updating: 'Yangilanmoqda…',
|
|
228
|
+
somethingWentWrong: 'Nimadir xato ketdi',
|
|
229
|
+
tryAgainLater: "Nimadir xato ketdi. Qaytadan urinib ko'ring.",
|
|
230
|
+
tryAgain: 'Qayta urinish',
|
|
231
|
+
shopClosed: "Do'kon vaqtincha yopiq",
|
|
232
|
+
notFound: 'Sahifa topilmadi',
|
|
233
|
+
nothingHere: "Hozircha bu yerda hech narsa yo'q.",
|
|
234
|
+
soldOut: "Sotuvda yo'q",
|
|
235
|
+
preOrder: 'Oldindan buyurtma',
|
|
236
|
+
sale: 'Chegirma',
|
|
237
|
+
isNew: 'Yangi',
|
|
238
|
+
searchPlaceholder: 'Nima qidiryapsiz?',
|
|
239
|
+
found: (count) => `${count} ta topildi`,
|
|
240
|
+
newArrivals: 'Yangi kelganlar',
|
|
241
|
+
onSale: 'Chegirmadagilar',
|
|
242
|
+
trending: 'Ommabop',
|
|
243
|
+
bestsellers: 'Xitlar',
|
|
244
|
+
banner: 'Banner',
|
|
245
|
+
stockLeft: (remaining, initial) => `${initial} tadan ${remaining} ta qoldi`,
|
|
246
|
+
endsAt: 'Tugaydi',
|
|
247
|
+
customersSay: 'Mijozlarimiz fikri',
|
|
248
|
+
reviewsCount: (count) => `${count} ta sharh`,
|
|
249
|
+
recommendUs: (percent) => `${percent}% bizni tavsiya qiladi`,
|
|
250
|
+
leaveReview: 'Sharh qoldirish',
|
|
251
|
+
addToCart: "Savatga qo'shish",
|
|
252
|
+
addedToCart: "Savatga qo'shildi.",
|
|
253
|
+
couldNotAdd: "Savatga qo'shib bo'lmadi.",
|
|
254
|
+
save: 'Saqlash',
|
|
255
|
+
saved: 'Saqlangan',
|
|
256
|
+
cartEmpty: "Savatingiz bo'sh",
|
|
257
|
+
loadingCart: 'Savat yuklanmoqda…',
|
|
258
|
+
quantity: 'Soni',
|
|
259
|
+
remove: "O'chirish",
|
|
260
|
+
notAvailable: 'Endi mavjud emas',
|
|
261
|
+
discountCode: 'Promokod',
|
|
262
|
+
apply: "Qo'llash",
|
|
263
|
+
codeApplied: "qo'llanildi",
|
|
264
|
+
codeNotApplied: "qo'llanilmadi",
|
|
265
|
+
checkout: 'Rasmiylashtirish',
|
|
266
|
+
checkoutTitle: 'Buyurtmani rasmiylashtirish',
|
|
267
|
+
preparingCheckout: 'Tayyorlanmoqda…',
|
|
268
|
+
contact: "Bog'lanish",
|
|
269
|
+
name: 'Ism',
|
|
270
|
+
phone: 'Telefon',
|
|
271
|
+
saveContact: 'Saqlash',
|
|
272
|
+
delivery: 'Yetkazib berish',
|
|
273
|
+
pickUp: 'Olib ketish',
|
|
274
|
+
orDeliverTo: 'Yoki manzilga yetkazish',
|
|
275
|
+
deliverTo: 'Manzilga yetkazish',
|
|
276
|
+
street: "Ko'cha, uy",
|
|
277
|
+
city: 'Shahar',
|
|
278
|
+
latitude: 'Kenglik',
|
|
279
|
+
longitude: 'Uzunlik',
|
|
280
|
+
useMyLocation: 'Joylashuvimni aniqlash',
|
|
281
|
+
showDeliveryOptions: "Yetkazib berish usullarini ko'rsatish",
|
|
282
|
+
free: 'bepul',
|
|
283
|
+
payment: "To'lov",
|
|
284
|
+
placeOrder: 'Buyurtmani tasdiqlash',
|
|
285
|
+
thankYou: 'Rahmat!',
|
|
286
|
+
order: 'Buyurtma',
|
|
287
|
+
payNow: "To'lash",
|
|
288
|
+
signIn: 'Kirish',
|
|
289
|
+
sendCode: 'Kod olish',
|
|
290
|
+
smsCode: 'SMS dagi kod',
|
|
291
|
+
signOut: 'Chiqish',
|
|
292
|
+
orders: 'Buyurtmalar',
|
|
293
|
+
loadingOrders: 'Buyurtmalar yuklanmoqda…',
|
|
294
|
+
noOrders: "Hozircha buyurtmalar yo'q.",
|
|
295
|
+
savedProducts: 'Saqlanganlar',
|
|
296
|
+
orderStatus: {
|
|
297
|
+
NEW: 'Yangi',
|
|
298
|
+
ACCEPTED: 'Qabul qilindi',
|
|
299
|
+
PROCESSED: 'Ishlov berilmoqda',
|
|
300
|
+
ASSEMBLED: "Yig'ildi",
|
|
301
|
+
DELIVERING: 'Yetkazilmoqda',
|
|
302
|
+
DELIVERED: 'Yetkazildi',
|
|
303
|
+
CANCELLED: 'Bekor qilindi',
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
export const MESSAGES = { en, ru, uz } as const;
|
|
308
|
+
|
|
309
|
+
/** The dictionary for a locale (`ru`, `ru-RU`, `uz-Latn-UZ`…); English when there is none. */
|
|
310
|
+
export function messages(locale: string): Messages {
|
|
311
|
+
const language = locale.toLowerCase().split('-')[0];
|
|
312
|
+
return language !== undefined && Object.hasOwn(MESSAGES, language)
|
|
313
|
+
? MESSAGES[language as keyof typeof MESSAGES]
|
|
314
|
+
: MESSAGES.en;
|
|
315
|
+
}
|