orionplace-react 0.7.6 → 0.7.8

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.
Files changed (39) hide show
  1. package/README.md +1 -1
  2. package/package.json +2 -2
  3. package/templates/components/orionplace/legal/StorefrontPrivacy.README.md +2 -2
  4. package/templates/components/orionplace/orders/OrderDetails.tsx +2 -2
  5. package/templates/components/orionplace/search/MainSearch.tsx +2 -2
  6. package/templates/components/orionplace/shared/OrionplaceBreadcrumbs.tsx +1 -1
  7. package/templates/components/orionplace/shared/StorefrontPagination.tsx +1 -1
  8. package/templates/components/orionplace/storefront/StorefrontFooter.tsx +1 -1
  9. package/templates/hooks/useOrionplaceStorefront.tsx +26 -8
  10. package/templates/lib/orionplace/accountLabels.ts +7 -0
  11. package/templates/lib/orionplace/activityLabels.ts +32 -1
  12. package/templates/lib/orionplace/blogLabels.ts +47 -1
  13. package/templates/lib/orionplace/browseLabels.ts +48 -1
  14. package/templates/lib/orionplace/cartLabels.ts +128 -1
  15. package/templates/lib/orionplace/cartPreview.ts +15 -0
  16. package/templates/lib/orionplace/categoryLabels.ts +9 -1
  17. package/templates/lib/orionplace/contactLabels.ts +51 -1
  18. package/templates/lib/orionplace/directoryLabels.ts +66 -1
  19. package/templates/lib/orionplace/errorPageLabels.ts +15 -0
  20. package/templates/lib/orionplace/featureLabels.ts +136 -1
  21. package/templates/lib/orionplace/featuredLabels.ts +10 -0
  22. package/templates/lib/orionplace/footerLabels.ts +17 -1
  23. package/templates/lib/orionplace/headerLabels.ts +30 -0
  24. package/templates/lib/orionplace/homeLabels.ts +22 -0
  25. package/templates/lib/orionplace/manufacturerIndex.ts +15 -0
  26. package/templates/lib/orionplace/orderLabels.ts +148 -1
  27. package/templates/lib/orionplace/orderPresentation.ts +45 -2
  28. package/templates/lib/orionplace/privacyLabels.ts +77 -2
  29. package/templates/lib/orionplace/productActionLabels.ts +48 -0
  30. package/templates/lib/orionplace/productLabels.ts +37 -0
  31. package/templates/lib/orionplace/profileLabels.ts +75 -1
  32. package/templates/lib/orionplace/promoLabels.ts +37 -1
  33. package/templates/lib/orionplace/reviewLabels.ts +81 -1
  34. package/templates/lib/orionplace/sessionLabels.ts +12 -1
  35. package/templates/lib/orionplace/subscriptionLabels.ts +34 -1
  36. package/templates/lib/orionplace/subscriptionManageLabels.ts +118 -2
  37. package/templates/lib/orionplace/tariffLabels.ts +54 -3
  38. package/templates/lib/orionplace/tariffVariables.ts +38 -0
  39. package/templates/lib/orionplace/ticketLabels.ts +94 -1
@@ -128,6 +128,71 @@ const ru: typeof en = {
128
128
  next: 'Следующая фотография',
129
129
  };
130
130
 
