orionplace-react 0.7.6 → 0.7.7

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 (36) 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/search/MainSearch.tsx +2 -2
  5. package/templates/components/orionplace/shared/OrionplaceBreadcrumbs.tsx +1 -1
  6. package/templates/components/orionplace/shared/StorefrontPagination.tsx +1 -1
  7. package/templates/components/orionplace/storefront/StorefrontFooter.tsx +1 -1
  8. package/templates/lib/orionplace/accountLabels.ts +7 -0
  9. package/templates/lib/orionplace/activityLabels.ts +32 -1
  10. package/templates/lib/orionplace/blogLabels.ts +47 -1
  11. package/templates/lib/orionplace/browseLabels.ts +48 -1
  12. package/templates/lib/orionplace/cartLabels.ts +128 -1
  13. package/templates/lib/orionplace/cartPreview.ts +15 -0
  14. package/templates/lib/orionplace/categoryLabels.ts +9 -1
  15. package/templates/lib/orionplace/contactLabels.ts +51 -1
  16. package/templates/lib/orionplace/directoryLabels.ts +66 -1
  17. package/templates/lib/orionplace/errorPageLabels.ts +15 -0
  18. package/templates/lib/orionplace/featureLabels.ts +136 -1
  19. package/templates/lib/orionplace/featuredLabels.ts +10 -0
  20. package/templates/lib/orionplace/footerLabels.ts +17 -1
  21. package/templates/lib/orionplace/headerLabels.ts +30 -0
  22. package/templates/lib/orionplace/homeLabels.ts +22 -0
  23. package/templates/lib/orionplace/manufacturerIndex.ts +15 -0
  24. package/templates/lib/orionplace/orderLabels.ts +148 -1
  25. package/templates/lib/orionplace/privacyLabels.ts +77 -2
  26. package/templates/lib/orionplace/productActionLabels.ts +27 -0
  27. package/templates/lib/orionplace/productLabels.ts +37 -0
  28. package/templates/lib/orionplace/profileLabels.ts +75 -1
  29. package/templates/lib/orionplace/promoLabels.ts +37 -1
  30. package/templates/lib/orionplace/reviewLabels.ts +81 -1
  31. package/templates/lib/orionplace/sessionLabels.ts +12 -1
  32. package/templates/lib/orionplace/subscriptionLabels.ts +34 -1
  33. package/templates/lib/orionplace/subscriptionManageLabels.ts +118 -2
  34. package/templates/lib/orionplace/tariffLabels.ts +54 -3
  35. package/templates/lib/orionplace/tariffVariables.ts +38 -0
  36. package/templates/lib/orionplace/ticketLabels.ts +94 -1
@@ -75,7 +75,81 @@ export function profileLabels(locale: string) {
75
75
  deleting: 'Удаляем…',
76
76
  deleted: 'Аккаунт удалён.',
77
77
  }