131
+ const es: typeof en = {
132
+ catalog: 'Catálogo',
133
+ sellers: 'Vendedores',
134
+ stores: 'Tiendas',
135
+ manufacturers: 'Fabricantes',
136
+ products: 'Ver los productos',
137
+ details: 'Detalles',
138
+ searchSeller: 'Nombre del vendedor',
139
+ searchStore: 'Tienda, ciudad o dirección',
140
+ searchManufacturer: 'Nombre del fabricante',
141
+ letter: 'Nombres que empiezan por',
142
+ rating: 'Valoración del vendedor',
143
+ reviews: 'Reseñas',
144
+ since: 'Vende desde',
145
+ hours: 'Horario',
146
+ phone: 'Teléfono',
147
+ weekdays: [
148
+ 'Lunes',
149
+ 'Martes',
150
+ 'Miércoles',
151
+ 'Jueves',
152
+ 'Viernes',
153
+ 'Sábado',
154
+ 'Domingo',
155
+ ],
156
+ addressDetails: 'Detalles de la dirección',
157
+ entrance: 'Portal',
158
+ intercom: 'Portero automático',
159
+ floor: 'Planta',
160
+ office: 'Oficina',
161
+ categories: 'Categorías',
162
+ refresh: 'Actualizar',
163
+ storesMap: 'Tiendas en el mapa',
164
+ noStores: 'No se han encontrado tiendas',
165
+ map: 'Mapa',
166
+ filters: 'Filtros',
167
+ clear: 'Borrar',
168
+ anyRating: 'Cualquier valoración',
169
+ andUp: 'o más',
170
+ sort: 'Ordenar',
171
+ ratingHigh: 'Mejor valoración primero',
172
+ ratingLow: 'Peor valoración primero',
173
+ results: 'Resultados',
174
+ productsCount: 'Productos',
175
+ outOf: 'de',
176
+ sellerProducts: 'Productos del vendedor',
177
+ allSellers: 'Todos los vendedores',
178
+ sellerMissing: 'Vendedor no encontrado',
179
+ sellerMissingHint: 'Puede que el vendedor haya dejado el marketplace.',
180
+ photos: 'Fotos',
181
+ noMatches: 'Ningún vendedor coincide con estos filtros',
182
+ sellerSections: 'Secciones de la página del vendedor',
183
+ productsTab: 'Productos',
184
+ sellerPhotos: 'Fotos del vendedor',
185
+ openPhoto: 'Abrir la foto',
186
+ more: 'Más',
187
+ less: 'Contraer',
188
+ showAllPhotos: 'Más fotos del vendedor',
189
+ showFewerPhotos: 'Contraer las fotos del vendedor',
190
+ close: 'Cerrar',
191
+ closePhoto: 'Cerrar el visor de fotos',
192
+ previous: 'Foto anterior',
193
+ next: 'Foto siguiente',
194
+ };
195
+
131
196
  export function directoryLabels(locale: string) {
132
- return locale.toLowerCase().startsWith('ru') ? ru : en;
197
+ return locale.toLowerCase().startsWith('ru') ? ru : locale.toLowerCase().startsWith('es') ? es : en;
133
198
  }
@@ -33,6 +33,21 @@ const labels = {
33
33
  retry: 'Повторить',
34
34
  details: 'Технические подробности',
35
35
  },
36
+ es: {
37
+ notFound: {
38
+ title: 'Página no encontrada',
39
+ text: 'Puede que la dirección esté mal escrita o que la página se haya movido o eliminado.',
40
+ },
41
+ error: {
42
+ title: 'Algo ha salido mal',
43
+ text: 'No se ha podido mostrar la página. Vuelve a intentarlo en un momento.',
44
+ },
45
+ code: 'Código de error',
46
+ home: 'Inicio',
47
+ catalog: 'Catálogo',
48
+ retry: 'Reintentar',
49
+ details: 'Detalles técnicos',
50
+ },
36
51
  };
37
52
 
38
53
  export function errorPageLabels(locale: string) {
@@ -266,6 +266,141 @@ const ru: typeof en = {
266
266
  },
267
267
  };
268
268
 
269
+ const es: typeof en = {
270
+ loading: 'Cargando…',
271
+ failed: 'No se ha podido completar la solicitud. Inténtalo de nuevo.',
272
+ retry: 'Reintentar',
273
+ refresh: 'Actualizar',
274
+ save: 'Guardar',
275
+ saved: 'Guardado',
276
+ cancel: 'Cancelar',
277
+ close: 'Cerrar',
278
+ delete: 'Eliminar',
279
+ edit: 'Editar',
280
+ add: 'Añadir',
281
+ back: 'Atrás',
282
+ next: 'Siguiente',
283
+ previous: 'Anterior',
284
+ page: 'Página',
285
+ empty: 'Todavía no hay nada aquí',
286
+ noMatches: 'Sin coincidencias',
287
+ account: 'Mi cuenta',
288
+ accountSignIn:
289
+ 'Inicia sesión para abrir tus pedidos, direcciones, monedero y las demás páginas de la cuenta.',
290
+ required: 'Obligatorio',
291
+ search: 'Buscar',
292
+ all: 'Todos',
293
+ continue: 'Continuar',
294
+ balance: 'Saldo',
295
+ navigation: {
296
+ profile: 'Perfil',
297
+ addresses: 'Direcciones',
298
+ orders: 'Pedidos',
299
+ tickets: 'Soporte',
300
+ wallet: 'Monedero',
301
+ subscriptions: 'Suscripciones',
302
+ wishlist: 'Favoritos',
303
+ promocodes: 'Mis códigos promocionales',
304
+ activity: 'Mi actividad',
305
+ },
306
+ logout: 'Cerrar sesión',
307
+ addresses: {
308
+ title: 'Mis direcciones',
309
+ description: 'Direcciones guardadas para la entrega.',
310
+ add: 'Añadir dirección',
311
+ edit: 'Editar dirección',
312
+ label: 'Nombre de la dirección',
313
+ country: 'País',
314
+ region: 'Región',
315
+ findRegion: 'Empieza a escribir una región',
316
+ city: 'Ciudad',
317
+ street: 'Calle',
318
+ house: 'Número',
319
+ postcode: 'Código postal',
320
+ line2: 'Línea de dirección adicional',
321
+ entrance: 'Portal',
322
+ intercom: 'Portero automático',
323
+ floor: 'Planta',
324
+ apartment: 'Piso',
325
+ details: 'Detalles adicionales',
326
+ default: 'Dirección de entrega predeterminada',
327
+ makeDefault: 'Predeterminada',
328
+ makeDefaultHint: 'Usar para la entrega por defecto',
329
+ clearDefault: 'Desmarcar',
330
+ clearDefaultHint: 'Quitar la selección predeterminada',
331
+ empty: 'Añade una dirección de entrega para empezar.',
332
+ chooseCountry: 'Elige un país',
333
+ locate: 'Localizar',
334
+ locationFailed: 'No se ha podido determinar la dirección. Introdúcela a mano.',
335
+ regionFailed: 'No se han podido cargar las regiones. Inténtalo de nuevo.',
336
+ hintsFailed:
337
+ 'Las sugerencias no están disponibles. Puedes seguir introduciendo la dirección a mano.',
338
+ deleteQuestion: '¿Eliminar esta dirección guardada?',
339
+ actions: 'Acciones de la dirección',
340
+ suggestionsLoading: 'Cargando sugerencias…',
341
+ savedTitle: 'Dirección guardada',
342
+ savedAsSent: 'Así se guarda la dirección en tu cuenta.',
343
+ savedRefined:
344
+ 'El servicio de direcciones ha precisado la dirección. Revisa los campos marcados y edítalos si hace falta.',
345
+ refined: 'precisado',
346
+ done: 'Listo',
347
+ defaultKept:
348
+ 'Esta es tu dirección de entrega predeterminada. Para quitar la marca, usa el menú de la dirección.',
349
+ noShipping: 'No hay envío a este país',
350
+ noShippingDefault:
351
+ 'No hay envío a este país, así que esta dirección no puede ser la predeterminada.',
352
+ },
353
+ wallet: {
354
+ title: 'Monedero y pagos',
355
+ description: 'Recarga tu saldo y sigue tu historial de pagos.',
356
+ topUp: 'Recargar saldo',
357
+ topUpAction: 'Depósito',
358
+ amount: 'Importe',
359
+ payment: 'Método de pago',
360
+ currency: 'Moneda',
361
+ create: 'Continuar',
362
+ history: 'Historial de pagos',
363
+ wallet: 'Monedero',
364
+ orders: 'Pedidos',
365
+ paid_subs: 'Suscripciones',
366
+ empty: 'Todavía no hay pagos en esta categoría.',
367
+ unavailable: 'No hay métodos de pago disponibles.',
368
+ pay: 'Pagar',
369
+ cancelInvoice: 'Cancelar',
370
+ cancelQuestion: '¿Cancelar esta factura sin pagar?',
371
+ refunds: 'Reembolsos',
372
+ refundToBalance: 'Devuelto al saldo',
373
+ refundToMethod: 'Devuelto al método de pago',
374
+ invoice: 'Factura',
375
+ paymentTitle: 'Pago',
376
+ check: 'Justificante',
377
+ transactionId: 'ID de transacción del pago',
378
+ comment: 'Comentario',
379
+ relatedOrder: 'Pedido',
380
+ relatedSubscription: 'Suscripción',
381
+ openOrder: 'Abrir el pedido',
382
+ openSubscription: 'Abrir mis suscripciones',
383
+ purpose: {
384
+ topUp: 'Recarga de saldo',
385
+ deduction: 'Descontado del saldo',
386
+ orderPayment: 'Pago de pedido',
387
+ subscriptionPayment: 'Pago de suscripción',
388
+ bonus: 'Abonado en el saldo',
389
+ refund: 'Reembolso',
390
+ },
391
+ // Invoice states by their number: the backend sends the state name
392
+ // in English only.
393
+ statuses: {
394
+ '-4': 'Cancelado',
395
+ '-3': 'Caducado',
396
+ '-2': 'Bloqueado',
397
+ '-1': 'Fallido',
398
+ '0': 'Creado',
399
+ '1': 'Completado',
400
+ } as Record<string, string>,
401
+ },
402
+ };
403
+
269
404
  export function featureLabels(locale: string) {
270
- return locale.toLowerCase().startsWith('ru') ? ru : en;
405
+ return locale.toLowerCase().startsWith('ru') ? ru : locale.toLowerCase().startsWith('es') ? es : en;
271
406
  }