78
- : {
78
+ : locale.toLowerCase().startsWith('es') ? {
79
+ title: 'Perfil personal',
80
+ intro: 'Tus datos, preferencias de contacto y la seguridad de la cuenta.',
81
+ overview: 'Cuenta',
82
+ home: 'Inicio',
83
+ saved: 'Cambios guardados.',
84
+ loading: 'Cargando tu perfil…',
85
+ retry: 'Reintentar',
86
+ failed: 'No se ha podido completar la solicitud. Inténtalo de nuevo.',
87
+ details: 'Datos personales',
88
+ detailsHint: 'Tu nombre, el teléfono de acceso y la fecha de nacimiento.',
89
+ firstName: 'Nombre',
90
+ lastName: 'Apellidos',
91
+ phone: 'Número de teléfono',
92
+ phoneHint: 'Tu teléfono de acceso.',
93
+ phoneCountryHint: 'Tu teléfono de acceso. Su país, {country}, decide qué métodos de pago puedes usar.',
94
+ dob: 'Fecha de nacimiento',
95
+ save: 'Guardar',
96
+ pending: 'Guardando…',
97
+ emailTitle: 'Correo y notificaciones',
98
+ email: 'Dirección de correo',
99
+ emailHint:
100
+ 'Verifica tu dirección antes de recibir novedades de pedidos y notificaciones por correo.',
101
+ sendCode: 'Enviar',
102
+ sendCodeHint: 'Enviar código de verificación',
103
+ code: 'Código de verificación',
104
+ verify: 'Verificar',
105
+ changeEmail: 'Cambiar',
106
+ changeEmailHint: 'Cambiar la dirección de correo',
107
+ resend: 'Reenviar',
108
+ resendHint: 'Enviar un código nuevo',
109
+ notifications: 'Notificaciones por correo',
110
+ notificationsHint: 'Novedades de pedidos, soporte y suscripciones, avisos de disponibilidad y ofertas. Los códigos de acceso se envían siempre.',
111
+ notificationLocale: 'Idioma de los correos',
112
+ chooseLocale: 'Elige un idioma',
113
+ oldPassword: 'Contraseña actual',
114
+ newPassword: 'Nueva contraseña',
115
+ confirmPassword: 'Confirma la nueva contraseña',
116
+ passwordHint: 'Usa al menos 6 caracteres.',
117
+ mismatch: 'Las contraseñas no coinciden.',
118
+ changePassword: 'Cambiar la contraseña',
119
+ createPassword: 'Crear contraseña',
120
+ showPassword: 'Mostrar la contraseña',
121
+ hidePassword: 'Ocultar la contraseña',
122
+ avatar: 'Foto de perfil',
123
+ upload: 'Elegir una foto',
124
+ change: 'Cambiar la foto',
125
+ remove: 'Quitar la foto',
126
+ signIn: 'Inicia sesión en tu cuenta',
127
+ signInOrRegister: 'Inicia sesión o regístrate',
128
+ signUp: 'Crear una cuenta',
129
+ signInHint:
130
+ 'Introduce tu número de teléfono para continuar. Los clientes nuevos pueden crear una cuenta aquí.',
131
+ next: 'Continuar',
132
+ password: 'Contraseña',
133
+ back: 'Atrás',
134
+ otpHint: 'Introduce el código de verificación que has recibido.',
135
+ otpSms: 'Introduce el código de 4 dígitos del SMS.',
136
+ otpCall: 'Introduce los 4 últimos dígitos del número que te llama.',
137
+ otpEmail: 'Introduce el código del correo enviado a',
138
+ signingIn: 'Iniciando sesión…',
139
+ refreshFailed: 'Has iniciado sesión, pero no se han podido cargar los datos de la cuenta.',
140
+ cooldown: 'Pide otro código en',
141
+ phoneCooldown: 'Vuelve a intentarlo en',
142
+ seconds: 's',
143
+ deleteTitle: 'Eliminar la cuenta',
144
+ deleteHint:
145
+ 'Elimina tu nombre, número de teléfono, correo, foto, direcciones y carrito, y cierra tu sesión. Los pedidos y las reseñas se conservan sin tus datos.',
146
+ deleteBlocked:
147
+ 'No es posible mientras haya un pedido abierto, un reembolso sin pagar, dinero en tu saldo o una suscripción de pago activa.',
148
+ deleteConfirm: 'Entiendo que la cuenta no se puede recuperar',
149
+ deleteAction: 'Eliminar la cuenta',
150
+ deleting: 'Eliminando…',
151
+ deleted: 'Tu cuenta se ha eliminado.',
152
+ } : {
79
153
  title: 'Personal profile',
80
154
  intro: 'Your details, contact preferences and account security.',
81
155
  overview: 'Account',
@@ -70,6 +70,42 @@ const ru: typeof en = {
70
70
  backToPromocodes: 'Мои промокоды',
71
71
  };
72
72
 
73
+ const es: typeof en = {
74
+ conditions: 'Condiciones',
75
+ discount: 'Descuento',
76
+ freeShipping: 'Envío gratuito',
77
+ scope: 'Se aplica a',
78
+ scopeSellers: 'Vendedores',
79
+ scopeCategories: 'Categorías',
80
+ scopeProducts: 'Productos',
81
+ scopeEverything: 'Todos los productos de la tienda',
82
+ minimumOrderAmount: 'Pedido mínimo',
83
+ maximumDiscount: 'Descuento máximo',
84
+ firstOrder: 'Primera compra',
85
+ firstOrderOnly: 'Solo para la primera compra en la tienda',
86
+ stacking: 'Artículos con descuento',
87
+ stackingAllowed: 'El código también se aplica a ellos',
88
+ stackingBlocked: 'El código no se aplica a ellos',
89
+ period: 'Válido',
90
+ until: 'Hasta',
91
+ untilLower: 'hasta',
92
+ since: 'Desde',
93
+ noPeriod: 'Sin fecha de fin',
94
+ usage: 'Usos restantes',
95
+ ofTotal: 'de',
96
+ unlimited: 'Ilimitado',
97
+ separator: ', ',
98
+ crumbPromocodes: 'Códigos promocionales',
99
+ crumbProducts: 'Productos',
100
+ products: 'Productos a los que se aplica este código',
101
+ productsHint:
102
+ 'Estos productos encajan con la oferta. Un código sigue necesitando las condiciones de arriba.',
103
+ productsEmpty: 'Ahora mismo ningún producto encaja con esta oferta.',
104
+ productsMissing: 'Esta oferta ya no está vigente.',
105
+ openProducts: 'Mostrar los productos',
106
+ backToPromocodes: 'Mis códigos promocionales',
107
+ };
108
+
73
109
  export function promoLabels(locale: string) {
74
- return locale.toLowerCase().startsWith('ru') ? ru : en;
110
+ return locale.toLowerCase().startsWith('ru') ? ru : locale.toLowerCase().startsWith('es') ? es : en;
75
111
  }
@@ -156,8 +156,88 @@ const ru: typeof en = {
156
156
  unhelpfulHint: 'Отметить отзыв как бесполезный',
157
157
  repliesHint: 'Показать ответы',
158
158
  };
159
+
160
+ const es: typeof en = {
161
+ title: 'Reseñas de clientes',
162
+ mine: 'Mis reseñas',
163
+ all: 'Todos',
164
+ write: 'Escribir una reseña',
165
+ writeAction: 'Reseña',
166
+ writeHint: 'Reseña este producto',
167
+ reply: 'Responder',
168
+ replies: 'Respuestas',
169
+ text: 'Texto de la reseña',
170
+ rating: 'Valoración',
171
+ chooseRating: 'Elige una valoración',
172
+ ratingRequired: 'Valora el producto de 1 a 5 estrellas.',
173
+ textMinimum: 'Al menos {count} caracteres',
174
+ images: 'Fotos',
175
+ addImages: 'Añadir fotos',
176
+ photosOnly: 'Con fotos',
177
+ allPhotos: 'Fotos de clientes',
178
+ photosTab: 'Fotos',
179
+ mineTab: 'Mías',
180
+ image: 'Foto de la reseña',
181
+ openImage: 'Abrir la foto',
182
+ photoViewer: 'Fotos de reseñas',
183
+ productPhotos: 'Fotos del producto',
184
+ openProductPhoto: 'Abrir la foto a pantalla completa',
185
+ empty: 'Aún no hay reseñas.',
186
+ emptyImages: 'Aún no hay fotos de clientes.',
187
+ send: 'Enviar',
188
+ save: 'Guardar',
189
+ editing: 'Editar la reseña',
190
+ pending: 'Pendiente de publicación',
191
+ denied: 'No publicada',
192
+ liked: 'Útil',
193
+ disliked: 'No útil',
194
+ repliesTo: 'Responder a',
195
+ newest: 'Más recientes primero',
196
+ highest: 'Mejor valoración',
197
+ lowest: 'Peor valoración',
198
+ order: 'Ordenar reseñas',
199
+ tooMany: 'Una reseña puede tener hasta cinco fotos.',
200
+ cannotEdit: 'Esta reseña no se puede editar.',
201
+ imageRemove: 'Quitar la foto',
202
+ product: 'Producto',
203
+ notFound: 'Este producto no está disponible.',
204
+ description: 'Sobre este producto',
205
+ more: 'Más',
206
+ less: 'Menos',
207
+ gallery: 'Imágenes del producto',
208
+ previousImage: 'Imagen anterior',
209
+ zoomIn: 'Ver a tamaño completo',
210
+ zoomOut: 'Ajustar a la pantalla',
211
+ nextImage: 'Imagen siguiente',
212
+ thumbnailsBack: 'Ver miniaturas anteriores',
213
+ thumbnailsForward: 'Ver miniaturas siguientes',
214
+ characteristics: 'Características',
215
+ allCharacteristics: 'Todas las características',
216
+ manufacturer: 'Fabricante',
217
+ manufacturerHint: 'Abrir la página del fabricante',
218
+ weight: 'Peso',
219
+ dimensions: 'Dimensiones (L × A × A)',
220
+ type: 'Tipo',
221
+ digital: 'Producto digital',
222
+ returns: 'Devoluciones',
223
+ returnRegular: 'Sin defecto',
224
+ returnDefect: 'Con defecto',
225
+ within: 'en un plazo de',
226
+ days: ['día', 'días'],
227
+ seller: 'Vendedor',
228
+ sellerHint: 'Abrir la página del vendedor',
229
+ showReviews: 'Ir a las reseñas',
230
+ average: 'Valoración media',
231
+ ofFive: 'de 5',
232
+ ratingFilter: 'Filtrar reseñas por valoración',
233
+ allRatings: 'Ver reseñas con cualquier valoración',
234
+ stars: 'estrellas',
235
+ helpfulHint: 'Marcar esta reseña como útil',
236
+ unhelpfulHint: 'Marcar esta reseña como no útil',
237
+ repliesHint: 'Ver respuestas',
238
+ };
159
239
  export function reviewLabels(locale: string) {
160
- return locale.toLowerCase().startsWith('ru') ? ru : en;
240
+ return locale.toLowerCase().startsWith('ru') ? ru : locale.toLowerCase().startsWith('es') ? es : en;
161
241
  }
162
242
 
163
243
  // OrionMarketplace's domain setting feedback_text_min_length, sent as
@@ -12,7 +12,18 @@ export function sessionLabels(locale: string) {
12
12
  done: 'Вы вышли из аккаунта',
13
13
  home: 'Главная',
14
14
  }
15
- : {
15
+ : locale.toLowerCase().startsWith('es') ? {
16
+ title: 'Cerrando sesión',
17
+ pending: 'Terminando tu sesión…',
18
+ hint: 'Volverás a la página de inicio de la tienda.',
19
+ failed: 'No se ha podido cerrar la sesión',
20
+ retryHint: 'Inténtalo de nuevo. El cierre de sesión lo confirma el servidor.',
21
+ refreshFailed:
22
+ 'Tu sesión ha terminado. No se ha podido recargar la tienda.',
23
+ retry: 'Reintentar',
24
+ done: 'Has cerrado la sesión',
25
+ home: 'Inicio',
26
+ } : {
16
27
  title: 'Signing out',
17
28
  pending: 'Ending your session…',
18
29
  hint: 'You will return to the storefront home page.',
@@ -62,6 +62,39 @@ const ru: typeof en = {
62
62
  allPlansHint: 'Показать все тарифы',
63
63
  emptyIds: 'Тарифы из этой ссылки недоступны.',
64
64
  };
65
+
66
+ const es: typeof en = {
67
+ offers: 'Planes de suscripción',
68
+ search: 'Buscar',
69
+ mine: 'Mis suscripciones',
70
+ emptyOffers: 'Ningún plan coincide con esta búsqueda.',
71
+ empty: 'Todavía no tienes suscripciones.',
72
+ choose: 'Ver los planes',
73
+ subscription: 'Suscripción',
74
+ created: 'Inicio',
75
+ until: 'Activa hasta',
76
+ renewal: 'Renovación automática',
77
+ disabled: 'Desactivada',
78
+ days: 'días',
79
+ stop: 'Desactivar',
80
+ stopHint: 'Desactivar la renovación automática',
81
+ stopQuestion:
82
+ '¿Desactivar la renovación automática? El periodo que ya has pagado seguirá disponible.',
83
+ confirmed: 'Suscripción comprada. Tu cuenta se ha actualizado.',
84
+ refreshRequired:
85
+ 'La acción se ha completado. Actualiza los datos de la cuenta para ver el resultado.',
86
+ intro:
87
+ 'Elige un plan y un periodo de suscripción. Los periodos de pago se cobran del saldo de la cuenta.',
88
+ noOffers: 'Todavía no hay planes de suscripción disponibles.',
89
+ reset: 'Restablecer',
90
+ support: 'Soporte de suscripciones',
91
+ wallet: 'Recargar saldo',
92
+ searchHint: 'Buscar por nombre del plan',
93
+ filtered: 'Solo se muestran los planes del enlace abierto.',
94
+ allPlans: 'Todos',
95
+ allPlansHint: 'Ver todos los planes',
96
+ emptyIds: 'Los planes de este enlace no están disponibles.',
97
+ };
65
98
  export function subscriptionLabels(locale: string) {
66
- return locale.toLowerCase().startsWith('ru') ? ru : en;
99
+ return locale.toLowerCase().startsWith('ru') ? ru : locale.toLowerCase().startsWith('es') ? es : en;
67
100
  }
@@ -280,14 +280,130 @@ const ru: typeof en = {
280
280
  usageOf: '{used} из {limit}',
281
281
  actions: 'Действия с подпиской',
282
282
  };
283
+
284
+ const es: typeof en = {
285
+ statusActive: 'Activos',
286
+ statusExpired: 'Terminada',
287
+ statusPending: 'Configurándose',
288
+ statusPendingHint:
289
+ 'El servicio se está preparando y confirma la suscripción por sí mismo.',
290
+ manage: 'Gestionar la suscripción',
291
+ extend: 'Prolongar ahora',
292
+ extendHint: 'Pagar otro periodo con el saldo de la cuenta',
293
+ renewalSettings: 'Renovación automática',
294
+ renewalHint: 'Elige el periodo que se paga automáticamente, o desactívalo',
295
+ changePlan: 'Cambiar de plan',
296
+ changePlanHint: 'Pasar esta suscripción a otro plan',
297
+ close: 'Cerrar',
298
+ cancel: 'Cancelar',
299
+ period: 'Periodo',
300
+ promo: 'Código promocional',
301
+ promoHint: 'Opcional. Un código promocional se aplica a un periodo de pago.',
302
+ balance: 'Saldo de la cuenta',
303
+ planPrice: 'Plan para este periodo',
304
+ optionPrice: 'Opción del servicio',
305
+ insufficient:
306
+ 'El saldo es inferior a este periodo. Recarga el saldo o elige otro periodo.',
307
+ topUp: 'Depósito',
308
+ extendTitle: 'Prolongar la suscripción',
309
+ extendSummary:
310
+ 'El periodo elegido se cobra del saldo de la cuenta en el acto y se suma a la suscripción.',
311
+ extendAfter:
312
+ 'Se suma {period} a la suscripción, y el importe se cobra ahora del saldo de la cuenta.',
313
+ extendSubmit: 'Pagar',
314
+ extendPending: 'Pagando…',
315
+ extendConfirm: 'Confirmar',
316
+ renewalTitle: 'Renovación automática',
317
+ renewalCurrentOn: 'Ahora: cada {days} por {price}.',
318
+ renewalCurrentOff: 'Ahora: la renovación automática está desactivada.',
319
+ renewalOff: 'Desactivar la renovación automática',
320
+ renewalOffHint: 'No se cobra nada; el periodo pagado sigue disponible.',
321
+ renewalEffectOff:
322
+ 'La renovación automática se detiene. La suscripción sigue disponible hasta el final del periodo pagado y no se vuelve a cobrar del saldo.',
323
+ renewalEffectOn:
324
+ 'La renovación por {days} cuesta {price} por el plan, más el cargo de la opción si la hay. Al terminar el periodo pagado, la renovación necesita saldo suficiente para el total. Si el periodo ya ha terminado, empieza de inmediato cuando el saldo alcanza. Si no, solo se guarda el ajuste.',
325
+ renewalSubmit: 'Guardar',
326
+ renewalPending: 'Guardando…',
327
+ renewalNoChange: 'Este es el ajuste actual.',
328
+ changeOption: 'Cambiar la opción del servicio',
329
+ changeOptionHint: 'Pasar esta suscripción a otra opción del servicio',
330
+ changePlanTitle: 'Cambiar el plan',
331
+ changeOptionTitle: 'Cambiar la opción del servicio',
332
+ changePlanSummary:
333
+ 'Los días no usados del periodo actual se reembolsan en el saldo de la cuenta, y el periodo seleccionado del nuevo plan se cobra completo.',
334
+ changeOptionSummary:
335
+ 'Los días no usados del periodo actual se reembolsan en el saldo de la cuenta, y el periodo seleccionado con la nueva opción del servicio se cobra completo.',
336
+ changePlanField: 'Nuevo plan',
337
+ changeOptionField: 'Opción del servicio',
338
+ changeCurrentPlan: 'Ahora: {plan}.',
339
+ changeCurrentOption: 'Ahora: {option}.',
340
+ changeNoOption: 'Sin opción del servicio',
341
+ changeRefund: 'Reembolso por los días no usados',
342
+ changeRefundHint:
343
+ 'Primero se abona el reembolso en el saldo de la cuenta y después se cobra el nuevo periodo, así que un cambio puede ser posible aunque ese mismo periodo no se pudiera comprar por separado.',
344
+ changeRefundUnknown:
345
+ 'El backend de la tienda calcula este importe cuando se envía el cambio.',
346
+ changeAvailable: 'Disponible para este cambio',
347
+ changeTotal: 'Se cobra por el nuevo periodo',
348
+ changeAfterPlan:
349
+ 'La suscripción pasa ahora a {plan} por {period}. Los días no usados se reembolsan en el saldo de la cuenta y se cobran {price} por el nuevo periodo.',
350
+ changeAfterOption:
351
+ 'La suscripción pasa ahora a {option} por {period}. Los días no usados se reembolsan en el saldo de la cuenta y se cobran {price} por el nuevo periodo.',
352
+ changeAfterPlanRefund:
353
+ 'La suscripción pasa ahora a {plan} por {period}. Se reembolsan {refund} en el saldo de la cuenta por los días no usados y se cobran {price} por el nuevo periodo.',
354
+ changeAfterOptionRefund:
355
+ 'La suscripción pasa ahora a {option} por {period}. Se reembolsan {refund} en el saldo de la cuenta por los días no usados y se cobran {price} por el nuevo periodo.',
356
+ changeConfirm: 'Confirmar',
357
+ changeSubmit: 'Pagar',
358
+ changePending: 'Cambiando…',
359
+ changeNoPlans: 'No hay otro plan al que pasar esta suscripción.',
360
+ changeNoOptions: 'Este plan no tiene ninguna opción del servicio que elegir.',
361
+ changeNoPeriods: 'Este plan no tiene ningún periodo con el que se pueda comprar un cambio.',
362
+ changeInsufficient:
363
+ 'El saldo es inferior al nuevo periodo. Primero se suma al saldo el reembolso por los días no usados, así que el cambio aún puede salir bien; recarga el saldo si la tienda lo rechaza.',
364
+ changeShort:
365
+ 'El saldo y el reembolso juntos son inferiores al nuevo periodo. Recarga el saldo o elige un periodo más corto.',
366
+ cancelSubscription: 'Cancelar la suscripción',
367
+ cancelHint: 'Detener la renovación automática y conservar el periodo pagado',
368
+ cancelTitle: 'Cancelar la suscripción',
369
+ cancelSummary:
370
+ 'La renovación automática se detiene y no se vuelve a cobrar nada. La suscripción sigue disponible hasta el {date} y no se reembolsa dinero.',
371
+ cancelSummaryNoDate:
372
+ 'La renovación automática se detiene y no se vuelve a cobrar nada. La suscripción sigue disponible hasta el final del periodo pagado y no se reembolsa dinero.',
373
+ cancelResume:
374
+ 'Elegir de nuevo un periodo de renovación automática reanuda la renovación y quita el estado de cancelada.',
375
+ cancelSubmit: 'Cancelar aviso',
376
+ cancelPending: 'Cancelando…',
377
+ cancelKeep: 'Conservar',
378
+ cancelled: 'Cancelada',
379
+ cancelledOn: 'Cancelada el {date}',
380
+ cancelledState:
381
+ 'La renovación automática está detenida. La suscripción sigue disponible hasta el {date}. Elegir un periodo de renovación automática la reanuda.',
382
+ cancelledStateNoDate:
383
+ 'La renovación automática está detenida. La suscripción sigue disponible hasta el final del periodo pagado. Elegir un periodo de renovación automática la reanuda.',
384
+ remoteTitle: 'Servicio de suscripción',
385
+ remoteId: 'ID de la suscripción en el servicio',
386
+ remoteSync: 'Última confirmación del servicio',
387
+ remoteSyncPending: 'Esperando a que el servicio confirme el último cambio',
388
+ remoteHost: 'Host',
389
+ planTitle: 'Plan',
390
+ planIncludes: 'Incluido en el plan',
391
+ planNotIncluded: 'no incluido',
392
+ usageTitle: 'Uso',
393
+ usageOf: '{used} de {limit}',
394
+ actions: 'Acciones de la suscripción',
395
+ };
283
396
  export function subscriptionManageLabels(locale: string) {
284
- return locale.toLowerCase().startsWith('ru') ? ru : en;
397
+ return locale.toLowerCase().startsWith('ru') ? ru : locale.toLowerCase().startsWith('es') ? es : en;
285
398
  }
286
399
 
287
400
  const russianDays = ['день', 'дня', 'дней'];
288
401
 
289
- /** A period length with its noun: `30 days`, `30 дней`, `1 день`. */
402
+ /** A period length with its noun: `30 days`, `30 días`, `30 дней`, `1 день`. */
290
403
  export function subscriptionDays(days: number, locale: string) {
404
+ if (locale.toLowerCase().startsWith('es')) {
405
+ return `${days} ${days === 1 ? 'día' : 'días'}`;
406
+ }
291
407
  if (!locale.toLowerCase().startsWith('ru')) {
292
408
  return `${days} ${days === 1 ? 'day' : 'days'}`;
293
409
  }
@@ -97,11 +97,60 @@ const labels = {
97
97
  unavailableMedia: 'У тарифа нет изображений или видео.',
98
98
  notFound: 'Этот тариф недоступен.',
99
99
  },
100
+ es: {
101
+ trial: 'Prueba',
102
+ free: 'Gratis',
103
+ periods: 'Periodo de suscripción',
104
+ noPeriods: 'No hay periodos de suscripción disponibles.',
105
+ adminOnly:
106
+ 'Este plan lo asigna el administrador de la tienda. No se puede contratar en línea.',
107
+ closed: 'Las nuevas suscripciones a este plan están cerradas.',
108
+ trialUsed: 'Ya has usado la prueba de esta suscripción.',
109
+ subscribe: 'Suscribirse',
110
+ tryTrial: 'Probar',
111
+ perPeriod: 'por {days}',
112
+ trialBadge: 'Prueba gratuita · {days}',
113
+ subscribeAria: 'Suscribirse a {name} por {days}',
114
+ trialAria: 'Probar {name} gratis durante {days}',
115
+ features: 'Incluido en el plan',
116
+ notIncluded: 'no incluido',
117
+ options: 'Opciones',
118
+ details: 'Detalles',
119
+ title: 'Detalles de la suscripción',
120
+ option: 'Opción adicional',
121
+ noOption: 'Sin opción adicional',
122
+ promo: 'Código promocional',
123
+ base: 'Plan',
124
+ extra: 'Opción',
125
+ total: 'Total',
126
+ beforePromo: 'Total antes del código promocional',
127
+ payment:
128
+ 'Las suscripciones de pago se cobran del saldo de tu cuenta. El importe final incluye cualquier descuento promocional aplicable.',
129
+ trialInfo: 'La prueba está disponible una vez por suscripción para tu cuenta.',
130
+ wallet: 'Recargar saldo',
131
+ confirm: 'Suscribirse',
132
+ confirmTrial: 'Empezar',
133
+ pending: 'Enviando…',
134
+ complete: 'Suscripción activada',
135
+ mine: 'Mis suscripciones',
136
+ close: 'Cerrar',
137
+ invalid: 'Este periodo u opción ya no está disponible.',
138
+ plans: 'Planes de suscripción',
139
+ gallery: 'Imágenes y vídeos del plan',
140
+ previousMedia: 'Anterior',
141
+ nextMedia: 'Siguiente',
142
+ image: 'Imagen del plan',
143
+ video: 'Vídeo del plan',
144
+ about: 'Sobre este plan',
145
+ unavailableMedia: 'Este plan no tiene imágenes ni vídeos.',
146
+ notFound: 'Este plan de suscripción no está disponible.',
147
+ },
100
148
  };
101
149
 
102
150
  const dayWords = {
103
151
  en: { one: 'day', other: 'days' },
104
152
  ru: { one: 'день', few: 'дня', many: 'дней', other: 'дней' },
153
+ es: { one: 'día', other: 'días' },
105
154
  };
106
155
 
107
156
  export function tariffLabels(locale: string) {
@@ -109,9 +158,11 @@ export function tariffLabels(locale: string) {
109
158
  }
110
159
 
111
160
  export function tariffDays(days: number, locale: string) {
112
- const russian = locale.toLowerCase().startsWith('ru');
113
- const words: Record<string, string> = russian ? dayWords.ru : dayWords.en;
114
- const category = new Intl.PluralRules(russian ? 'ru' : 'en').select(days);
161
+ const language = locale.toLowerCase().startsWith('ru')
162
+ ? 'ru'
163
+ : locale.toLowerCase().startsWith('es') ? 'es' : 'en';
164
+ const words: Record<string, string> = dayWords[language];
165
+ const category = new Intl.PluralRules(language).select(days);
115
166
  return `${days} ${words[category] ?? words.other}`;
116
167
  }
117
168
 
@@ -82,11 +82,49 @@ const copy: Record<string, Record<string, TariffVariableCopy>> = {
82
82
  unlimited: true,
83
83
  },
84
84
  },
85
+ es: {
86
+ sales_module: {
87
+ name: 'Módulo de ventas',
88
+ hint: 'Todo lo necesario para vender: catálogo, carrito, pedidos, pagos y vendedores.',
89
+ },
90
+ blog_module: {
91
+ name: 'Módulo de blog',
92
+ hint: 'Una sección de contenido con categorías, comentarios y lectura de pago.',
93
+ },
94
+ qr_module: {
95
+ name: 'Módulo QR',
96
+ hint: 'Etiquetado QR de las existencias físicas para almacén y venta, junto con los ajustes de existencias del panel de gestión.',
97
+ },
98
+ max_files_size: {
99
+ name: 'Almacenamiento de archivos',
100
+ hint: 'Almacenamiento total del proyecto. Cada subida se suma al almacenamiento ya usado, y se rechaza una subida que supere este total.',
101
+ unit: 'megabytes',
102
+ unlimited: true,
103
+ },
104
+ max_api_requests: {
105
+ name: 'Solicitudes a la API al mes',
106
+ hint: 'Cuántas solicitudes a la API puede hacer el proyecto durante un mes natural. El contador vuelve a empezar el primer día del mes siguiente.',
107
+ unit: 'count',
108
+ unlimited: true,
109
+ },
110
+ max_front_hosts: {
111
+ name: 'Dominios de escaparate',
112
+ hint: 'Cuántos dominios de escaparate se pueden conectar a la vez.',
113
+ unit: 'count',
114
+ },
115
+ max_sellers: {
116
+ name: 'Vendedores',
117
+ hint: 'Cuántas cuentas de vendedor puede usar la tienda. Con un solo vendedor se activa la interfaz simplificada de tienda única.',
118
+ unit: 'count',
119
+ unlimited: true,
120
+ },
121
+ },
85
122
  };
86
123
 
87
124
  const units = {
88
125
  en: { megabytes: 'MB', gigabytes: 'GB', unlimited: 'Unlimited' },
89
126
  ru: { megabytes: 'МБ', gigabytes: 'ГБ', unlimited: 'Без ограничений' },
127
+ es: { megabytes: 'MB', gigabytes: 'GB', unlimited: 'Ilimitado' },
90
128
  };
91
129
 
92
130
  export function tariffVariableCopy(locale: string) {
@@ -192,6 +192,99 @@ const ru: typeof en = {
192
192
  decisionDeclined: 'Отклонено',
193
193
  };
194
194
 
195
+ const es: typeof en = {
196
+ title: 'Soporte',
197
+ new: 'Nueva conversación',
198
+ newAction: 'Nuevo',
199
+ newHint: 'Nueva conversación',
200
+ ticket: 'Conversación',
201
+ open: 'Abiertas',
202
+ closed: 'Cerradas',
203
+ statusOpen: 'Abiertas',
204
+ statusClosed: 'Cerradas',
205
+ empty: 'No hay conversaciones en esta categoría.',
206
+ message: 'Mensaje',
207
+ images: 'Imágenes',
208
+ attach: 'Adjuntar',
209
+ choose: 'Elige una conversación o empieza una nueva.',
210
+ back: 'Conversaciones',
211
+ backHint: 'Todas las conversaciones',
212
+ send: 'Enviar',
213
+ create: 'Crear',
214
+ close: 'Cerrar',
215
+ closeHint: 'Cerrar la conversación',
216
+ closeQuestion:
217
+ '¿Cerrar esta conversación? Ya no podrás responder aquí.',
218
+ delete: 'Eliminar',
219
+ deleteHint: 'Eliminar la conversación',
220
+ deleteQuestion: '¿Eliminar esta conversación y su mensaje?',
221
+ rating: 'Valora el soporte que recibiste',
222
+ unrated: 'Sin valoración',
223
+ rated: 'Tu valoración',
224
+ image: 'Imagen adjunta',
225
+ imageError: 'No se ha podido cargar esta imagen.',
226
+ removeImage: 'Quitar la imagen',
227
+ tooMany: 'Elige hasta cinco imágenes para un mensaje.',
228
+ product: 'Sobre un artículo de tu pedido',
229
+ option: 'Sobre una opción de tu pedido',
230
+ subscription: 'Sobre tu suscripción',
231
+ common: 'Describe en qué podemos ayudarte.',
232
+ unread: 'Mensajes sin leer',
233
+ sent: 'Enviado',
234
+ order: 'Ver el pedido',
235
+ refreshRequired: 'Actualiza la conversación antes de enviar otro mensaje.',
236
+ waitSupport: 'Espera la respuesta del soporte. Después podrás añadir detalles.',
237
+ waitDelay:
238
+ 'Espera la respuesta del soporte. Podrás enviar otro mensaje unos minutos después del anterior.',
239
+ draftLost: 'El mensaje se ha guardado. Actualiza para ver la conversación.',
240
+ typeCommon: 'Pregunta general',
241
+ typeOrder: 'Artículo del pedido',
242
+ typeSeller: 'Pregunta al vendedor',
243
+ typeSubscription: 'Suscripción',
244
+ refundCanceled: 'Devolución cancelada',
245
+ refundCreated: 'Pendiente de envío',
246
+ refundSent: 'Devolución enviada',
247
+ refundReceived: 'Recibida por la tienda',
248
+ refundDone: 'Reembolso aprobado',
249
+ refundProblem: 'Reembolso rechazado',
250
+ refundHints: {
251
+ canceled: 'Esta devolución se ha cancelado, así que no habrá reembolso.',
252
+ created: 'Devuelve los artículos de abajo con el transportista de esta devolución.',
253
+ sent: 'La devolución va de camino a la tienda.',
254
+ received: 'La tienda ha recibido la devolución.',
255
+ done: 'Se ha aprobado el reembolso de los artículos devueltos.',
256
+ problem:
257
+ 'La tienda ha rechazado los artículos devueltos, así que ese dinero no se paga.',
258
+ },
259
+ refund: 'Devolución',
260
+ refundCarrier: 'Transportista',
261
+ refundTrack: 'Número de seguimiento de la devolución',
262
+ refundAmount: 'Importe del reembolso',
263
+ refundCarrierStatus: 'Estado del transportista',
264
+ refundItems: 'Artículos de esta devolución',
265
+ subject: 'Esta conversación trata sobre',
266
+ subscriptionSubject: 'Esta conversación trata sobre la suscripción',
267
+ itemUnknown: 'El artículo ya no está disponible',
268
+ itemOption: 'Opción',
269
+ itemQuantity: 'Cantidad',
270
+ itemPrice: 'Pagado',
271
+ itemPicture: 'Imagen',
272
+ refundCounts: {
273
+ awaiting: 'Para devolver',
274
+ received: 'Devueltos',
275
+ approved: 'Aprobados para reembolso',
276
+ defect: 'De ellos, defectuosos',
277
+ },
278
+ defect: 'Defecto',
279
+ defectOptional: 'El artículo es defectuoso',
280
+ defectOnly:
281
+ 'El plazo normal de devolución ha terminado; solo es posible devolverlo por defecto.',
282
+ decision: 'Decisión',
283
+ decisionPending: 'En revisión',
284
+ decisionApproved: 'Aprobado',
285
+ decisionDeclined: 'Rechazado',
286
+ };
287
+
195
288
  export type TicketStatusIcon = 'lock' | 'unlock';
196
289
 
197
290
  export interface TicketStatusView {
@@ -200,7 +293,7 @@ export interface TicketStatusView {
200
293
  }
201
294
 
202
295
  export function ticketLabels(locale: string) {
203
- return locale.toLowerCase().startsWith('ru') ? ru : en;
296
+ return locale.toLowerCase().startsWith('ru') ? ru : locale.toLowerCase().startsWith('es') ? es : en;
204
297
  }
205
298
 
206
299
  // The backend status text is not translated, so known statuses use the