@@ -21,6 +21,16 @@ const labels = {
21
21
  'Рекомендации подбираются по категориям, которые вы искали.',
22
22
  home: 'Главная',
23
23
  },
24
+ es: {
25
+ title: 'Destacados',
26
+ description: 'Productos de las categorías que has buscado.',
27
+ empty:
28
+ 'Busca productos: las recomendaciones salen de las categorías que buscas.',
29
+ guestTitle: 'Inicia sesión para ver recomendaciones',
30
+ guestDescription:
31
+ 'Las recomendaciones se eligen entre las categorías que has buscado.',
32
+ home: 'Inicio',
33
+ },
24
34
  };
25
35
 
26
36
  export function featuredLabels(locale: string) {
@@ -17,7 +17,23 @@ export function footerLabels(locale: string) {
17
17
  new: 'Новинки',
18
18
  featured: 'Рекомендуем',
19
19
  }
20
- : {
20
+ : locale.toLowerCase().startsWith('es') ? {
21
+ catalog: 'Catálogo',
22
+ sellers: 'Vendedores',
23
+ stores: 'Tiendas',
24
+ manufacturers: 'Fabricantes',
25
+ sections: 'Descubre',
26
+ contact: 'Contacto',
27
+ privacy: 'Política de privacidad',
28
+ home: 'Inicio',
29
+ profile: 'Mi cuenta',
30
+ journal: 'Blog',
31
+ rights: 'Todos los derechos reservados.',
32
+ products: 'Productos',
33
+ discounts: 'Descuentos',
34
+ new: 'Novedades',
35
+ featured: 'Destacados',
36
+ } : {
21
37
  catalog: 'Catalog',
22
38
  sellers: 'Sellers',
23
39
  stores: 'Stores',
@@ -61,6 +61,36 @@ const labels = {
61
61
  wishlistSelection: 'Запрошено избранное',
62
62
  cartSelection: 'Запрошена корзина',
63
63
  },
64
+ es: {
65
+ home: 'Inicio del marketplace',
66
+ language: 'Idioma',
67
+ currency: 'Moneda',
68
+ search: 'Buscar en el marketplace',
69
+ find: 'Buscar',
70
+ catalog: 'Catálogo',
71
+ manufacturers: 'Fabricantes',
72
+ journal: 'Blog',
73
+ close: 'Cerrar el catálogo',
74
+ back: 'Atrás',
75
+ viewCategory: 'Ver',
76
+ highlights: 'Categorías destacadas',
77
+ empty: 'No hay categorías disponibles',
78
+ emptyProducts: 'No hay productos representativos',
79
+ saved: 'Favoritos',
80
+ cart: 'Carrito',
81
+ variantLoading: 'Cargando la variante seleccionada…',
82
+ variantFailed: 'No se ha podido cargar esta variante. Vuelve a seleccionarla para reintentar.',
83
+ searchSelection: 'Búsqueda solicitada',
84
+ categorySelection: 'Categoría seleccionada',
85
+ productSelection: 'Producto seleccionado',
86
+ sellerSelection: 'Vendedor seleccionado',
87
+ signInSelection: 'Inicio de sesión solicitado',
88
+ signOutSelection: 'Cierre de sesión solicitado',
89
+ profileSelection: 'Perfil solicitado',
90
+ walletSelection: 'Monedero solicitado',
91
+ wishlistSelection: 'Favoritos solicitados',
92
+ cartSelection: 'Carrito solicitado',
93
+ },
64
94
  };
65
95
 
66
96
  export function headerLabels(locale: string) {
@@ -45,6 +45,28 @@ const labels = {
45
45
  eventSelected: 'Выбрано событие',
46
46
  bannerSelected: 'Выбран баннер',
47
47
  },
48
+ es: {
49
+ categories: 'Comprar por categoría',
50
+ products: 'Productos',
51
+ discounts: 'Descuentos',
52
+ new: 'Novedades',
53
+ newFailed: 'No se han podido cargar las novedades.',
54
+ featured: 'Hallazgos destacados',
55
+ events: 'Eventos y ofertas',
56
+ banner: 'Lo mejor de la tienda',
57
+ previous: 'Diapositiva anterior',
58
+ previousProducts: 'Productos anteriores',
59
+ nextProducts: 'Productos siguientes',
60
+ next: 'Diapositiva siguiente',
61
+ viewAll: 'Más',
62
+ loading: 'Cargando la tienda…',
63
+ failed: 'No se ha podido cargar la tienda.',
64
+ retry: 'Reintentar',
65
+ category: 'Categoría',
66
+ event: 'Evento',
67
+ eventSelected: 'Evento seleccionado',
68
+ bannerSelected: 'Banner seleccionado',
69
+ },
48
70
  };
49
71
 
50
72
  export function homeLabels(locale: string) {
@@ -76,6 +76,21 @@ export function manufacturerIndexLabels(locale: string) {
76
76
  };
77
77
  }
78
78
 
79
+ if (locale.toLowerCase().startsWith('es')) {
80
+ return {
81
+ title: 'Fabricantes',
82
+ total: 'Total de fabricantes',
83
+ alphabet: 'Alfabeto de fabricantes',
84
+ logos: 'Logotipos de fabricantes',
85
+ load: 'Cargar',
86
+ loading: 'Cargando fabricantes…',
87
+ empty: 'No se han encontrado fabricantes',
88
+ emptyAlphabet: 'No hay fabricantes en este alfabeto',
89
+ retry: 'Reintentar',
90
+ allOn: 'Todos los que empiezan por',
91
+ all: 'Todos',
92
+ };
93
+ }
79
94
  return {
80
95
  title: 'Manufacturers',
81
96
  total: 'Total manufacturers',
@@ -284,6 +284,150 @@ const ru: typeof en = {
284
284
  },
285
285
  };
286
286
 
287
+ const es: typeof en = {
288
+ title: 'Mis pedidos',
289
+ allOrders: 'Todos los pedidos',
290
+ order: 'Pedido',
291
+ placed: 'Realizado',
292
+ empty: 'No hay pedidos en este grupo',
293
+ emptyHint: 'Revisa las otras pestañas o explora el catálogo.',
294
+ catalog: 'Ir al catálogo',
295
+ loading: 'Cargando pedidos',
296
+ tabs: 'Grupos de pedidos',
297
+ active: 'Activos',
298
+ canceled: 'Cancelado',
299
+ finished: 'Completado',
300
+ refund: 'Devoluciones',
301
+ details: 'Detalles',
302
+ status: 'Estado',
303
+ statusOrder: 'Estado del pedido',
304
+ statusPayment: 'Estado del pago',
305
+ items: 'Artículos',
306
+ delivery: 'Envío',
307
+ payment: 'Pago',
308
+ summary: 'Resumen',
309
+ actions: 'Acciones',
310
+ total: 'Total',
311
+ paid: 'Pagado',
312
+ left: 'Importe pendiente',
313
+ subtotal: 'Artículos',
314
+ discount: 'Descuento',
315
+ promo: 'Código promocional',
316
+ deliveryDiscount: 'Descuento en el envío',
317
+ shippingCost: 'Envío',
318
+ refunded: 'Reembolsado',
319
+ calculating: 'Calculando',
320
+ pay: 'Pagar',
321
+ payHint: 'Pagar o cambiar el método de pago',
322
+ method: 'Método',
323
+ paymentMethod: 'Método de pago',
324
+ choosePayment: 'Elige un método de pago',
325
+ unavailable: 'No hay métodos de pago disponibles.',
326
+ paymentTime: 'Tiempo para pagar',
327
+ minutes: 'min',
328
+ cancel: 'Cancelar',
329
+ cancelHint: 'Cancelar el pedido',
330
+ cancelQuestion: '¿Cancelar este pedido?',
331
+ repeat: 'Repetir pedido',
332
+ repeatHint: 'Repetir pedido: añadir al carrito los artículos de este pedido',
333
+ repeatQuestion:
334
+ '¿Sustituir el carrito actual por los artículos disponibles de este pedido?',
335
+ repeated: 'Los artículos se han añadido a tu carrito.',
336
+ openCart: 'Abrir el carrito',
337
+ shipment: 'Envío parcial',
338
+ of: 'de',
339
+ shipments: 'Envíos',
340
+ recipient: 'Destinatario',
341
+ contact: 'Contacto',
342
+ phone: 'Teléfono',
343
+ email: 'Correo electrónico',
344
+ carrier: 'Transportista',
345
+ apartment: 'piso',
346
+ address: 'Dirección',
347
+ pickupPoint: 'Punto de recogida',
348
+ shipsFrom: 'Se envía desde',
349
+ digitalDelivery: 'Entrega digital',
350
+ estimate: 'Previsto',
351
+ sentDate: 'Enviado',
352
+ deliveredDate: 'Entregado',
353
+ returnedByCarrierDate: 'Devuelto por el transportista',
354
+ tracking: 'Número de seguimiento',
355
+ trackingStatus: 'Estado del transportista',
356
+ quantity: 'Cantidad',
357
+ price: 'Precio',
358
+ lineTotal: 'Total de la línea',
359
+ options: 'Opciones del artículo',
360
+ optionsTotal: 'Opciones',
361
+ itemTotal: 'Total del artículo',
362
+ download: 'Descargar',
363
+ digital: 'Contenido comprado',
364
+ digitalReturned: 'Devuelto',
365
+ attachment: 'Tu archivo adjunto',
366
+ support: 'Solicitar la devolución de este artículo',
367
+ supportOption: 'Solicitar la devolución de esta opción',
368
+ supportDefect: 'Devolver este artículo por defecto',
369
+ supportOptionDefect: 'Devolver esta opción por defecto',
370
+ ticket: 'Abrir la conversación',
371
+ returnTitle: 'Devolución',
372
+ returnTrack: 'Número de seguimiento de la devolución',
373
+ returnAmount: 'Importe del reembolso',
374
+ returnCounts: {
375
+ awaiting: 'Para devolver',
376
+ received: 'Devueltos',
377
+ approved: 'Aprobados para reembolso',
378
+ defect: 'De ellos, defectuosos',
379
+ },
380
+ refundToPay: 'Reembolso aprobado',
381
+ estimated:
382
+ 'Se está calculando el coste del envío. Después podrás pagar.',
383
+ comment: 'Comentario del pedido',
384
+ refreshRequired: 'Actualiza los pedidos antes de hacer otro cambio.',
385
+ statuses: {
386
+ processing: 'En preparación',
387
+ shipped: 'Enviado',
388
+ partlyShipped: 'Enviado en parte',
389
+ delivered: 'Entregado',
390
+ partlyDelivered: 'Entregado en parte',
391
+ canceled: 'Cancelado',
392
+ refund: 'Devolución',
393
+ },
394
+ statusHints: {
395
+ processing: 'El pedido está aceptado y se está preparando para el envío.',
396
+ shipped: 'Todos los envíos están en camino.',
397
+ partlyShipped:
398
+ 'Algunos envíos están en camino; otros se están preparando.',
399
+ delivered: 'Todos los envíos se han entregado.',
400
+ partlyDelivered:
401
+ 'Algunos envíos se han entregado; otros están en camino.',
402
+ canceled: 'El pedido se ha cancelado.',
403
+ refund: 'Se ha solicitado la devolución de artículos de este pedido.',
404
+ },
405
+ payments: {
406
+ notPaid: 'Sin pagar',
407
+ partlyPaid: 'Pagado en parte',
408
+ onDelivery: 'Pago contra reembolso',
409
+ paid: 'Pagado',
410
+ paidAfterCancel: 'Pagado tras la cancelación',
411
+ },
412
+ steps: {
413
+ placed: 'Realizado',
414
+ shipped: 'Enviado',
415
+ delivered: 'Entregado',
416
+ },
417
+ stepStates: {
418
+ done: 'Listo',
419
+ current: 'Ahora',
420
+ todo: 'Siguiente',
421
+ },
422
+ shipmentStates: {
423
+ preparing: 'En preparación',
424
+ sent: 'En camino',
425
+ delivered: 'Entregado',
426
+ canceled: 'Cancelado',
427
+ returned: 'Devuelto por el transportista',
428
+ },
429
+ };
430
+
287
431
  function russianPlural(count: number, forms: [string, string, string]) {
288
432
  const tens = count % 100;
289
433
  const ones = count % 10;
@@ -303,9 +447,12 @@ export function orderItemCount(locale: string, count: number) {
303
447
  return `${count} ${russianPlural(count, ['товар', 'товара', 'товаров'])}`;
304
448
  }
305
449
 
450
+ if (locale.toLowerCase().startsWith('es')) {
451
+ return `${count} ${count === 1 ? 'artículo' : 'artículos'}`;
452
+ }
306
453
  return `${count} ${count === 1 ? 'item' : 'items'}`;
307
454
  }
308
455
 
309
456
  export function orderLabels(locale: string) {
310
- return locale.toLowerCase().startsWith('ru') ? ru : en;
457
+ return locale.toLowerCase().startsWith('ru') ? ru : locale.toLowerCase().startsWith('es') ? es : en;
311
458
  }
@@ -59,6 +59,8 @@ export interface OrderStep {
59
59
  current: boolean;
60
60
  count: number;
61
61
  total: number;
62
+ /** The date the step was reached ('' until then); see orderStepDate. */
63
+ date?: string;
62
64
  }
63
65
 
64
66
  export type OrderShipmentStateKey =
@@ -228,7 +230,39 @@ export function orderCanCancel(
228
230
  }
229
231
 
230
232
  // Canceled and returned orders have no delivery progress to show.
231
- export function orderSteps(order: OrderShipmentCounters): OrderStep[] {
233
+ // The date a step was reached: the order's own date for Placed; for Shipped
234
+ // and Delivered, once every shipment got there, the latest of their sent
235
+ // (or delivery) dates; '' while a shipment has not reached the step.
236
+ export function orderStepDate(
237
+ order: OrderShipmentCounters & Partial<Pick<IOrder, 'time_submited'>>,
238
+ key: OrderStepKey,
239
+ ): string {
240
+ if (key === 'placed') {
241
+ return order.time_submited?.date ?? '';
242
+ }
243
+
244
+ const shipments = order.delivery_froms ?? [];
245
+ const reached = shipments.map((shipment) =>
246
+ key === 'shipped'
247
+ ? shipment.dates?.sent || shipment.dates?.delivery_date_real
248
+ : shipment.dates?.delivery_date_real,
249
+ );
250
+
251
+ if (!reached.length || reached.some((date) => !date?.date)) {
252
+ return '';
253
+ }
254
+
255
+ // The latest is the one the fewest minutes ago (any date format).
256
+ const latest = reached.reduce((best, date) =>
257
+ Number(date?.minutes_ago ?? 0) < Number(best?.minutes_ago ?? 0) ? date : best,
258
+ );
259
+
260
+ return latest?.date ?? '';
261
+ }
262
+
263
+ export function orderSteps(
264
+ order: OrderShipmentCounters & Partial<Pick<IOrder, 'time_submited'>>,
265
+ ): OrderStep[] {
232
266
  const { total, sent, delivered } = orderShipmentProgress(order);
233
267
 
234
268
  if (
@@ -239,13 +273,21 @@ export function orderSteps(order: OrderShipmentCounters): OrderStep[] {
239
273
  }
240
274
 
241
275
  const steps = [
242
- { key: 'placed', state: 'done', current: false, count: 1, total: 1 },
276
+ {
277
+ key: 'placed',
278
+ state: 'done',
279
+ current: false,
280
+ count: 1,
281
+ total: 1,
282
+ date: orderStepDate(order, 'placed'),
283
+ },
243
284
  {
244
285
  key: 'shipped',
245
286
  state: stepState(sent, total),
246
287
  current: false,
247
288
  count: sent,
248
289
  total,
290
+ date: orderStepDate(order, 'shipped'),
249
291
  },
250
292
  {
251
293
  key: 'delivered',
@@ -253,6 +295,7 @@ export function orderSteps(order: OrderShipmentCounters): OrderStep[] {
253
295
  current: false,
254
296
  count: delivered,
255
297
  total,
298
+ date: orderStepDate(order, 'delivered'),
256
299
  },
257
300
  ] satisfies OrderStep[];
258
301