Changeset 3645531
- Timestamp:
- 08/13/2026 02:03:58 PM (2 months ago)
- Location:
- opcion5-sports-event-registration/trunk
- Files:
-
- 11 added
- 35 edited
-
admin/class-wpcr-add-participant.php (modified) (4 diffs)
-
admin/class-wpcr-admin-assets.php (modified) (1 diff)
-
admin/class-wpcr-admin-menu.php (modified) (12 diffs)
-
admin/class-wpcr-category-settings.php (modified) (16 diffs)
-
admin/class-wpcr-edit-event.php (modified) (5 diffs)
-
admin/class-wpcr-edit-participant.php (modified) (5 diffs)
-
admin/class-wpcr-form-settings.php (modified) (7 diffs)
-
admin/class-wpcr-modalidades.php (modified) (7 diffs)
-
admin/class-wpcr-participants-list.php (modified) (2 diffs)
-
admin/events/tabs/emails.php (modified) (12 diffs)
-
admin/events/tabs/general.php (modified) (8 diffs)
-
admin/events/tabs/options.php (modified) (21 diffs)
-
admin/events/tabs/participants.php (modified) (1 diff)
-
admin/events/tabs/prices.php (modified) (12 diffs)
-
admin/events/tabs/tech.php (modified) (8 diffs)
-
admin/js/wpcr-admin.js (modified) (1 diff)
-
asset/admin/js/shared/save-event.js (modified) (3 diffs)
-
asset/admin/js/tabs/cobros.js (modified) (2 diffs)
-
asset/admin/js/tabs/participants.js (modified) (2 diffs)
-
asset/wpcr-frontend.js (modified) (6 diffs)
-
cron/wpcr-cron-pairs.php (modified) (1 diff)
-
includes/class-wpcr-demo-data.php (modified) (7 diffs)
-
includes/class-wpcr-install.php (modified) (1 diff)
-
includes/emails/class-wpcr-payment-emails.php (modified) (5 diffs)
-
includes/emails/class-wpcr-result-email.php (modified) (6 diffs)
-
languages (added)
-
languages/opcion5-sports-event-registration-de_DE.mo (added)
-
languages/opcion5-sports-event-registration-de_DE.po (added)
-
languages/opcion5-sports-event-registration-es_ES.mo (added)
-
languages/opcion5-sports-event-registration-es_ES.po (added)
-
languages/opcion5-sports-event-registration-fr_FR.mo (added)
-
languages/opcion5-sports-event-registration-fr_FR.po (added)
-
languages/opcion5-sports-event-registration-it_IT.mo (added)
-
languages/opcion5-sports-event-registration-it_IT.po (added)
-
languages/opcion5-sports-event-registration-pt_PT.mo (added)
-
languages/opcion5-sports-event-registration-pt_PT.po (added)
-
modules/addons/AddonsPage.php (modified) (24 diffs)
-
opcion5-sports-event-registration.php (modified) (5 diffs)
-
public/ajax-wpcr-dni.php (modified) (5 diffs)
-
public/class-wpcr-payment-mails.php (modified) (1 diff)
-
public/class-wpcr-payment-page.php (modified) (4 diffs)
-
public/class-wpcr-public-list.php (modified) (19 diffs)
-
public/class-wpcr-public.php (modified) (74 diffs)
-
public/views/payment-bank-transfer.php (modified) (5 diffs)
-
public/wpcr-inscripcion-confirmada.php (modified) (12 diffs)
-
readme.txt (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
opcion5-sports-event-registration/trunk/admin/class-wpcr-add-participant.php
r3642215 r3645531 13 13 add_submenu_page( 14 14 null, 15 'Añadir participante',16 'Añadir participante',15 __( 'Add entrant', 'opcion5-sports-event-registration' ), 16 __( 'Add entrant', 'opcion5-sports-event-registration' ), 17 17 'manage_options', 18 18 'wpcr-add-participant', … … 27 27 // Solo lectura para saber qué evento mostrar; el alta verifica su propio nonce. 28 28 // phpcs:disable WordPress.Security.NonceVerification.Recommended 29 if(empty($_GET['event'])) wp_die( "Falta parámetro event");29 if(empty($_GET['event'])) wp_die( esc_html__( 'Missing event parameter', 'opcion5-sports-event-registration' ) ); 30 30 31 31 $this->public_id = sanitize_text_field( wp_unslash( $_GET['event'] ) ); … … 45 45 46 46 <h1>➕ Nuevo participante</h1> 47 <p><b> Evento ID público:</b> <?php echo esc_html($this->public_id); ?></p>47 <p><b><?php esc_html_e( 'Public event ID:', 'opcion5-sports-event-registration' ); ?></b> <?php echo esc_html($this->public_id); ?></p> 48 48 49 49 <?php … … 82 82 83 83 <h2>🆕 Participante registrado</h2> 84 <p> ¿Cómo deseas continuar?</p><br>84 <p><?php esc_html_e( 'How do you want to continue?', 'opcion5-sports-event-registration' ); ?></p><br> 85 85 86 86 <button id="wpcr-pay-manual" class="button button-primary" style="width:100%;margin-bottom:10px;font-weight:bold;"> -
opcion5-sports-event-registration/trunk/admin/class-wpcr-admin-assets.php
r3642215 r3645531 32 32 // Nonce compartido para las acciones AJAX del editor de eventos 33 33 // (invitar, recalcular categorías, guardar resultados…) 34 /* 35 * Los textos de los .js del editor van aquí: un fichero .js no lo alcanza el 36 * .mo. Se traducen en PHP y el navegador los recibe ya traducidos. 'wpcr-tabs' 37 * se encola antes que el resto, así que wpcrAdmin existe para todos ellos. 38 */ 34 39 wp_localize_script('wpcr-tabs', 'wpcrAdmin', [ 35 40 'nonce' => wp_create_nonce('wpcr_admin_ajax'), 41 'i18n' => [ 42 'recalcCategories' => __( 'Recalculate categories', 'opcion5-sports-event-registration' ), 43 'deleteEntrant' => __( 'Delete this entrant?', 'opcion5-sports-event-registration' ), 44 'invalidAmount' => __( 'Enter a valid amount.', 'opcion5-sports-event-registration' ), 45 'processing' => __( 'Processing…', 'opcion5-sports-event-registration' ), 46 'saving' => __( 'Saving…', 'opcion5-sports-event-registration' ), 47 'decimalPoint' => __( 'The "Race distance (km)" field must use a POINT as the decimal separator (for example 20.5), not a comma. Fix the value before saving.', 'opcion5-sports-event-registration' ), 48 'alreadyEntered' => __( "This entrant is already registered for this event.\n\nYou cannot add them again.", 'opcion5-sports-event-registration' ), 49 ], 36 50 ]); 37 51 -
opcion5-sports-event-registration/trunk/admin/class-wpcr-admin-menu.php
r3642215 r3645531 142 142 'url' => admin_url('admin-ajax.php'), 143 143 'nonce' => wp_create_nonce('wpcr_dni_lookup'), 144 // Los textos del .js se traducen aquí: el .mo no llega a un fichero .js. 145 'i18n' => [ 146 'alreadyEntered' => __( "This entrant is already registered for this event.\n\nYou cannot add them again.", 'opcion5-sports-event-registration' ), 147 ], 144 148 ]); 145 149 } … … 167 171 add_submenu_page( 168 172 'wpcr-competition', 169 __('Event os','opcion5-sports-event-registration'),170 __('Event os','opcion5-sports-event-registration'),173 __('Events','opcion5-sports-event-registration'), 174 __('Events','opcion5-sports-event-registration'), 171 175 $cap, 172 176 'wpcr-competition', … … 196 200 add_submenu_page( 197 201 'wpcr-competition', 198 __('Categor ías','opcion5-sports-event-registration'),199 __('Categor ías','opcion5-sports-event-registration'),202 __('Categories','opcion5-sports-event-registration'), 203 __('Categories','opcion5-sports-event-registration'), 200 204 $cap, 201 205 'wpcr-category-settings', … … 205 209 add_submenu_page( 206 210 'wpcr-competition', 207 __('Form ularios','opcion5-sports-event-registration'),208 __('Form ularios','opcion5-sports-event-registration'),211 __('Forms','opcion5-sports-event-registration'), 212 __('Forms','opcion5-sports-event-registration'), 209 213 $cap, 210 214 'wpcr-form-settings', … … 245 249 add_submenu_page( 246 250 null, 247 __('Edit ar evento','opcion5-sports-event-registration'),248 __('Edit ar evento','opcion5-sports-event-registration'),251 __('Edit event','opcion5-sports-event-registration'), 252 __('Edit event','opcion5-sports-event-registration'), 249 253 $cap, 250 254 'wpcr-edit-event', … … 254 258 add_submenu_page( 255 259 null, 256 __('A ñadir nuevo evento','opcion5-sports-event-registration'),257 __('A ñadir nuevo evento','opcion5-sports-event-registration'),260 __('Add new event','opcion5-sports-event-registration'), 261 __('Add new event','opcion5-sports-event-registration'), 258 262 $cap, 259 263 'wpcr-add-event', … … 276 280 public function render_participants_page_fallback() { 277 281 278 echo '<div class="wrap"><h1> Participantes</h1>';282 echo '<div class="wrap"><h1>' . esc_html__( 'Entrants', 'opcion5-sports-event-registration' ) . '</h1>'; 279 283 280 284 if ( class_exists( 'WPCR_Participants_List' ) ) { … … 394 398 LISTADO DE EVENTOS (sin límite en el número de eventos) 395 399 ========================================================= */ 396 echo '<div class="wrap"><h1> Eventos / Pruebas</h1>';400 echo '<div class="wrap"><h1>' . esc_html__( 'Events', 'opcion5-sports-event-registration' ) . '</h1>'; 397 401 398 402 /** … … 403 407 <strong>Significado de los estados:</strong> 404 408 <div style="display:flex; align-items:center; flex-wrap:wrap; gap:20px; margin-top:6px;"> 405 <span>🟢 <strong> Abierto:</strong> las inscripciones están disponibles.</span>409 <span>🟢 <strong>' . esc_html__( 'Open:', 'opcion5-sports-event-registration' ) . '</strong> las inscripciones están disponibles.</span> 406 410 <span>🟡 <strong>Pendiente:</strong> las inscripciones aún no han comenzado.</span> 407 <span>🔴 <strong> Cerrado:</strong> las inscripciones han finalizado.</span>411 <span>🔴 <strong>' . esc_html__( 'Closed:', 'opcion5-sports-event-registration' ) . '</strong> las inscripciones han finalizado.</span> 408 412 </div> 409 413 </div>'; … … 445 449 <th class="wpcr-id">ID</th> 446 450 <th class="wpcr-title">Título</th> 447 <th> Fecha</th>448 <th> Apertura</th>449 <th> Cierre</th>451 <th>' . esc_html__( 'Date', 'opcion5-sports-event-registration' ) . '</th> 452 <th>' . esc_html__( 'Opens', 'opcion5-sports-event-registration' ) . '</th> 453 <th>' . esc_html__( 'Closes', 'opcion5-sports-event-registration' ) . '</th> 450 454 <th>Inscritos</th> 451 <th> Cupo</th>455 <th>' . esc_html__( 'Quota', 'opcion5-sports-event-registration' ) . '</th> 452 456 <th>Estado</th> 453 457 <th>Formulario</th> … … 588 592 $close_ts = $e->reg_close ? strtotime($e->reg_close) : 0; 589 593 590 $event_date = $event_ts ? date_i18n('d/m/Y',$event_ts) : '—';591 $open_date = $open_ts ? date_i18n('d/m/Y H:i',$open_ts) : '—';592 $close_date = $close_ts ? date_i18n('d/m/Y H:i',$close_ts) : '—';594 $event_date = wpcr_format_date($event_ts, '—'); 595 $open_date = wpcr_format_datetime($open_ts, '—'); 596 $close_date = wpcr_format_datetime($close_ts, '—'); 593 597 594 598 if ( $open_ts && $open_ts > $now ) { … … 948 952 echo '<div class="wrap">'; 949 953 echo '<h1>¿Qué tipo de evento quieres crear?</h1>'; 950 echo '<p style="color:#555;max-width:760px;"> Elige cómo se organiza tu prueba. Lo configuras todo después; esto solo prepara la estructura adecuada.</p>';954 echo '<p style="color:#555;max-width:760px;">' . esc_html__( 'Choose how your event is organised. You configure everything afterwards; this only sets up the right structure.', 'opcion5-sports-event-registration' ) . '</p>'; 951 955 952 956 echo '<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px;max-width:1040px;margin-top:18px;">'; -
opcion5-sports-event-registration/trunk/admin/class-wpcr-category-settings.php
r3642215 r3645531 86 86 87 87 private function render_category_sets_list_content() { 88 echo '<h1>' . esc_html__( 'C onfiguración de Categorías', 'opcion5-sports-event-registration' ) .88 echo '<h1>' . esc_html__( 'Category settings', 'opcion5-sports-event-registration' ) . 89 89 ' <a href="' . esc_url( admin_url( 'admin.php?page=wpcr-category-settings&action=add' ) ) . '" class="page-title-action">' . 90 esc_html__( 'A ñadir nuevo conjunto', 'opcion5-sports-event-registration' ) . '</a></h1>';90 esc_html__( 'Add new set', 'opcion5-sports-event-registration' ) . '</a></h1>'; 91 91 92 92 $sets = WPCR_Data_Model::get_all_category_sets(); … … 99 99 <thead> 100 100 <tr> 101 <th><?php esc_html_e( ' Nombre del Conjunto', 'opcion5-sports-event-registration' ); ?></th>102 <th><?php esc_html_e( 'T ipo', 'opcion5-sports-event-registration' ); ?></th>103 <th style="text-align:center;"><?php esc_html_e( 'Total Categorías', 'opcion5-sports-event-registration' ); ?></th>104 <th style="text-align:center;"><?php esc_html_e( 'M asc.', 'opcion5-sports-event-registration' ); ?></th>105 <th style="text-align:center;"><?php esc_html_e( ' Fem.', 'opcion5-sports-event-registration' ); ?></th>106 <th style="text-align:center;"><?php esc_html_e( 'Mix tas', 'opcion5-sports-event-registration' ); ?></th>107 <th><?php esc_html_e( 'Ac ciones', 'opcion5-sports-event-registration' ); ?></th>101 <th><?php esc_html_e( 'Set name', 'opcion5-sports-event-registration' ); ?></th> 102 <th><?php esc_html_e( 'Type', 'opcion5-sports-event-registration' ); ?></th> 103 <th style="text-align:center;"><?php esc_html_e( 'Total categories', 'opcion5-sports-event-registration' ); ?></th> 104 <th style="text-align:center;"><?php esc_html_e( 'Men', 'opcion5-sports-event-registration' ); ?></th> 105 <th style="text-align:center;"><?php esc_html_e( 'Women', 'opcion5-sports-event-registration' ); ?></th> 106 <th style="text-align:center;"><?php esc_html_e( 'Mixed', 'opcion5-sports-event-registration' ); ?></th> 107 <th><?php esc_html_e( 'Actions', 'opcion5-sports-event-registration' ); ?></th> 108 108 </tr> 109 109 </thead> … … 112 112 <?php if ( empty( $sets ) ) : ?> 113 113 <tr> 114 <td colspan="7" style="text-align:center;"><?php esc_html_e( 'No hay conjuntos de categorías creados.', 'opcion5-sports-event-registration' ); ?></td>114 <td colspan="7" style="text-align:center;"><?php esc_html_e( 'No category sets have been created yet.', 'opcion5-sports-event-registration' ); ?></td> 115 115 </tr> 116 116 <?php else : ?> … … 164 164 '<a href="%s">%s</a>', 165 165 esc_url( wp_nonce_url( admin_url( 'admin.php?page=wpcr-category-settings&action=edit&id=' . $id ), 'wpcr_edit_set_' . $id ) ), 166 esc_html__( 'Edit ar', 'opcion5-sports-event-registration' )166 esc_html__( 'Edit', 'opcion5-sports-event-registration' ) 167 167 ), 168 168 sprintf( 169 169 '<a href="%s" data-wpcr-confirm="%s">%s</a>', 170 170 esc_url( $base . '&action=delete' ), 171 esc_attr__( ' ¿Estás seguro de que quieres borrar este conjunto?', 'opcion5-sports-event-registration' ),172 esc_html__( ' Borrar', 'opcion5-sports-event-registration' )171 esc_attr__( 'Are you sure you want to delete this set?', 'opcion5-sports-event-registration' ), 172 esc_html__( 'Delete', 'opcion5-sports-event-registration' ) 173 173 ) 174 174 ] ); … … 234 234 235 235 ?> 236 <h1><?php echo $is_edit ? esc_html__( 'Edit ar conjunto de categorías', 'opcion5-sports-event-registration' ) : esc_html__( 'Añadir conjunto de categorías', 'opcion5-sports-event-registration' ); ?></h1>236 <h1><?php echo $is_edit ? esc_html__( 'Edit category set', 'opcion5-sports-event-registration' ) : esc_html__( 'Add category set', 'opcion5-sports-event-registration' ); ?></h1> 237 237 238 238 <form method="post" id="wpcr-set-and-categories-form"> … … 243 243 <table class="form-table"> 244 244 <tr> 245 <th><label for="set_name"><?php esc_html_e( ' Nombre del conjunto', 'opcion5-sports-event-registration' ); ?></label></th>245 <th><label for="set_name"><?php esc_html_e( 'Set name', 'opcion5-sports-event-registration' ); ?></label></th> 246 246 <td> 247 247 <input type="text" id="set_name" name="set_name" class="regular-text" required value="<?php echo esc_attr( $set['name'] ); ?>"> 248 <p class="description"><?php esc_html_e( 'N ombre del conjunto que identifica a este grupo de categorías.', 'opcion5-sports-event-registration' ); ?></p>248 <p class="description"><?php esc_html_e( 'Name that identifies this group of categories.', 'opcion5-sports-event-registration' ); ?></p> 249 249 </td> 250 250 </tr> 251 251 <tr> 252 <th><?php esc_html_e( ' Tipo de categorización', 'opcion5-sports-event-registration' ); ?></th>252 <th><?php esc_html_e( 'Category type', 'opcion5-sports-event-registration' ); ?></th> 253 253 <td> 254 254 <label style="margin-right:20px;"> 255 255 <input type="radio" name="set_type" value="age" <?php checked( $set['type'] ?? 'age', 'age' ); ?>> 256 <?php esc_html_e( ' Por edad (ej: de 6 a 8 años)', 'opcion5-sports-event-registration' ); ?>256 <?php esc_html_e( 'By age (e.g. from 6 to 8 years old)', 'opcion5-sports-event-registration' ); ?> 257 257 </label> 258 258 <label> 259 259 <input type="radio" name="set_type" value="birth_year" <?php checked( $set['type'] ?? 'age', 'birth_year' ); ?>> 260 <?php esc_html_e( ' Por año de nacimiento (ej: nacidos entre 2016 y2018)', 'opcion5-sports-event-registration' ); ?>260 <?php esc_html_e( 'By year of birth (e.g. born between 2016 and 2018)', 'opcion5-sports-event-registration' ); ?> 261 261 </label> 262 <p class="description"><?php esc_html_e( ' Esta opción afecta a cómo se asignan los participantes a cada categoría en el momento de la inscripción.', 'opcion5-sports-event-registration' ); ?></p>262 <p class="description"><?php esc_html_e( 'This setting affects how entrants are assigned to each category when they register.', 'opcion5-sports-event-registration' ); ?></p> 263 263 </td> 264 264 </tr> 265 265 </table> 266 266 267 <h2><?php esc_html_e( 'Categor ías internas', 'opcion5-sports-event-registration' ); ?></h2>267 <h2><?php esc_html_e( 'Categories in this set', 'opcion5-sports-event-registration' ); ?></h2> 268 268 269 269 <?php $set_type = $set['type'] ?? 'age'; ?> … … 271 271 <thead> 272 272 <tr> 273 <th width="35%"><?php esc_html_e( ' Nombre de la Categoría', 'opcion5-sports-event-registration' ); ?></th>274 <th width="15%" class="wpcr-col-age" <?php echo $set_type === 'birth_year' ? 'style="display:none"' : ''; ?>><?php esc_html_e( ' Edad mín.', 'opcion5-sports-event-registration' ); ?></th>275 <th width="15%" class="wpcr-col-age" <?php echo $set_type === 'birth_year' ? 'style="display:none"' : ''; ?>><?php esc_html_e( ' Edad máx.', 'opcion5-sports-event-registration' ); ?></th>276 <th width="15%" class="wpcr-col-year" <?php echo $set_type !== 'birth_year' ? 'style="display:none"' : ''; ?>><?php esc_html_e( ' Año desde', 'opcion5-sports-event-registration' ); ?></th>277 <th width="15%" class="wpcr-col-year" <?php echo $set_type !== 'birth_year' ? 'style="display:none"' : ''; ?>><?php esc_html_e( ' Año hasta', 'opcion5-sports-event-registration' ); ?></th>278 <th width="10%"><?php esc_html_e( 'G énero', 'opcion5-sports-event-registration' ); ?></th>279 <th width="10%"><?php esc_html_e( 'Ac ciones', 'opcion5-sports-event-registration' ); ?></th>273 <th width="35%"><?php esc_html_e( 'Category name', 'opcion5-sports-event-registration' ); ?></th> 274 <th width="15%" class="wpcr-col-age" <?php echo $set_type === 'birth_year' ? 'style="display:none"' : ''; ?>><?php esc_html_e( 'Min. age', 'opcion5-sports-event-registration' ); ?></th> 275 <th width="15%" class="wpcr-col-age" <?php echo $set_type === 'birth_year' ? 'style="display:none"' : ''; ?>><?php esc_html_e( 'Max. age', 'opcion5-sports-event-registration' ); ?></th> 276 <th width="15%" class="wpcr-col-year" <?php echo $set_type !== 'birth_year' ? 'style="display:none"' : ''; ?>><?php esc_html_e( 'Year from', 'opcion5-sports-event-registration' ); ?></th> 277 <th width="15%" class="wpcr-col-year" <?php echo $set_type !== 'birth_year' ? 'style="display:none"' : ''; ?>><?php esc_html_e( 'Year to', 'opcion5-sports-event-registration' ); ?></th> 278 <th width="10%"><?php esc_html_e( 'Gender', 'opcion5-sports-event-registration' ); ?></th> 279 <th width="10%"><?php esc_html_e( 'Actions', 'opcion5-sports-event-registration' ); ?></th> 280 280 </tr> 281 281 </thead> … … 293 293 </table> 294 294 295 <p><button type="button" id="add-category-row" class="button"><?php esc_html_e( 'A ñadir Categoría', 'opcion5-sports-event-registration' ); ?></button></p>295 <p><button type="button" id="add-category-row" class="button"><?php esc_html_e( 'Add category', 'opcion5-sports-event-registration' ); ?></button></p> 296 296 297 297 <p class="submit"> 298 <button type="submit" class="button button-primary"><?php echo $is_edit ? esc_html__( ' Guardar cambios', 'opcion5-sports-event-registration' ) : esc_html__( 'Crear conjunto', 'opcion5-sports-event-registration' ); ?></button>299 <a class="button" href="<?php echo esc_url( admin_url( 'admin.php?page=wpcr-category-settings' ) ); ?>"><?php esc_html_e( 'Cancel ar', 'opcion5-sports-event-registration' ); ?></a>298 <button type="submit" class="button button-primary"><?php echo $is_edit ? esc_html__( 'Save changes', 'opcion5-sports-event-registration' ) : esc_html__( 'Create set', 'opcion5-sports-event-registration' ); ?></button> 299 <a class="button" href="<?php echo esc_url( admin_url( 'admin.php?page=wpcr-category-settings' ) ); ?>"><?php esc_html_e( 'Cancel', 'opcion5-sports-event-registration' ); ?></a> 300 300 <?php if ( $is_edit ) : ?> 301 <a class="button" style="margin-left:10px;" href="<?php echo esc_url( admin_url( 'admin.php?page=wpcr-category-settings&action=delete&id=' . intval( $set_id ) . '&_wpnonce=' . wp_create_nonce( 'wpcr_category_set_action_' . $set_id ) ) ); ?>" data-wpcr-confirm="<?php echo esc_attr__( ' ¿Estás seguro de que quieres borrar este conjunto?', 'opcion5-sports-event-registration' ); ?>"><?php esc_html_e( 'Borrar conjunto', 'opcion5-sports-event-registration' ); ?></a>301 <a class="button" style="margin-left:10px;" href="<?php echo esc_url( admin_url( 'admin.php?page=wpcr-category-settings&action=delete&id=' . intval( $set_id ) . '&_wpnonce=' . wp_create_nonce( 'wpcr_category_set_action_' . $set_id ) ) ); ?>" data-wpcr-confirm="<?php echo esc_attr__( 'Are you sure you want to delete this set?', 'opcion5-sports-event-registration' ); ?>"><?php esc_html_e( 'Delete set', 'opcion5-sports-event-registration' ); ?></a> 302 302 <?php endif; ?> 303 303 </p> … … 327 327 <h1><?php 328 328 /* translators: %s: nombre del conjunto de categorías */ 329 printf( esc_html__( ' Gestionar Categorías: %s', 'opcion5-sports-event-registration' ), esc_html( $set_data['name'] ) );329 printf( esc_html__( 'Manage categories: %s', 'opcion5-sports-event-registration' ), esc_html( $set_data['name'] ) ); 330 330 ?></h1> 331 <p><a href="<?php echo esc_url( admin_url( 'admin.php?page=wpcr-category-settings' ) ); ?>">« <?php esc_html_e( ' Volver al listado', 'opcion5-sports-event-registration' ); ?></a></p>331 <p><a href="<?php echo esc_url( admin_url( 'admin.php?page=wpcr-category-settings' ) ); ?>">« <?php esc_html_e( 'Back to the list', 'opcion5-sports-event-registration' ); ?></a></p> 332 332 333 333 <form method="post" id="wpcr-categories-form"> … … 338 338 <thead> 339 339 <tr> 340 <th width="25%"><?php esc_html_e( ' Nombre de la Categoría', 'opcion5-sports-event-registration' ); ?></th>341 <th width="15%"><?php esc_html_e( ' Edad Mínima', 'opcion5-sports-event-registration' ); ?></th>342 <th width="15%"><?php esc_html_e( ' Edad Máxima', 'opcion5-sports-event-registration' ); ?></th>343 <th width="15%"><?php esc_html_e( 'G énero', 'opcion5-sports-event-registration' ); ?></th>344 <th width="20%"><?php esc_html_e( 'Ac ciones', 'opcion5-sports-event-registration' ); ?></th>340 <th width="25%"><?php esc_html_e( 'Category name', 'opcion5-sports-event-registration' ); ?></th> 341 <th width="15%"><?php esc_html_e( 'Minimum age', 'opcion5-sports-event-registration' ); ?></th> 342 <th width="15%"><?php esc_html_e( 'Maximum age', 'opcion5-sports-event-registration' ); ?></th> 343 <th width="15%"><?php esc_html_e( 'Gender', 'opcion5-sports-event-registration' ); ?></th> 344 <th width="20%"><?php esc_html_e( 'Actions', 'opcion5-sports-event-registration' ); ?></th> 345 345 </tr> 346 346 </thead> … … 356 356 </table> 357 357 358 <p><button type="button" id="add-category-row" class="button"><?php esc_html_e( 'A ñadir Categoría', 'opcion5-sports-event-registration' ); ?></button></p>359 <?php submit_button( esc_html__( ' Guardar Categorías', 'opcion5-sports-event-registration' ), 'primary', 'wpcr_save_categories' ); ?>358 <p><button type="button" id="add-category-row" class="button"><?php esc_html_e( 'Add category', 'opcion5-sports-event-registration' ); ?></button></p> 359 <?php submit_button( esc_html__( 'Save categories', 'opcion5-sports-event-registration' ), 'primary', 'wpcr_save_categories' ); ?> 360 360 </form> 361 361 … … 395 395 </select> 396 396 </td> 397 <td><button type="button" class="button button-secondary delete-category-row" data-row-id="<?php echo esc_attr( $row_id ); ?>"><?php esc_html_e( ' Borrar', 'opcion5-sports-event-registration' ); ?></button></td>397 <td><button type="button" class="button button-secondary delete-category-row" data-row-id="<?php echo esc_attr( $row_id ); ?>"><?php esc_html_e( 'Delete', 'opcion5-sports-event-registration' ); ?></button></td> 398 398 </tr> 399 399 <?php … … 448 448 private function handle_save_set_and_categories() { 449 449 if ( ! current_user_can( 'manage_options' ) ) { 450 wp_die( esc_html__( 'No autorizado.', 'opcion5-sports-event-registration' ) );450 wp_die( esc_html__( 'Not allowed.', 'opcion5-sports-event-registration' ) ); 451 451 } 452 452 453 453 if ( empty( $_POST['wpcr_save_set_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['wpcr_save_set_nonce'] ) ), 'wpcr_save_set_nonce' ) ) { 454 wp_die( esc_html__( ' Verificación de seguridad fallida.', 'opcion5-sports-event-registration' ) );454 wp_die( esc_html__( 'Security check failed.', 'opcion5-sports-event-registration' ) ); 455 455 } 456 456 … … 461 461 462 462 if ( empty( $set_name ) ) { 463 wp_die( esc_html__( ' El nombre del conjunto no puede estar vacío.', 'opcion5-sports-event-registration' ) );463 wp_die( esc_html__( 'The set name cannot be empty.', 'opcion5-sports-event-registration' ) ); 464 464 } 465 465 … … 467 467 468 468 if ( ! $saved_set_id ) { 469 wp_die( esc_html__( ' No se pudo guardar el conjunto.', 'opcion5-sports-event-registration' ) );469 wp_die( esc_html__( 'The set could not be saved.', 'opcion5-sports-event-registration' ) ); 470 470 } 471 471 … … 510 510 private function handle_save_categories( $set_id ) { 511 511 if ( ! isset( $_POST['wpcr_categories_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['wpcr_categories_nonce'] ) ), 'wpcr_save_categories_nonce' ) ) { 512 wp_die( esc_html__( ' Verificación de seguridad fallida.', 'opcion5-sports-event-registration' ) );512 wp_die( esc_html__( 'Security check failed.', 'opcion5-sports-event-registration' ) ); 513 513 } 514 514 -
opcion5-sports-event-registration/trunk/admin/class-wpcr-edit-event.php
r3642215 r3645531 140 140 $wpcr_new_type = ( $is_new && isset( $_GET['wpcr_type'] ) ) ? sanitize_key( wp_unslash( $_GET['wpcr_type'] ) ) : ''; 141 141 $wpcr_type_notice = [ 142 'multidistancia' => 'Estás creando una <strong> carrera con multidistancias</strong>. Rellena los datos generales y <strong>guarda</strong>; después añade las distancias en la pestaña <strong>🏁 Distancias</strong>.',143 'stages' => 'Estás creando una <strong> carrera por etapas</strong>. Rellena los datos generales (y el precio del <em>pack</em> en Precios y Pagos) y <strong>guarda</strong>; después añade las etapas en la pestaña <strong>🏔 Etapas</strong>.',142 'multidistancia' => 'Estás creando una <strong>' . esc_html__( 'race with several distances', 'opcion5-sports-event-registration' ) . '</strong>. Rellena los datos generales y <strong>' . esc_html__( 'save', 'opcion5-sports-event-registration' ) . '</strong>; después añade las distancias en la pestaña <strong>🏁 ' . esc_html__( 'Distances', 'opcion5-sports-event-registration' ) . '</strong>.', 143 'stages' => 'Estás creando una <strong>' . esc_html__( 'stage race', 'opcion5-sports-event-registration' ) . '</strong>. Rellena los datos generales (y el precio del <em>pack</em> en Precios y Pagos) y <strong>' . esc_html__( 'save', 'opcion5-sports-event-registration' ) . '</strong>; después añade las etapas en la pestaña <strong>🏔 Etapas</strong>.', 144 144 ]; 145 145 if ( isset( $wpcr_type_notice[ $wpcr_new_type ] ) ) : … … 181 181 }; 182 182 $wpcr_extension_tabs = [ 183 'distances' => [ 'label' => '🏁 Distancias', 'on' => $distances_eligible && $wpcr_ext_on('wpcr-multidistancia') ],183 'distances' => [ 'label' => '🏁 ' . __( 'Distances', 'opcion5-sports-event-registration' ), 'on' => $distances_eligible && $wpcr_ext_on('wpcr-multidistancia') ], 184 184 'stages' => [ 'label' => '🏔 Etapas', 'on' => $stages_eligible && $wpcr_ext_on('wpcr-stages') ], 185 185 'aid' => [ 'label' => '🥤 Avituallamientos', 'on' => $wpcr_ext_on('wpcr-aid-stations') ], … … 187 187 'cartel' => [ 'label' => '🖼 Cartel', 'on' => $wpcr_ext_on('wpcr-cartel-designer') ], 188 188 'checkin' => [ 'label' => '🎫 Entrega', 'on' => $wpcr_ext_on('wpcr-checkin') ], 189 'timing' => [ 'label' => '⏱ Cronometraje', 'on' => $wpcr_ext_on('wpcr-timing') ],190 'crono' => [ 'label' => '⏱ Contrarreloj', 'on' => $wpcr_ext_on('wpcr-crono') ],189 'timing' => [ 'label' => '⏱ ' . __( 'Timing', 'opcion5-sports-event-registration' ), 'on' => $wpcr_ext_on('wpcr-timing') ], 190 'crono' => [ 'label' => '⏱ ' . __( 'Time trial', 'opcion5-sports-event-registration' ), 'on' => $wpcr_ext_on('wpcr-crono') ], 191 191 'rfid' => [ 'label' => '🔖 RFID', 'on' => $wpcr_ext_on('wpcr-rfid') ], 192 'stats' => [ 'label' => '📊 Estadísticas', 'on' => $wpcr_ext_on('wpcr-stats') ],193 'results' => [ 'label' => '🏁 Clasificaciones', 'on' => $wpcr_ext_on('wpcr-results') ],194 'import' => [ 'label' => '📂 Importar CSV', 'on' => $wpcr_ext_on('wpcr-import') ],192 'stats' => [ 'label' => '📊 ' . __( 'Statistics', 'opcion5-sports-event-registration' ), 'on' => $wpcr_ext_on('wpcr-stats') ], 193 'results' => [ 'label' => '🏁 ' . __( 'Standings', 'opcion5-sports-event-registration' ), 'on' => $wpcr_ext_on('wpcr-results') ], 194 'import' => [ 'label' => '📂 ' . __( 'Import CSV', 'opcion5-sports-event-registration' ), 'on' => $wpcr_ext_on('wpcr-import') ], 195 195 ]; 196 196 ?> … … 201 201 <div class="wpcr-tab-bar"> 202 202 <div class="wpcr-tab active" data-open="wpcr-tab-general">General</div> 203 <div class="wpcr-tab" data-open="wpcr-tab-tech">📁 Info técnica</div>204 <div class="wpcr-tab" data-open="wpcr-tab-options"> Opciones</div>205 <div class="wpcr-tab" data-open="wpcr-tab-prices"> Precios y Pagos</div>203 <div class="wpcr-tab" data-open="wpcr-tab-tech">📁 <?php esc_html_e( 'Race info', 'opcion5-sports-event-registration' ); ?></div> 204 <div class="wpcr-tab" data-open="wpcr-tab-options"><?php esc_html_e( 'Options', 'opcion5-sports-event-registration' ); ?></div> 205 <div class="wpcr-tab" data-open="wpcr-tab-prices"><?php esc_html_e( 'Prices and payments', 'opcion5-sports-event-registration' ); ?></div> 206 206 <div class="wpcr-tab" data-open="wpcr-tab-emails">Emails</div> 207 <div class="wpcr-tab" data-open="wpcr-tab-participants"> Participantes</div>208 <div class="wpcr-tab" data-open="wpcr-tab-payments">💳 Cobros</div>207 <div class="wpcr-tab" data-open="wpcr-tab-participants"><?php esc_html_e( 'Entrants', 'opcion5-sports-event-registration' ); ?></div> 208 <div class="wpcr-tab" data-open="wpcr-tab-payments">💳 <?php esc_html_e( 'Payments', 'opcion5-sports-event-registration' ); ?></div> 209 209 <?php foreach ( $wpcr_extension_tabs as $wpcr_tab_key => $wpcr_tab ) : ?> 210 210 <?php if ( $wpcr_tab['on'] ) : ?> … … 577 577 578 578 if ( ! $row ) { 579 $msg = "<h2 style='color:red;'> Evento no encontrado</h2>";579 $msg = "<h2 style='color:red;'>" . esc_html__( 'Event not found', 'opcion5-sports-event-registration' ) . "</h2>"; 580 580 if ( $is_ajax ) { 581 581 wp_send_json_error( ['message' => 'Evento no encontrado'] ); -
opcion5-sports-event-registration/trunk/admin/class-wpcr-edit-participant.php
r3642215 r3645531 301 301 // Render formulario 302 302 // ---------------------------- 303 echo '<div class="wrap"><h1>' . ( $participant_id ? esc_html__( 'Edit ar participante', 'opcion5-sports-event-registration' ) : esc_html__( 'Añadir participante', 'opcion5-sports-event-registration' ) ) . '</h1>';303 echo '<div class="wrap"><h1>' . ( $participant_id ? esc_html__( 'Edit entrant', 'opcion5-sports-event-registration' ) : esc_html__( 'Add entrant', 'opcion5-sports-event-registration' ) ) . '</h1>'; 304 304 305 305 echo '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '">'; … … 346 346 347 347 // Convierte YYYY-MM-DD → DD/MM/YYYY solo para visualizar 348 $dob_display = ($val && $val !== '0000-00-00') ? date_i18n("d/m/Y", strtotime($val)) : '';348 $dob_display = wpcr_format_date($val); 349 349 350 350 echo '<input type="text" … … 459 459 // ---------------------------- 460 460 if ( ! empty( $template_clean ) ) { 461 echo '<tr><th colspan="2"><strong>' . esc_html__( ' Campos adicionales', 'opcion5-sports-event-registration' ) . '</strong></th></tr>';461 echo '<tr><th colspan="2"><strong>' . esc_html__( 'Extra fields', 'opcion5-sports-event-registration' ) . '</strong></th></tr>'; 462 462 } 463 463 … … 615 615 // botón guardar + volver 616 616 echo '<p class="submit">'; 617 submit_button( esc_html__( ' Guardar cambios', 'opcion5-sports-event-registration' ), 'primary', 'submit', false );617 submit_button( esc_html__( 'Save changes', 'opcion5-sports-event-registration' ), 'primary', 'submit', false ); 618 618 // Volver siempre al listado general (ignorar evento) 619 619 $back_url = admin_url("admin.php?page=wpcr-participants"); … … 716 716 echo '<!DOCTYPE html><html><head><meta charset="utf-8"></head>' 717 717 . '<body style="font-family:-apple-system,Segoe UI,sans-serif;color:#1d2327;padding:24px;">' 718 . esc_html__( ' Guardado. Cerrando…', 'opcion5-sports-event-registration' );718 . esc_html__( 'Saved. Closing…', 'opcion5-sports-event-registration' ); 719 719 wp_print_inline_script_tag( 720 720 'if(window.parent&&window.parent!==window){window.parent.postMessage({wpcr:"participant-saved",id:' . (int) $id . '},"*");}' -
opcion5-sports-event-registration/trunk/admin/class-wpcr-form-settings.php
r3642215 r3645531 39 39 ?> 40 40 <div class="wrap"> 41 <h1 class="wp-heading-inline"><?php esc_html_e( ' Formularios personalizados', 'opcion5-sports-event-registration' ); ?></h1>42 <a href="?page=wpcr-form-settings&action=add" class="page-title-action"><?php esc_html_e( 'A ñadir nuevo', 'opcion5-sports-event-registration' ); ?></a>41 <h1 class="wp-heading-inline"><?php esc_html_e( 'Custom forms', 'opcion5-sports-event-registration' ); ?></h1> 42 <a href="?page=wpcr-form-settings&action=add" class="page-title-action"><?php esc_html_e( 'Add new', 'opcion5-sports-event-registration' ); ?></a> 43 43 <hr class="wp-header-end"> 44 44 … … 47 47 <tr> 48 48 <th><?php esc_html_e( 'ID', 'opcion5-sports-event-registration' ); ?></th> 49 <th><?php esc_html_e( 'N ombre', 'opcion5-sports-event-registration' ); ?></th>50 <th><?php esc_html_e( 'Descrip ción', 'opcion5-sports-event-registration' ); ?></th>51 <th><?php esc_html_e( 'Ac ciones', 'opcion5-sports-event-registration' ); ?></th>49 <th><?php esc_html_e( 'Name', 'opcion5-sports-event-registration' ); ?></th> 50 <th><?php esc_html_e( 'Description', 'opcion5-sports-event-registration' ); ?></th> 51 <th><?php esc_html_e( 'Actions', 'opcion5-sports-event-registration' ); ?></th> 52 52 </tr> 53 53 </thead> 54 54 <tbody> 55 55 <?php if ( empty( $forms ) ) : ?> 56 <tr><td colspan="4"><?php esc_html_e( 'No hay formularios creados.', 'opcion5-sports-event-registration' ); ?></td></tr>56 <tr><td colspan="4"><?php esc_html_e( 'No forms have been created yet.', 'opcion5-sports-event-registration' ); ?></td></tr> 57 57 <?php else : ?> 58 58 <?php foreach ( $forms as $f ) : ?> … … 62 62 <td><?php echo esc_html( $f['description'] ); ?></td> 63 63 <td> 64 <a href="?page=wpcr-form-settings&action=edit&id=<?php echo esc_attr( $f['id'] ); ?>" class="button"><?php esc_html_e( 'Edit ar', 'opcion5-sports-event-registration' ); ?></a>64 <a href="?page=wpcr-form-settings&action=edit&id=<?php echo esc_attr( $f['id'] ); ?>" class="button"><?php esc_html_e( 'Edit', 'opcion5-sports-event-registration' ); ?></a> 65 65 </td> 66 66 </tr> … … 168 168 <?php 169 169 echo $id 170 ? esc_html__( 'Edit ar formulario', 'opcion5-sports-event-registration' )171 : esc_html__( 'N uevo formulario', 'opcion5-sports-event-registration' );170 ? esc_html__( 'Edit form', 'opcion5-sports-event-registration' ) 171 : esc_html__( 'New form', 'opcion5-sports-event-registration' ); 172 172 ?> 173 173 </h1> … … 180 180 <table class="form-table" role="presentation"> 181 181 <tr> 182 <th><label for="name"><?php esc_html_e( ' Nombre del formulario', 'opcion5-sports-event-registration' ); ?></label></th>182 <th><label for="name"><?php esc_html_e( 'Form name', 'opcion5-sports-event-registration' ); ?></label></th> 183 183 <td><input name="name" id="name" type="text" value="<?php echo esc_attr( $form['name'] ); ?>" class="regular-text" required></td> 184 184 </tr> 185 185 <tr> 186 <th><label for="description"><?php esc_html_e( 'Descrip ción', 'opcion5-sports-event-registration' ); ?></label></th>186 <th><label for="description"><?php esc_html_e( 'Description', 'opcion5-sports-event-registration' ); ?></label></th> 187 187 <td><textarea name="description" id="description" rows="3" class="large-text"><?php echo esc_textarea( $form['description'] ); ?></textarea></td> 188 188 </tr> 189 189 </table> 190 190 191 <h2><?php esc_html_e( ' Constructor de campos', 'opcion5-sports-event-registration' ); ?></h2>191 <h2><?php esc_html_e( 'Field builder', 'opcion5-sports-event-registration' ); ?></h2> 192 192 193 193 <div style="background:#f9f9f9;border:1px solid #ccd0d4;border-left:4px solid #2271b1;padding:12px 15px;border-radius:4px;margin-bottom:20px;"> 194 <p><strong><?php esc_html_e( ' Campos obligatorios del sistema (no editables aquí):', 'opcion5-sports-event-registration' ); ?></strong></p>194 <p><strong><?php esc_html_e( 'Required system fields (not editable here):', 'opcion5-sports-event-registration' ); ?></strong></p> 195 195 <ul style="margin-left:20px;list-style:disc;"> 196 <li><?php esc_html_e( ' DNI / Nacionalidad — usados para identificación y lógica de documento.', 'opcion5-sports-event-registration' ); ?></li>197 <li><?php esc_html_e( ' Fecha de nacimiento — usada para calcular edad y categoría.', 'opcion5-sports-event-registration' ); ?></li>198 <li><?php esc_html_e( 'G énero — usado para calcular la categoría por edad y sexo.', 'opcion5-sports-event-registration' ); ?></li>199 <li><?php esc_html_e( 'P olítica de privacidad — campo legal obligatorio.', 'opcion5-sports-event-registration' ); ?></li>196 <li><?php esc_html_e( 'ID number / Nationality — used for identification and document checks.', 'opcion5-sports-event-registration' ); ?></li> 197 <li><?php esc_html_e( 'Date of birth — used to work out age and category.', 'opcion5-sports-event-registration' ); ?></li> 198 <li><?php esc_html_e( 'Gender — used to work out the category by age and gender.', 'opcion5-sports-event-registration' ); ?></li> 199 <li><?php esc_html_e( 'Privacy policy — required legal field.', 'opcion5-sports-event-registration' ); ?></li> 200 200 </ul> 201 <p style="margin-top:8px;"><?php esc_html_e( ' En este constructor solo verás y editarás los campos extra específicos de la prueba.', 'opcion5-sports-event-registration' ); ?></p>201 <p style="margin-top:8px;"><?php esc_html_e( 'In this builder you only see and edit the extra fields specific to the event.', 'opcion5-sports-event-registration' ); ?></p> 202 202 </div> 203 203 … … 205 205 206 206 <p class="submit" style="margin-top:20px;"> 207 <button type="submit" class="button-primary"><?php esc_html_e( ' Guardar formulario', 'opcion5-sports-event-registration' ); ?></button>208 <a href="?page=wpcr-form-settings" class="button"><?php esc_html_e( 'Cancel ar', 'opcion5-sports-event-registration' ); ?></a>207 <button type="submit" class="button-primary"><?php esc_html_e( 'Save form', 'opcion5-sports-event-registration' ); ?></button> 208 <a href="?page=wpcr-form-settings" class="button"><?php esc_html_e( 'Cancel', 'opcion5-sports-event-registration' ); ?></a> 209 209 </p> 210 210 … … 456 456 public function handle_save_form() { 457 457 if ( empty( $_POST['wpcr_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['wpcr_nonce'] ) ), 'wpcr_save_form' ) ) { 458 wp_die( esc_html__( ' Nonce no válido.', 'opcion5-sports-event-registration' ) );458 wp_die( esc_html__( 'Invalid nonce.', 'opcion5-sports-event-registration' ) ); 459 459 } 460 460 461 461 if ( ! current_user_can( 'manage_options' ) ) { 462 wp_die( esc_html__( 'No autorizado.', 'opcion5-sports-event-registration' ) );462 wp_die( esc_html__( 'Not allowed.', 'opcion5-sports-event-registration' ) ); 463 463 } 464 464 -
opcion5-sports-event-registration/trunk/admin/class-wpcr-modalidades.php
r3642215 r3645531 7 7 8 8 if ( ! current_user_can('manage_options') ) { 9 wp_die( esc_html__('No autorizado', 'opcion5-sports-event-registration') );9 wp_die( esc_html__('Not allowed', 'opcion5-sports-event-registration') ); 10 10 } 11 11 … … 32 32 $wpdb->update($table, ['image'=>null], ['id'=>$id]); 33 33 34 echo "<div class='updated'><p>🗑 Imagen eliminada correctamente.</p></div>";34 echo "<div class='updated'><p>🗑 " . esc_html__( 'Image deleted successfully.', 'opcion5-sports-event-registration' ) . "</p></div>"; 35 35 } 36 36 } … … 58 58 $wpdb->delete($table, ['id'=>$id]); 59 59 60 echo "<div class='updated'><p>🗑 Modalidad eliminada junto con su imagen.</p></div>";60 echo "<div class='updated'><p>🗑 " . esc_html__( 'Discipline deleted along with its image.', 'opcion5-sports-event-registration' ) . "</p></div>"; 61 61 } 62 62 … … 75 75 $wpdb->insert($table, ['name'=>$name, 'slug'=>$slug]); 76 76 77 echo "<div class='updated'><p>✔ Modalidad añadida correctamente</p></div>";77 echo "<div class='updated'><p>✔ " . esc_html__( 'Discipline added successfully', 'opcion5-sports-event-registration' ) . "</p></div>"; 78 78 } 79 79 … … 137 137 $wpdb->update($table, $update_data, ['id'=>$id]); 138 138 139 echo "<div class='updated'><p>✏ Modalidad actualizada con éxito</p></div>";139 echo "<div class='updated'><p>✏ " . esc_html__( 'Discipline updated successfully', 'opcion5-sports-event-registration' ) . "</p></div>"; 140 140 } 141 141 … … 154 154 echo " <input type='text' name='wpcr_new_mod' placeholder='Nueva modalidad (MTB, Trail...)' 155 155 required style='width:260px;padding:6px;'> 156 <button class='button button-primary'> Añadir</button>156 <button class='button button-primary'>" . esc_html__( 'Add', 'opcion5-sports-event-registration' ) . "</button> 157 157 </form>"; 158 158 … … 185 185 <a href="<?php echo esc_url($url_edit); ?>" class="button button-small">✏ Editar</a> 186 186 <a href="<?php echo esc_url($url_delimg); ?>" class="button button-small" 187 data-wpcr-confirm=" ¿Eliminar SOLO la imagen?">🖼 Eliminar imagen</a>187 data-wpcr-confirm="' . esc_attr__( 'Delete ONLY the image?', 'opcion5-sports-event-registration' ) . '">🖼 ' . esc_html__( 'Delete image', 'opcion5-sports-event-registration' ) . '</a> 188 188 <a href="<?php echo esc_url($url_del); ?>" class="button button-small" style="color:#c00" 189 data-wpcr-confirm=" ¿Eliminar modalidad y su imagen?">🗑 Eliminar</a>189 data-wpcr-confirm="' . esc_attr__( 'Delete the discipline and its image?', 'opcion5-sports-event-registration' ) . '">🗑 ' . esc_html__( 'Delete', 'opcion5-sports-event-registration' ) . '</a> 190 190 </td> 191 191 </tr> -
opcion5-sports-event-registration/trunk/admin/class-wpcr-participants-list.php
r3642215 r3645531 271 271 // plugin ($pair_cell y get_row_actions_html) se filtra con wp_kses_post(). 272 272 echo '<tr data-search="' . esc_attr( $search_val ) . '">' 273 . '<td><a href="' . esc_url( $edit_url ) . '" title="' . esc_attr__( 'Edit ar ficha del participante', 'opcion5-sports-event-registration' ) . '">' . esc_html( $p['first_name'] ) . '</a></td>'273 . '<td><a href="' . esc_url( $edit_url ) . '" title="' . esc_attr__( 'Edit entrant details', 'opcion5-sports-event-registration' ) . '">' . esc_html( $p['first_name'] ) . '</a></td>' 274 274 . '<td>' . esc_html( $ap ) . '</td>' 275 275 . '<td>' . esc_html( $p['dni'] ) . '</td>' … … 281 281 . '<td><b>' . esc_html( $estado ) . '</b></td>' 282 282 . '<td class="wpcr-actions-compact">' 283 . '<a href="' . esc_url( $edit_url ) . '" class="wpcr-ico" data-tip="' . esc_attr__( 'Edit ar participante', 'opcion5-sports-event-registration' ) . '">✎</a>'283 . '<a href="' . esc_url( $edit_url ) . '" class="wpcr-ico" data-tip="' . esc_attr__( 'Edit entrant', 'opcion5-sports-event-registration' ) . '">✎</a>' 284 284 . '<button class="wpcr-icon-btn wpcr-pay"' 285 285 . ' data-id="' . esc_attr( $p['id'] ) . '"' 286 286 . ' data-name="' . esc_attr( $full_name ) . '"' 287 287 . ' data-email="' . esc_attr( $p['email'] ) . '"' 288 . ' data-tip="' . esc_attr__( 'Pa gos', 'opcion5-sports-event-registration' ) . '">💳</button>'289 . '<button class="wpcr-ico wpcr-invite" data-id="' . esc_attr( $p['id'] ) . '" data-tip="' . esc_attr__( 'Invit ar', 'opcion5-sports-event-registration' ) . '">🟢</button>'288 . ' data-tip="' . esc_attr__( 'Payments', 'opcion5-sports-event-registration' ) . '">💳</button>' 289 . '<button class="wpcr-ico wpcr-invite" data-id="' . esc_attr( $p['id'] ) . '" data-tip="' . esc_attr__( 'Invite', 'opcion5-sports-event-registration' ) . '">🟢</button>' 290 290 . wp_kses_post( self::get_row_actions_html( $p ) ) 291 . '<button class="wpcr-ico wpcr-delete" data-id="' . esc_attr( $p['id'] ) . '" data-tip="' . esc_attr__( ' Eliminar participante', 'opcion5-sports-event-registration' ) . '" style="color:#d33">🗑</button>'291 . '<button class="wpcr-ico wpcr-delete" data-id="' . esc_attr( $p['id'] ) . '" data-tip="' . esc_attr__( 'Delete entrant', 'opcion5-sports-event-registration' ) . '" style="color:#d33">🗑</button>' 292 292 . '</td>' 293 293 . '</tr>'; -
opcion5-sports-event-registration/trunk/admin/events/tabs/emails.php
r3642215 r3645531 11 11 <!-- Email inscripción recibida --> 12 12 <tr> 13 <th> Email inscripción recibida</th>13 <th><?php esc_html_e( 'Registration received email', 'opcion5-sports-event-registration' ); ?></th> 14 14 <td> 15 15 <?php $ins_enabled = $event["wpcr_mail_ins_enabled"] ?? 0; ?> … … 20 20 </label> 21 21 22 <p><strong> Asunto email</strong><br>22 <p><strong><?php esc_html_e( 'Email subject', 'opcion5-sports-event-registration' ); ?></strong><br> 23 23 <input type="text" name="wpcr_mail_ins_subject" class="regular-text" 24 24 value="<?php echo esc_attr( $event['wpcr_mail_ins_subject'] ?? 'Inscripción recibida - {nombre_evento}' ); ?>"> 25 25 </p> 26 26 27 <p><strong> Contenido del email</strong></p>27 <p><strong><?php esc_html_e( 'Email content', 'opcion5-sports-event-registration' ); ?></strong></p> 28 28 <?php 29 29 $body = $event['wpcr_mail_ins_body'] ?? … … 47 47 <!-- Email de resultado provisional en meta --> 48 48 <tr> 49 <th> Email de resultado en meta</th>49 <th><?php esc_html_e( 'Finish line result email', 'opcion5-sports-event-registration' ); ?></th> 50 50 <td> 51 51 <?php $res_enabled = $event['result_mail_enabled'] ?? 0; ?> … … 67 67 <?php endif; ?> 68 68 69 <p><strong> Asunto email</strong><br>69 <p><strong><?php esc_html_e( 'Email subject', 'opcion5-sports-event-registration' ); ?></strong><br> 70 70 <input type="text" name="result_mail_subject" class="regular-text" 71 71 value="<?php echo esc_attr( $event['result_mail_subject'] ?? '🏁 Tu resultado provisional - {nombre_evento}' ); ?>"> 72 72 </p> 73 73 74 <p><strong> Contenido del email</strong></p>74 <p><strong><?php esc_html_e( 'Email content', 'opcion5-sports-event-registration' ); ?></strong></p> 75 75 <?php 76 76 $res_body = $event['result_mail_body'] ?: … … 107 107 </label> 108 108 109 <p><strong> Días después del registro para avisar:</strong><br>109 <p><strong><?php esc_html_e( 'Days after registration to send the reminder:', 'opcion5-sports-event-registration' ); ?></strong><br> 110 110 <input type="number" name="wpcr_mail_reminder_days" min="0" 111 111 style="width:80px" … … 114 114 </p> 115 115 116 <p><strong> Plantilla recordatorio</strong></p>116 <p><strong><?php esc_html_e( 'Reminder template', 'opcion5-sports-event-registration' ); ?></strong></p> 117 117 <?php 118 118 $rem = $event['wpcr_mail_reminder_body'] ?? … … 145 145 <br><br> 146 146 147 <label> Días después de registrarse:</label>147 <label><?php esc_html_e( 'Days after registering:', 'opcion5-sports-event-registration' ); ?></label> 148 148 <input type="number" name="reminder_days" 149 149 value="<?php echo esc_attr( $event["reminder_days"] ?? 2 ); ?>" … … 151 151 <p><small>Se enviará un email si el usuario no ha realizado el pago.</small></p> 152 152 153 <p><strong> Contenido del email</strong></p>153 <p><strong><?php esc_html_e( 'Email content', 'opcion5-sports-event-registration' ); ?></strong></p> 154 154 <?php 155 155 wp_editor( … … 182 182 <br><br> 183 183 184 <label> Días antes del cierre del cupo:</label>184 <label><?php esc_html_e( 'Days before the quota closes:', 'opcion5-sports-event-registration' ); ?></label> 185 185 <input type="number" name="last_call_days" 186 186 value="<?php echo esc_attr( $event["last_call_days"] ?? 1 ); ?>" … … 188 188 <p><small>Se enviará como aviso final de urgencia.</small></p> 189 189 190 <p><strong> Contenido del email</strong></p>190 <p><strong><?php esc_html_e( 'Email content', 'opcion5-sports-event-registration' ); ?></strong></p> 191 191 <?php 192 192 wp_editor( … … 217 217 218 218 <ul class="wpcr-side-list"> 219 <li><strong>{nombre_evento}</strong> - nombre del evento</li>220 <li><strong>{fecha_evento}</strong> - fecha del evento</li>221 <li><strong>{precio}</strong> - precio actual con IVA</li>222 <li><strong>{nombre}</strong> - nombre del participante</li>223 <li><strong>{apellidos}</strong> - apellidos del participante</li>224 <li><strong>{dni}</strong> - documento identificativo</li>225 <li><strong>{fecha_inscripcion}</strong> - fecha y hora de registro</li>226 <li><strong>{url_pago}</strong> - enlace directo al pago</li>219 <li><strong>{nombre_evento}</strong> <?php esc_html_e( '- event name', 'opcion5-sports-event-registration' ); ?></li> 220 <li><strong>{fecha_evento}</strong> <?php esc_html_e( '- event date', 'opcion5-sports-event-registration' ); ?></li> 221 <li><strong>{precio}</strong> <?php esc_html_e( '- current price including VAT', 'opcion5-sports-event-registration' ); ?></li> 222 <li><strong>{nombre}</strong> <?php esc_html_e( '- entrant first name', 'opcion5-sports-event-registration' ); ?></li> 223 <li><strong>{apellidos}</strong> <?php esc_html_e( '- entrant surname', 'opcion5-sports-event-registration' ); ?></li> 224 <li><strong>{dni}</strong> <?php esc_html_e( '- ID number', 'opcion5-sports-event-registration' ); ?></li> 225 <li><strong>{fecha_inscripcion}</strong> <?php esc_html_e( '- registration date and time', 'opcion5-sports-event-registration' ); ?></li> 226 <li><strong>{url_pago}</strong> <?php esc_html_e( '- direct payment link', 'opcion5-sports-event-registration' ); ?></li> 227 227 <?php if ( wpcr_is_addon_active( 'wpcr-checkin' ) ) : ?> 228 228 <li><strong>{qr_entrega}</strong> - QR para recoger el dorsal (addon Entrega de dorsales). Si no lo colocas, se añade solo al final del email de confirmación.</li> … … 232 232 <h3 class="wpcr-side-title" style="margin-top:18px;">Solo email de resultado</h3> 233 233 <ul class="wpcr-side-list"> 234 <li><strong>{tiempo}</strong> - tiempo empleado</li>235 <li><strong>{dorsal}</strong> - dorsal del corredor</li>236 <li><strong>{pos_general}</strong> - posición general provisional</li>237 <li><strong>{pos_categoria}</strong> - posición en su categoría</li>238 <li><strong>{pos_genero}</strong> - posición por género</li>239 <li><strong>{categoria}</strong> - nombre de la categoría</li>240 <li><strong>{url_clasificaciones}</strong> - enlace a la pestaña de clasificaciones de la página pública del evento</li>234 <li><strong>{tiempo}</strong> <?php esc_html_e( '- finishing time', 'opcion5-sports-event-registration' ); ?></li> 235 <li><strong>{dorsal}</strong> <?php esc_html_e( '- entrant bib number', 'opcion5-sports-event-registration' ); ?></li> 236 <li><strong>{pos_general}</strong> <?php esc_html_e( '- provisional overall position', 'opcion5-sports-event-registration' ); ?></li> 237 <li><strong>{pos_categoria}</strong> <?php esc_html_e( '- position in their category', 'opcion5-sports-event-registration' ); ?></li> 238 <li><strong>{pos_genero}</strong> <?php esc_html_e( '- position by gender', 'opcion5-sports-event-registration' ); ?></li> 239 <li><strong>{categoria}</strong> <?php esc_html_e( '- category name', 'opcion5-sports-event-registration' ); ?></li> 240 <li><strong>{url_clasificaciones}</strong> <?php esc_html_e( '- link to the standings tab of the public event page', 'opcion5-sports-event-registration' ); ?></li> 241 241 <li><strong>{clasificacion_local}</strong> - línea con la posición en la clasificación local (solo se rellena si el corredor es local y el evento tiene activada esa clasificación; si no, queda vacío)</li> 242 242 </ul> -
opcion5-sports-event-registration/trunk/admin/events/tabs/general.php
r3642215 r3645531 11 11 <table class="form-table"> 12 12 <tr> 13 <th colspan="2"><h3 style="margin:0;">⚙️ Datos principales del evento</h3></th>13 <th colspan="2"><h3 style="margin:0;">⚙️ <?php esc_html_e( 'Main event details', 'opcion5-sports-event-registration' ); ?></h3></th> 14 14 </tr> 15 15 <tr> … … 44 44 45 45 <tr> 46 <th><label for="wpcr-description"> Descripción</label></th>46 <th><label for="wpcr-description"><?php esc_html_e( 'Description', 'opcion5-sports-event-registration' ); ?></label></th> 47 47 <td> 48 48 <textarea id="wpcr-description" name="description" rows="3" class="large-text"><?php … … 61 61 <td> 62 62 <select id="wpcr-nationality" name="nationality" style="width:260px;"> 63 <option value="ES" <?php selected($currentNat,'ES'); ?>> España</option>63 <option value="ES" <?php selected($currentNat,'ES'); ?>><?php esc_html_e( 'Spain', 'opcion5-sports-event-registration' ); ?></option> 64 64 <option value="OTRA" <?php echo $isOther?'selected':''; ?>>Otra (indicar)</option> 65 65 </select> … … 74 74 <!-- ░░░ PROVINCIA ░░░ --> 75 75 <tr id="row-provincia"> 76 <th><label for="wpcr-provincia"> Provincia</label></th>76 <th><label for="wpcr-provincia"><?php esc_html_e( 'Province', 'opcion5-sports-event-registration' ); ?></label></th> 77 77 <td> 78 78 <select id="wpcr-provincia" name="provincia" style="width:260px;"> … … 127 127 <!-- LOCALIDAD --> 128 128 <tr> 129 <th><label for="wpcr-localidad"> Localidad</label></th>129 <th><label for="wpcr-localidad"><?php esc_html_e( 'Town', 'opcion5-sports-event-registration' ); ?></label></th> 130 130 <td> 131 131 <input type="text" id="wpcr-localidad" name="localidad" … … 165 165 166 166 <tr> 167 <th> Estado</th>167 <th><?php esc_html_e( 'Status', 'opcion5-sports-event-registration' ); ?></th> 168 168 <td><label><input type="checkbox" name="status" value="1" 169 169 <?php checked($event["status"],1); ?>> Activo</label></td> … … 278 278 <div class="wpcr-poster-box"> 279 279 280 <h3 class="wpcr-poster-title">📌 Cartel del evento</h3>281 <p class="wpcr-poster-desc"> Formatos recomendados: JPG o PNG — Máx 1MB</p>280 <h3 class="wpcr-poster-title">📌 <?php esc_html_e( 'Event poster', 'opcion5-sports-event-registration' ); ?></h3> 281 <p class="wpcr-poster-desc"><?php esc_html_e( 'Recommended formats: JPG or PNG — max. 1MB', 'opcion5-sports-event-registration' ); ?></p> 282 282 283 283 <!-- PREVIEW --> … … 294 294 295 295 <label class="wpcr-upload-btn"> 296 <span>📁 Seleccionar archivo</span>296 <span>📁 <?php esc_html_e( 'Choose file', 'opcion5-sports-event-registration' ); ?></span> 297 297 <input type="file" id="poster_file" name="poster_file" accept="image/*"> 298 298 </label> -
opcion5-sports-event-registration/trunk/admin/events/tabs/options.php
r3642215 r3645531 3 3 TAB OPCIONES 4 4 =============================== --> 5 <h3>🛠 Opciones del evento</h3>5 <h3>🛠 <?php esc_html_e( 'Event options', 'opcion5-sports-event-registration' ); ?></h3> 6 6 7 7 <table class="form-table"> … … 11 11 ================================ --> 12 12 <tr> 13 <th> Distancia de la prueba (km)</th>13 <th><?php esc_html_e( 'Race distance (km)', 'opcion5-sports-event-registration' ); ?></th> 14 14 <td> 15 15 <input type="number" name="distance_km" min="0" step="0.01" … … 30 30 ================================ --> 31 31 <tr> 32 <th> Límite de participantes</th>32 <th><?php esc_html_e( 'Entrant limit', 'opcion5-sports-event-registration' ); ?></th> 33 33 <td> 34 34 <label> … … 48 48 ================================ --> 49 49 <tr> 50 <th> Modalidad parejas</th>50 <th><?php esc_html_e( 'Pair registration', 'opcion5-sports-event-registration' ); ?></th> 51 51 <td> 52 52 <label> … … 63 63 <?php echo esc_attr( empty( $event['pairs_enabled'] ) ? 'display:none;' : '' ); ?>"> 64 64 65 <p style="margin:0 0 6px;"><strong> Modalidades de pareja disponibles:</strong></p>65 <p style="margin:0 0 6px;"><strong><?php esc_html_e( 'Pair categories available:', 'opcion5-sports-event-registration' ); ?></strong></p> 66 66 <label style="display:inline-block;margin-right:16px;"> 67 67 <input type="checkbox" name="pair_categories[]" value="male" … … 80 80 </label> 81 81 82 <p style="margin:14px 0 4px;"><strong> Cupo de inscripciones para parejas</strong> (número de parejas, cada una son 2 dorsales; 0 = sin límite):</p>82 <p style="margin:14px 0 4px;"><strong><?php esc_html_e( 'Pair registration quota', 'opcion5-sports-event-registration' ); ?></strong> (número de parejas, cada una son 2 dorsales; 0 = sin límite):</p> 83 83 <input type="number" name="pairs_max_couples" min="0" 84 84 value="<?php echo (int) ( $event['pairs_max_couples'] ?? 0 ); ?>" … … 113 113 ================================ --> 114 114 <tr> 115 <th> Bloqueo / lista de espera</th>115 <th><?php esc_html_e( 'Cut-off / waiting list', 'opcion5-sports-event-registration' ); ?></th> 116 116 <td> 117 117 … … 147 147 148 148 <tr> 149 <th colspan="3"><h3 style="margin:0;">📝 Personalizaciones</h3></th>149 <th colspan="3"><h3 style="margin:0;">📝 <?php esc_html_e( 'Customisations', 'opcion5-sports-event-registration' ); ?></h3></th> 150 150 </tr> 151 151 <?php if ( wpcr_is_addon_active( 'wpcr-participant-area' ) ) : ?> 152 152 <tr> 153 <th> Fondo del diploma</th>153 <th><?php esc_html_e( 'Certificate background', 'opcion5-sports-event-registration' ); ?></th> 154 154 <td> 155 155 <?php … … 161 161 <img src="<?php echo esc_url( $diploma_bg_url ); ?>" style="max-width:320px;border:1px solid #ddd;border-radius:6px;display:block;"> 162 162 </div> 163 <button type="button" class="button" id="wpcr-diploma-bg-select">🖼 Elegir imagen de fondo</button>164 <button type="button" class="button" id="wpcr-diploma-bg-remove" style="<?php echo $diploma_bg_url ? '' : 'display:none;'; ?>">🗑 Quitar</button>163 <button type="button" class="button" id="wpcr-diploma-bg-select">🖼 <?php esc_html_e( 'Choose background image', 'opcion5-sports-event-registration' ); ?></button> 164 <button type="button" class="button" id="wpcr-diploma-bg-remove" style="<?php echo $diploma_bg_url ? '' : 'display:none;'; ?>">🗑 <?php esc_html_e( 'Remove', 'opcion5-sports-event-registration' ); ?></button> 165 165 <p style="margin-top:8px;padding:8px 12px;background:#f0f4ff;border-left:3px solid #0073aa;font-size:13px;color:#333;"> 166 166 Se usa como fondo del diploma de participación descargable desde el área privada del corredor. 167 <strong> Medida recomendada: 1754 × 1240 px</strong> (horizontal, formato JPG o PNG). Si no subes167 <strong><?php esc_html_e( 'Recommended size: 1754 × 1240 px', 'opcion5-sports-event-registration' ); ?></strong> (horizontal, formato JPG o PNG). Si no subes 168 168 ninguna, se usa un diseño por defecto. 169 169 </p> … … 196 196 <?php endif; ?> 197 197 <tr> 198 <th> Formulario inscripción</th>198 <th><?php esc_html_e( 'Registration form', 'opcion5-sports-event-registration' ); ?></th> 199 199 <td> 200 200 <select name="form_template_id"> 201 <option value="0"> Formulario estándar</option>201 <option value="0"><?php esc_html_e( 'Standard form', 'opcion5-sports-event-registration' ); ?></option> 202 202 <?php foreach ($forms as $f): ?> 203 203 <option value="<?php echo (int)$f["id"]; ?>" … … 218 218 <td> 219 219 <select name="category_set_id"> 220 <option value="0"> — Sin asignar —</option>220 <option value="0"><?php esc_html_e( '— Not assigned —', 'opcion5-sports-event-registration' ); ?></option> 221 221 <?php foreach ($categories as $c): ?> 222 222 <option value="<?php echo (int)$c["id"]; ?>" … … 238 238 ================================ --> 239 239 <tr> 240 <th> Seleccionar talla</th>240 <th><?php esc_html_e( 'Select size', 'opcion5-sports-event-registration' ); ?></th> 241 241 <td> 242 242 … … 255 255 <?php echo esc_attr( empty($event['tallas_enabled']) ? 'display:none;' : '' ); ?>"> 256 256 257 <label><strong> Etiqueta campo:</strong></label><br>257 <label><strong><?php esc_html_e( 'Field label:', 'opcion5-sports-event-registration' ); ?></strong></label><br> 258 258 <input type="text" name="tallas_label" 259 259 value="<?php echo esc_attr($event['tallas_label'] ?? 'Selecciona tu talla'); ?>" 260 260 style="width:260px;margin-bottom:8px;"> 261 261 262 <p><strong> Tallas disponibles:</strong></p>262 <p><strong><?php esc_html_e( 'Sizes available:', 'opcion5-sports-event-registration' ); ?></strong></p> 263 263 264 264 <?php … … 308 308 <tr> 309 309 <th colspan="2" style="padding-top:25px;"> 310 <h3 style="margin:0;"> Validación de DNI</h3>310 <h3 style="margin:0;"><?php esc_html_e( 'ID number validation', 'opcion5-sports-event-registration' ); ?></h3> 311 311 </th> 312 312 </tr> 313 313 314 314 <tr> 315 <th> Validar formato DNI/NIE español</th>315 <th><?php esc_html_e( 'Check the Spanish ID/NIE format', 'opcion5-sports-event-registration' ); ?></th> 316 316 <td> 317 317 <label> … … 336 336 <tr> 337 337 <th colspan="2" style="padding-top:25px;"> 338 <h3 style="margin:0;"> Privacidad del evento</h3>338 <h3 style="margin:0;"><?php esc_html_e( 'Event privacy', 'opcion5-sports-event-registration' ); ?></h3> 339 339 </th> 340 340 </tr> … … 356 356 ?> 357 357 <tr> 358 <th> Activar política de privacidad</th>358 <th><?php esc_html_e( 'Enable privacy policy', 'opcion5-sports-event-registration' ); ?></th> 359 359 <td> 360 360 <label> 361 361 <input type="checkbox" id="wpcr-privacy-enabled" name="privacy_enabled" value="1" 362 362 <?php checked( $event['privacy_enabled'] ?? 0 , 1 ); ?>> 363 Activar política de privacidad363 <?php esc_html_e( 'Enable privacy policy', 'opcion5-sports-event-registration' ); ?> 364 364 </label> 365 365 <p style="font-size:13px;color:#777;margin-top:6px;"> … … 371 371 372 372 <tr class="wpcr-privacy-row"> 373 <th> Texto de la política<br><small>(HTML permitido)</small></th>373 <th><?php esc_html_e( 'Policy text', 'opcion5-sports-event-registration' ); ?><br><small><?php esc_html_e( '(HTML allowed)', 'opcion5-sports-event-registration' ); ?></small></th> 374 374 <td> 375 375 <?php if ( $org_has ) : ?> … … 381 381 <?php else : ?> 382 382 <p style="font-size:13px;color:#b45309;margin:0 0 6px;"> 383 ⚠ No hay datos del organizador en la pestaña <strong> Info técnica</strong>.383 ⚠ No hay datos del organizador en la pestaña <strong><?php esc_html_e( 'Race info', 'opcion5-sports-event-registration' ); ?></strong>. 384 384 Complétalos allí y pulsa “Regenerar” para que aparezcan como responsable del tratamiento. 385 385 </p> … … 392 392 393 393 <p style="margin-top:8px;"> 394 <button type="button" class="button" id="wpcr-privacy-regen">↻ Regenerar con datos del organizador</button>394 <button type="button" class="button" id="wpcr-privacy-regen">↻ <?php esc_html_e( 'Regenerate with the organizer details', 'opcion5-sports-event-registration' ); ?></button> 395 395 <span style="font-size:12px;color:#777;margin-left:8px;"> 396 396 Sustituye el texto por el modelo por defecto (perderás los cambios manuales). … … 432 432 433 433 <tr class="wpcr-privacy-row"> 434 <th> URL documento completo<br><small>(opcional)</small></th>434 <th><?php esc_html_e( 'Full document URL', 'opcion5-sports-event-registration' ); ?><br><small><?php esc_html_e( '(optional)', 'opcion5-sports-event-registration' ); ?></small></th> 435 435 <td> 436 436 <input type="url" … … 451 451 ================================ --> 452 452 <tr> 453 <th> Privacidad en el listado de inscritos público</th>453 <th><?php esc_html_e( 'Privacy in the public entrants list', 'opcion5-sports-event-registration' ); ?></th> 454 454 <td> 455 455 <label> -
opcion5-sports-event-registration/trunk/admin/events/tabs/participants.php
r3642215 r3645531 3 3 TAB PARTICIPANTES 4 4 =============================== --> 5 <h2 style="margin-top:0;">👥 Participantes del evento</h2>5 <h2 style="margin-top:0;">👥 <?php esc_html_e( 'Event entrants', 'opcion5-sports-event-registration' ); ?></h2> 6 6 7 7 <div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:16px;"> 8 8 <a id="wpcr-add-user" class="button button-primary" 9 9 href="<?php echo esc_url( admin_url( 'admin.php?page=wpcr-add-participant&event=' . rawurlencode( (string) ( $event['public_id'] ?? '' ) ) ) ); ?>"> 10 + Añadir participante10 + <?php esc_html_e( 'Add entrant', 'opcion5-sports-event-registration' ); ?> 11 11 </a> 12 <button type="button" id="wpcr-recalc-categories" class="button" style="background:#f0f0f0;">🔄 Recalcular categorías</button>12 <button type="button" id="wpcr-recalc-categories" class="button" style="background:#f0f0f0;">🔄 <?php esc_html_e( 'Recalculate categories', 'opcion5-sports-event-registration' ); ?></button> 13 13 <span id="wpcr-recalc-status" style="font-size:13px;font-weight:600;"></span> 14 14 -
opcion5-sports-event-registration/trunk/admin/events/tabs/prices.php
r3642215 r3645531 12 12 ?> 13 13 14 <h2 style="margin-top:0;">💶 Configuración de precios</h2>15 <p> Elige el modo de precio y configura las tarifas.</p>14 <h2 style="margin-top:0;">💶 <?php esc_html_e( 'Price settings', 'opcion5-sports-event-registration' ); ?></h2> 15 <p><?php esc_html_e( 'Choose the pricing mode and set the fees.', 'opcion5-sports-event-registration' ); ?></p> 16 16 17 17 <table class="form-table" style="max-width:900px;"> … … 21 21 ================================ --> 22 22 <tr> 23 <th> Modo de precio</th>23 <th><?php esc_html_e( 'Pricing mode', 'opcion5-sports-event-registration' ); ?></th> 24 24 <td> 25 25 <?php … … 31 31 <input type="radio" name="price_mode" value="fixed" 32 32 <?php checked($price_mode,'fixed'); ?>> 33 Precio fijo33 <?php esc_html_e( 'Fixed price', 'opcion5-sports-event-registration' ); ?> 34 34 </label><br> 35 35 … … 37 37 <input type="radio" name="price_mode" value="ranges" 38 38 <?php checked($price_mode,'ranges'); ?>> 39 Precio por franjas39 <?php esc_html_e( 'Price by date', 'opcion5-sports-event-registration' ); ?> 40 40 </label><br> 41 41 … … 43 43 <input type="radio" name="price_mode" value="free" 44 44 <?php checked($price_mode,'free'); ?>> 45 Gratis45 <?php esc_html_e( 'Free', 'opcion5-sports-event-registration' ); ?> 46 46 </label> 47 47 48 48 <div id="wpcr-price-fixed" 49 49 style="margin-top:10px; <?php echo esc_attr( ($price_mode==='fixed')?'':'display:none;' ); ?>"> 50 <label> Importe (€):</label>50 <label><?php esc_html_e( 'Amount (€):', 'opcion5-sports-event-registration' ); ?></label> 51 51 <input type="number" step="0.01" name="fixed_price" 52 52 value="<?php echo esc_attr($fixed_price); ?>" … … 54 54 55 55 <p style="font-size:12px;color:#666;margin-top:6px;"> 56 Si seleccionas Gratis, este importe se ignorará.56 <?php esc_html_e( 'If you choose Free, this amount is ignored.', 'opcion5-sports-event-registration' ); ?> 57 57 </p> 58 58 </div> … … 65 65 <tr id="wpcr-prices-ranges-row" 66 66 style="<?php echo esc_attr( ($price_mode==='ranges')?'':'display:none;' ); ?>"> 67 <th> Franjas de precio</th>67 <th><?php esc_html_e( 'Price periods', 'opcion5-sports-event-registration' ); ?></th> 68 68 <td> 69 69 70 <p> Configura diferentes precios según el rango de fechas.</p>70 <p><?php esc_html_e( 'Set different prices depending on the date range.', 'opcion5-sports-event-registration' ); ?></p> 71 71 72 72 <table class="widefat" style="max-width:750px;"> 73 73 <thead> 74 74 <tr> 75 <th> Desde</th>76 <th> Hasta</th>77 <th> Precio (€)</th>75 <th><?php esc_html_e( 'From', 'opcion5-sports-event-registration' ); ?></th> 76 <th><?php esc_html_e( 'To', 'opcion5-sports-event-registration' ); ?></th> 77 <th><?php esc_html_e( 'Price (€)', 'opcion5-sports-event-registration' ); ?></th> 78 78 <th></th> 79 79 </tr> … … 101 101 <button type="button" 102 102 class="button wpcr-remove"> 103 Eliminar103 <?php esc_html_e( 'Remove', 'opcion5-sports-event-registration' ); ?> 104 104 </button> 105 105 </td> … … 113 113 class="button button-primary" 114 114 style="margin-top:8px;"> 115 + Añadir franja115 <?php esc_html_e( '+ Add period', 'opcion5-sports-event-registration' ); ?> 116 116 </button> 117 117 … … 123 123 ================================ --> 124 124 <tr> 125 <th> Extras / Opciones adicionales</th>125 <th><?php esc_html_e( 'Extras / Optional add-ons', 'opcion5-sports-event-registration' ); ?></th> 126 126 <td> 127 127 128 <p> Añade suplementos o descuentos opcionales. El precio puede ser negativo.</p>128 <p><?php esc_html_e( 'Add optional extras or discounts. The price can be negative.', 'opcion5-sports-event-registration' ); ?></p> 129 129 130 130 <table class="widefat" style="max-width:750px;margin-top:10px;"> 131 131 <thead> 132 132 <tr> 133 <th> Título</th>134 <th> Precio (€)</th>133 <th><?php esc_html_e( 'Title', 'opcion5-sports-event-registration' ); ?></th> 134 <th><?php esc_html_e( 'Price (€)', 'opcion5-sports-event-registration' ); ?></th> 135 135 <th>Tipo</th> 136 136 <th></th> … … 161 161 <button type="button" 162 162 class="button wpcr-remove-extra"> 163 Eliminar163 <?php esc_html_e( 'Remove', 'opcion5-sports-event-registration' ); ?> 164 164 </button> 165 165 </td> … … 172 172 id="wpcr-add-extra" 173 173 class="button"> 174 + Añadir extra174 <?php esc_html_e( '+ Add extra', 'opcion5-sports-event-registration' ); ?> 175 175 </button> 176 176 -
opcion5-sports-event-registration/trunk/admin/events/tabs/tech.php
r3642215 r3645531 7 7 DATOS DEL ORGANIZADOR 8 8 =============================== --> 9 <h2 style="margin-top:0;">👤 Datos del organizador</h2>9 <h2 style="margin-top:0;">👤 <?php esc_html_e( 'Organizer details', 'opcion5-sports-event-registration' ); ?></h2> 10 10 <p class="description"> 11 Información de contacto del organizador del evento11 <?php esc_html_e( 'Contact details of the event organizer', 'opcion5-sports-event-registration' ); ?> 12 12 </p> 13 13 … … 30 30 value="1" 31 31 <?php checked($org_name_pub); ?>> 32 Mostrar en la página pública32 <?php esc_html_e( 'Show on the public page', 'opcion5-sports-event-registration' ); ?> 33 33 </label> 34 34 </p> … … 52 52 value="1" 53 53 <?php checked($org_email_pub); ?>> 54 Mostrar en la página pública54 <?php esc_html_e( 'Show on the public page', 'opcion5-sports-event-registration' ); ?> 55 55 </label> 56 56 </p> … … 59 59 60 60 <tr> 61 <th><label for="wpcr-organizer-phone"> Teléfono de contacto</label></th>61 <th><label for="wpcr-organizer-phone"><?php esc_html_e( 'Contact phone', 'opcion5-sports-event-registration' ); ?></label></th> 62 62 <td> 63 63 <input type="text" … … 74 74 value="1" 75 75 <?php checked($org_phone_pub); ?>> 76 Mostrar en la página pública76 <?php esc_html_e( 'Show on the public page', 'opcion5-sports-event-registration' ); ?> 77 77 </label> 78 78 </p> … … 97 97 ]; 98 98 ?> 99 <h2 style="margin-top:30px;">📢 Canal de comunicación</h2>99 <h2 style="margin-top:30px;">📢 <?php esc_html_e( 'Communication channel', 'opcion5-sports-event-registration' ); ?></h2> 100 100 <p class="description"> 101 101 Enlaces a las redes sociales o web donde se publican las comunicaciones del evento. … … 135 135 </tr> 136 136 <tr> 137 <th> Apertura de inscripciones</th>138 <td><?php echo ! empty( $event['reg_open'] ) && $event['reg_open'] !== '0000-00-00 00:00:00' ? esc_html( date_i18n( 'd/m/Y H:i', strtotime( $event['reg_open'] )) ) : '<em style="color:#999;">Sin definir</em>'; ?></td>139 </tr> 140 <tr> 141 <th> Cierre de inscripciones</th>142 <td><?php echo ! empty( $event['reg_close'] ) && $event['reg_close'] !== '0000-00-00 00:00:00' ? esc_html( date_i18n( 'd/m/Y H:i', strtotime( $event['reg_close'] )) ) : '<em style="color:#999;">Sin definir</em>'; ?></td>137 <th><?php esc_html_e( 'Registration opens', 'opcion5-sports-event-registration' ); ?></th> 138 <td><?php echo ! empty( $event['reg_open'] ) && $event['reg_open'] !== '0000-00-00 00:00:00' ? esc_html( wpcr_format_datetime( $event['reg_open'] ) ) : '<em style="color:#999;">Sin definir</em>'; ?></td> 139 </tr> 140 <tr> 141 <th><?php esc_html_e( 'Registration closes', 'opcion5-sports-event-registration' ); ?></th> 142 <td><?php echo ! empty( $event['reg_close'] ) && $event['reg_close'] !== '0000-00-00 00:00:00' ? esc_html( wpcr_format_datetime( $event['reg_close'] ) ) : '<em style="color:#999;">Sin definir</em>'; ?></td> 143 143 </tr> 144 144 <tr> … … 189 189 OBSERVACIONES 190 190 =============================== --> 191 <h2 style="margin-top:30px;">📝 Observaciones</h2>191 <h2 style="margin-top:30px;">📝 <?php esc_html_e( 'Notes', 'opcion5-sports-event-registration' ); ?></h2> 192 192 <p class="description">Texto libre para cualquier información adicional que quieras mostrar en la ficha técnica pública (normativa, avituallamientos, recomendaciones, etc.).</p> 193 193 <textarea name="tech_observations" rows="5" style="width:100%;max-width:900px;"><?php echo esc_textarea( $event['tech_observations'] ?? '' ); ?></textarea> -
opcion5-sports-event-registration/trunk/admin/js/wpcr-admin.js
r3642215 r3645531 58 58 //------------------------------------------- 59 59 if (res.data && res.data.already_in_event) { 60 alert("⚠️ Este participante YA está inscrito en este evento.\n\nNo puedes añadirlo de nuevo.");60 alert("⚠️ " + wpcr_ajax.i18n.alreadyEntered); 61 61 return; 62 62 } -
opcion5-sports-event-registration/trunk/asset/admin/js/shared/save-event.js
r3642215 r3645531 12 12 13 13 function warnInvalidDistanceComma(){ 14 alert('⚠ El campo "Distancia de la prueba (km)" debe usar un PUNTO como separador decimal (ejemplo: 20.5), no una coma. Corrige el valor antes de guardar.');14 alert('⚠ ' + wpcrAdmin.i18n.decimalPoint); 15 15 } 16 16 … … 26 26 27 27 var btn = $(this); 28 btn.prop('disabled', true).text( 'Guardando...⏳');28 btn.prop('disabled', true).text(wpcrAdmin.i18n.saving + ' ⏳'); 29 29 30 30 var form = document.getElementById('wpcr-event-form'); … … 82 82 83 83 var btn = $(this); 84 btn.prop('disabled', true).text( 'Guardando...⏳');84 btn.prop('disabled', true).text(wpcrAdmin.i18n.saving + ' ⏳'); 85 85 86 86 var form = document.getElementById('wpcr-event-form'); -
opcion5-sports-event-registration/trunk/asset/admin/js/tabs/cobros.js
r3642215 r3645531 21 21 22 22 if (!id || !amount) { 23 alert( 'Indica un importe válido.');23 alert(wpcrAdmin.i18n.invalidAmount); 24 24 return; 25 25 } 26 26 27 27 // 🔒 Feedback inmediato 28 btn.prop('disabled', true).text( 'Procesando...⏳');28 btn.prop('disabled', true).text(wpcrAdmin.i18n.processing + ' ⏳'); 29 29 30 30 jQuery.post( … … 67 67 68 68 // 🔒 Feedback inmediato 69 btn.prop('disabled', true).text( 'Procesando...⏳');69 btn.prop('disabled', true).text(wpcrAdmin.i18n.processing + ' ⏳'); 70 70 71 71 jQuery.post( -
opcion5-sports-event-registration/trunk/asset/admin/js/tabs/participants.js
r3642215 r3645531 81 81 }) 82 82 .always(function(){ 83 $btn.prop('disabled', false).text('🔄 Recalcular categorías');83 $btn.prop('disabled', false).text('🔄 ' + wpcrAdmin.i18n.recalcCategories); 84 84 setTimeout(function(){ $status.text(''); }, 6000); 85 85 }); … … 141 141 jQuery('.wpcr-delete').off('click').on('click', function(e){ 142 142 e.preventDefault(); 143 if (!confirm( '¿Eliminar inscrito?')) return;143 if (!confirm(wpcrAdmin.i18n.deleteEntrant)) return; 144 144 const id = jQuery(this).data('id'); 145 145 jQuery.post(ajaxurl, { action: 'wpcr_delete_user', id, nonce: wpcrAdmin.nonce }, loadParticipants); -
opcion5-sports-event-registration/trunk/asset/wpcr-frontend.js
r3642215 r3645531 85 85 var validarDNIActivo = (window.wpcr_ajax && wpcr_ajax.validate_dni !== false); 86 86 if (validarDNIActivo && nationality === "ES" && !validarDNI(dni)) { 87 feedback.textContent = "⚠️ DNI/NIE no válido. Comprueba el número y la letra.";87 feedback.textContent = "⚠️ " + wpcr_ajax.i18n.invalidDni; 88 88 feedback.style.color = "red"; 89 89 return; … … 114 114 try { res = JSON.parse(raw); } 115 115 catch (e) { 116 feedback.textContent = "Error al comprobar el DNI. Inténtalo de nuevo.";116 feedback.textContent = wpcr_ajax.i18n.checkError; 117 117 feedback.style.color = "red"; 118 118 console.error("WPCR DNI: respuesta no válida del servidor:", raw); … … 124 124 var errMsg = (res && res.data && res.data.msg) 125 125 ? res.data.msg 126 : "Error al comprobar el DNI. Inténtalo de nuevo.";126 : wpcr_ajax.i18n.checkError; 127 127 feedback.textContent = "⚠️ " + errMsg; 128 128 feedback.style.color = "red"; … … 132 132 // Ya está inscrito en este evento 133 133 if (res.data && res.data.already_in_event) { 134 feedback.textContent = "⚠️ Este DNI ya está inscrito en esta prueba.";134 feedback.textContent = "⚠️ " + wpcr_ajax.i18n.alreadyIn; 135 135 feedback.style.color = "red"; 136 136 return; … … 169 169 var resumen = 170 170 "<div style='background:#f0fdf4;border:1px solid #86efac;border-radius:8px;padding:12px 14px;margin:10px 0;text-align:left;'>" + 171 "<div style='font-weight:bold;color:#166534;margin-bottom:6px;'>✓ Te hemos reconocido de inscripciones anteriores</div>" +171 "<div style='font-weight:bold;color:#166534;margin-bottom:6px;'>✓ " + wpcr_ajax.i18n.recognised + "</div>" + 172 172 "<div style='font-size:13px;color:#334155;line-height:1.7;'>" + 173 (masked.first_name ? "Nombre:<b>" + masked.first_name + " " + (masked.last_name || "") + "</b><br>" : "") +174 (masked.email ? "Email:<b>" + masked.email + "</b><br>" : "") +175 (masked.phone ? "Teléfono:<b>" + masked.phone + "</b><br>" : "") +176 (masked.localidad ? "Localidad:<b>" + masked.localidad + "</b>" : "") +173 (masked.first_name ? wpcr_ajax.i18n.labelName + " <b>" + masked.first_name + " " + (masked.last_name || "") + "</b><br>" : "") + 174 (masked.email ? wpcr_ajax.i18n.labelEmail + " <b>" + masked.email + "</b><br>" : "") + 175 (masked.phone ? wpcr_ajax.i18n.labelPhone + " <b>" + masked.phone + "</b><br>" : "") + 176 (masked.localidad ? wpcr_ajax.i18n.labelTown + " <b>" + masked.localidad + "</b>" : "") + 177 177 "</div></div>"; 178 178 179 179 feedback.innerHTML = 180 180 resumen + 181 "<button type='button' id='wpcr-load-data' style='padding:8px 14px;margin-right:10px;'> Son correctos, usar mis datos</button>" +182 "<button type='button' id='wpcr-reset-data' style='padding:8px 14px;'> Han cambiado, actualizarlos</button>";181 "<button type='button' id='wpcr-load-data' style='padding:8px 14px;margin-right:10px;'>" + wpcr_ajax.i18n.useMyData + "</button>" + 182 "<button type='button' id='wpcr-reset-data' style='padding:8px 14px;'>" + wpcr_ajax.i18n.dataChanged + "</button>"; 183 183 184 184 var btnLoad = document.getElementById("wpcr-load-data"); … … 197 197 198 198 feedback.innerHTML = 199 "<span style='color:green;font-weight:bold;'>✓ Usaremos tus datos guardados. Completa lo que falte (talla, etc.) y pulsa Enviar.</span>";199 "<span style='color:green;font-weight:bold;'>✓ " + wpcr_ajax.i18n.willUseSaved + "</span>"; 200 200 }; 201 201 } -
opcion5-sports-event-registration/trunk/cron/wpcr-cron-pairs.php
r3642215 r3645531 55 55 if ( ! is_email( $p['email'] ) ) continue; 56 56 57 $subject = 'Tu pareja no completó la inscripción - ' . $ev['name']; 57 $subject = sprintf( 58 /* translators: %s: event name */ 59 __( 'Your partner did not complete the registration - %s', 'opcion5-sports-event-registration' ), 60 $ev['name'] 61 ); 58 62 $body = ' 59 63 <div style="font-family:Arial,Helvetica,sans-serif;line-height:1.6;color:#0a2540;max-width:600px;margin:0 auto;"> 60 <h2 style="color:#0d47a1;">👥 Inscripción por parejas — ' . esc_html( $ev['name'] ) . '</h2> 61 <p>Hola <strong>' . esc_html( $p['first_name'] ) . '</strong>,</p> 62 <p>El plazo de inscripción de <strong>' . esc_html( $ev['name'] ) . '</strong> ha finalizado y tu pareja 63 (código <strong>' . esc_html( $p['pair_code'] ) . '</strong>) no llegó a completar su inscripción.</p> 64 <p><strong>Tu plaza sigue siendo válida:</strong> pasas a participar en la modalidad 65 <strong>individual</strong>.</p> 66 <p>Si crees que se trata de un error, contacta con la organización del evento.</p>' 64 <h2 style="color:#0d47a1;">👥 ' . sprintf( 65 /* translators: %s: event name */ 66 esc_html__( 'Pair registration — %s', 'opcion5-sports-event-registration' ), 67 esc_html( $ev['name'] ) 68 ) . '</h2> 69 <p>' . sprintf( 70 /* translators: %s: participant first name */ 71 esc_html__( 'Hi %s,', 'opcion5-sports-event-registration' ), 72 '<strong>' . esc_html( $p['first_name'] ) . '</strong>' 73 ) . '</p> 74 <p>' . sprintf( 75 /* translators: 1: event name, 2: pair code */ 76 esc_html__( 'Registration for %1$s has closed and your partner (code %2$s) did not complete theirs.', 'opcion5-sports-event-registration' ), 77 '<strong>' . esc_html( $ev['name'] ) . '</strong>', 78 '<strong>' . esc_html( $p['pair_code'] ) . '</strong>' 79 ) . '</p> 80 <p>' . sprintf( 81 /* translators: 1: "Your place is still valid" in bold, 2: the word "individual" in bold */ 82 esc_html__( '%1$s you now take part in the %2$s category.', 'opcion5-sports-event-registration' ), 83 '<strong>' . esc_html__( 'Your place is still valid:', 'opcion5-sports-event-registration' ) . '</strong>', 84 '<strong>' . esc_html__( 'individual', 'opcion5-sports-event-registration' ) . '</strong>' 85 ) . '</p> 86 <p>' . esc_html__( 'If you think this is a mistake, please contact the event organizer.', 'opcion5-sports-event-registration' ) . '</p>' 67 87 . ( function_exists( 'wpcr_email_footer' ) ? wpcr_email_footer() : '' ) . ' 68 88 </div>'; -
opcion5-sports-event-registration/trunk/includes/class-wpcr-demo-data.php
r3642215 r3645531 74 74 ] ); 75 75 $price_extras = wp_json_encode( [ 76 [ 'label' => 'Camiseta técnica', 'price' => 5, 'type' => 'checkbox' ],77 [ 'label' => 'Maillot oficial', 'price' => 25, 'type' => 'checkbox' ],76 [ 'label' => __( 'Technical T-shirt', 'opcion5-sports-event-registration' ), 'price' => 5, 'type' => 'checkbox' ], 77 [ 'label' => __( 'Official jersey', 'opcion5-sports-event-registration' ), 'price' => 25, 'type' => 'checkbox' ], 78 78 ] ); 79 79 … … 86 86 // 6) Crear el evento demo (salida a las 09:00 del día de la prueba, cupo de 100 plazas) 87 87 $wpdb->insert( $events_table, [ 88 'name' => '🧪 Evento de ejemplo',88 'name' => '🧪 ' . __( 'Sample event', 'opcion5-sports-event-registration' ), 89 89 'description' => 'Este es un evento de ejemplo con inscritos, modalidad, categorías y precios ya rellenos para que pruebes el plugin: formulario de inscripción, gestión de participantes, precios y correos. Puedes borrarlo cuando quieras desde "Resetear datos demo".', 90 90 'event_date' => $event_date, … … 117 117 $event_id = (int) $wpdb->insert_id; 118 118 if ( ! $event_id ) { 119 return [ 'ok' => false, 'msg' => 'No se pudo crear el evento de ejemplo.'];119 return [ 'ok' => false, 'msg' => __( 'The sample event could not be created.', 'opcion5-sports-event-registration' ) ]; 120 120 } 121 121 … … 143 143 update_option( 'wpcr_demo_category_set_id', $category_set_id, false ); 144 144 145 return [ 'ok' => true, 'msg' => 'Datos de ejemplo instalados correctamente.', 'event_id' => $event_id ];145 return [ 'ok' => true, 'msg' => __( 'Sample data installed successfully.', 'opcion5-sports-event-registration' ), 'event_id' => $event_id ]; 146 146 } 147 147 … … 154 154 delete_option( self::OPTION_EVENT_ID ); 155 155 self::cleanup_orphan_demo_category_set(); 156 return [ 'ok' => true, 'msg' => 'No había datos de ejemplo instalados.'];156 return [ 'ok' => true, 'msg' => __( 'There was no sample data installed.', 'opcion5-sports-event-registration' ) ]; 157 157 } 158 158 … … 164 164 self::cleanup_orphan_demo_modality(); 165 165 166 return [ 'ok' => true, 'msg' => 'Datos de ejemplo eliminados.'];166 return [ 'ok' => true, 'msg' => __( 'Sample data removed.', 'opcion5-sports-event-registration' ) ]; 167 167 } 168 168 … … 221 221 222 222 $wpdb->insert( $sets_table, [ 223 'name' => 'Categorías de ejemplo (por edad)',223 'name' => __( 'Sample categories (by age)', 'opcion5-sports-event-registration' ), 224 224 'type' => 'age', 225 225 ] ); -
opcion5-sports-event-registration/trunk/includes/class-wpcr-install.php
r3642215 r3645531 356 356 [ 357 357 'option' => 'wpcr_event_list_page_id', 358 'title' => __( 'Event os', 'opcion5-sports-event-registration' ),358 'title' => __( 'Events', 'opcion5-sports-event-registration' ), 359 359 'shortcode' => 'wpcr_event_list', 360 360 ], 361 361 [ 362 362 'option' => 'wpcr_event_page_id', 363 'title' => __( ' Inscripción', 'opcion5-sports-event-registration' ),363 'title' => __( 'Registration', 'opcion5-sports-event-registration' ), 364 364 'shortcode' => 'wpcr_event', 365 365 ], -
opcion5-sports-event-registration/trunk/includes/emails/class-wpcr-payment-emails.php
r3642215 r3645531 79 79 $subject = apply_filters( 80 80 'wpcr_payment_email_subject', 81 '✅ Pago confirmado – ' . $event_name, 81 '✅ ' . sprintf( 82 /* translators: %s: event name */ 83 __( 'Payment confirmed – %s', 'opcion5-sports-event-registration' ), 84 $event_name 85 ), 82 86 $payment, 83 87 $event, … … 95 99 <tr><td align='center'> 96 100 97 <h2 style='color:#003a99;margin-top:0;'>🎉 Pago confirmado</h2>101 <h2 style='color:#003a99;margin-top:0;'>🎉 " . esc_html__( 'Payment confirmed', 'opcion5-sports-event-registration' ) . "</h2> 98 102 99 103 <p style='font-size:16px;'> 100 Hola <strong>{$name}</strong>, 104 " . sprintf( 105 /* translators: %s: participant first name */ 106 esc_html__( 'Hi %s,', 'opcion5-sports-event-registration' ), 107 '<strong>' . $name . '</strong>' 108 ) . " 101 109 </p> 102 110 103 111 <p style='font-size:15px;'> 104 Tu inscripción en el evento: 112 " . esc_html__( 'Your registration for the event:', 'opcion5-sports-event-registration' ) . " 105 113 </p> 106 114 … … 108 116 109 117 <p style='font-size:15px;'> 110 <strong> Importe pagado:</strong> {$amount} €<br>111 <strong> Método de pago:</strong> {$method}118 <strong>" . esc_html__( 'Amount paid:', 'opcion5-sports-event-registration' ) . "</strong> {$amount} €<br> 119 <strong>" . esc_html__( 'Payment method:', 'opcion5-sports-event-registration' ) . "</strong> {$method} 112 120 </p> 113 121 … … 115 123 116 124 <p style='font-size:14px;color:#555;'> 117 ✅ Tu plaza ha quedado <strong>confirmada</strong>.<br> 118 Te esperamos el día del evento. 125 ✅ " . sprintf( 126 /* translators: %s: the word "confirmed", in bold */ 127 esc_html__( 'Your place is now %s.', 'opcion5-sports-event-registration' ), 128 '<strong>' . esc_html__( 'confirmed', 'opcion5-sports-event-registration' ) . '</strong>' 129 ) . "<br> 130 " . esc_html__( 'See you on the day of the event.', 'opcion5-sports-event-registration' ) . " 119 131 </p> 120 132 121 133 <p style='font-size:13px;color:#777;margin-top:25px;'> 122 Este email es automático, no respondas a este mensaje. 134 " . esc_html__( 'This is an automatic email, please do not reply to it.', 'opcion5-sports-event-registration' ) . " 123 135 </p> 124 136 … … 160 172 wpcr_mail( 161 173 $organizer_email, 162 '💳 Pago recibido – ' . $event_name, 163 "Se ha confirmado un pago de {$amount} € ({$method}) para el evento {$event_name}.", 174 '💳 ' . sprintf( 175 /* translators: %s: event name */ 176 __( 'Payment received – %s', 'opcion5-sports-event-registration' ), 177 $event_name 178 ), 179 sprintf( 180 /* translators: 1: amount with currency, 2: payment method, 3: event name */ 181 __( 'A payment of %1$s € (%2$s) has been confirmed for the event %3$s.', 'opcion5-sports-event-registration' ), 182 $amount, 183 $method, 184 $event_name 185 ), 164 186 $headers, 165 187 $event_name -
opcion5-sports-event-registration/trunk/includes/emails/class-wpcr-result-email.php
r3642215 r3645531 105 105 106 106 if ( $pos_local > 0 ) { 107 $gender_label = $gender === 'M' ? 'masculina' : 'femenina'; 108 $local_line = '🏠 Posición en la clasificación local ' . $gender_label . ': <b>' . $pos_local . '</b><br><br>'; 107 $gender_label = $gender === 'M' 108 ? __( "men's", 'opcion5-sports-event-registration' ) 109 : __( "women's", 'opcion5-sports-event-registration' ); 110 $local_line = '🏠 ' . sprintf( 111 /* translators: 1: gender of the local standings, 2: position */ 112 __( 'Position in the %1$s local standings: <b>%2$s</b>', 'opcion5-sports-event-registration' ), 113 $gender_label, 114 $pos_local 115 ) . '<br><br>'; 109 116 } 110 117 } … … 112 119 } 113 120 114 $subject = $event['result_mail_subject'] ?: '🏁 Tu resultado provisional - {nombre_evento}';121 $subject = $event['result_mail_subject'] ?: '🏁 ' . __( 'Your provisional result - {nombre_evento}', 'opcion5-sports-event-registration' ); 115 122 $body = $event['result_mail_body'] ?: self::default_body(); 116 123 … … 128 135 '{apellidos}' => trim( ( $participant['middle_name'] ?? '' ) . ' ' . ( $participant['last_name'] ?? '' ) ), 129 136 '{nombre_evento}' => $event['name'], 130 '{fecha_evento}' => ! empty( $event['event_date'] ) ? date_i18n( 'd/m/Y', strtotime( $event['event_date'] ) ) : '',137 '{fecha_evento}' => wpcr_format_date( $event['event_date'] ?? '' ), 131 138 '{dorsal}' => $result['dorsal'] ?: ( $participant['dorsal'] ?? '' ), 132 139 '{tiempo}' => $result['tiempo'], … … 146 153 $area_url = $results_base . '#wpcr-area-privada'; 147 154 $diploma_notice = '<div style="margin-top:18px;padding:14px 16px;background:#f0f4ff;border:1px solid #c0d0f0;border-radius:8px;text-align:center;">' 148 . '<p style="margin:0 0 10px;font-size:14px;">📄 ¿Ya tienes tu cuenta? Descarga tu <b>diploma de participación</b> desde tu área privada.</p>' 149 . '<a href="' . esc_url( $area_url ) . '" target="_blank" style="display:inline-block;padding:10px 20px;background:#166534;color:#ffffff;border-radius:6px;text-decoration:none;font-weight:bold;font-size:14px;">🎓 Ir a mi área privada</a>' 155 . '<p style="margin:0 0 10px;font-size:14px;">📄 ' . sprintf( 156 /* translators: %s: the words "participation certificate", in bold */ 157 esc_html__( 'Do you already have an account? Download your %s from your private area.', 'opcion5-sports-event-registration' ), 158 '<b>' . esc_html__( 'participation certificate', 'opcion5-sports-event-registration' ) . '</b>' 159 ) . '</p>' 160 . '<a href="' . esc_url( $area_url ) . '" target="_blank" style="display:inline-block;padding:10px 20px;background:#166534;color:#ffffff;border-radius:6px;text-decoration:none;font-weight:bold;font-size:14px;">🎓 ' . esc_html__( 'Go to my private area', 'opcion5-sports-event-registration' ) . '</a>' 150 161 . '</div>'; 151 162 } … … 154 165 . wpautop( $body ) 155 166 . $diploma_notice 156 . '<p style="font-size:12px;color:#888;margin-top:18px;"> Resultado provisional, pendiente de revisión oficial por la organización.</p>'167 . '<p style="font-size:12px;color:#888;margin-top:18px;">' . esc_html__( 'Provisional result, pending official review by the organization.', 'opcion5-sports-event-registration' ) . '</p>' 157 168 . ( function_exists( 'wpcr_email_footer' ) ? wpcr_email_footer() : '' ) 158 169 . '</div>'; … … 172 183 } 173 184 185 /** 186 * Cuerpo por defecto del email de resultados. 187 * 188 * Los marcadores entre llaves los sustituye strtr() más arriba y son los 189 * mismos que el organizador puede usar en su propia plantilla: no se 190 * traducen, o las plantillas ya guardadas dejarían de rellenar los datos. 191 */ 174 192 private static function default_body() { 175 return 'Hola {nombre}, ¡acabas de cruzar la meta de <b>{nombre_evento}</b>! 🎉<br><br>' 176 . 'Este es tu resultado <b>provisional</b>:<br><br>' 177 . '⏱ Tiempo: <b>{tiempo}</b><br>' 178 . '🏆 Posición general: <b>{pos_general}</b><br>' 179 . '🏅 Posición en tu categoría ({categoria}): <b>{pos_categoria}</b><br>' 180 . '🚻 Posición por género: <b>{pos_genero}</b><br><br>' 193 return sprintf( 194 /* translators: 1: the {nombre} placeholder, 2: the {nombre_evento} placeholder in bold */ 195 __( 'Hi %1$s, you have just crossed the finish line at %2$s!', 'opcion5-sports-event-registration' ), 196 '{nombre}', 197 '<b>{nombre_evento}</b>' 198 ) . ' 🎉<br><br>' 199 . sprintf( 200 /* translators: %s: the word "provisional", in bold */ 201 __( 'This is your %s result:', 'opcion5-sports-event-registration' ), 202 '<b>' . __( 'provisional', 'opcion5-sports-event-registration' ) . '</b>' 203 ) . '<br><br>' 204 . '⏱ ' . __( 'Time:', 'opcion5-sports-event-registration' ) . ' <b>{tiempo}</b><br>' 205 . '🏆 ' . __( 'Overall position:', 'opcion5-sports-event-registration' ) . ' <b>{pos_general}</b><br>' 206 . '🏅 ' . __( 'Position in your category', 'opcion5-sports-event-registration' ) . ' ({categoria}): <b>{pos_categoria}</b><br>' 207 . '🚻 ' . __( 'Position by gender:', 'opcion5-sports-event-registration' ) . ' <b>{pos_genero}</b><br><br>' 181 208 . '{clasificacion_local}' 182 209 . '<a href="{url_clasificaciones}" target="_blank" ' 183 210 . 'style="display:inline-block;padding:12px 24px;background:#0d47a1;color:#ffffff;' 184 211 . 'border-radius:6px;text-decoration:none;font-weight:bold;font-size:15px;">' 185 . '📱 Ver clasificaciones completas</a><br><br>'186 . '¡Enhorabuena por completar el recorrido!';212 . '📱 ' . __( 'See the full standings', 'opcion5-sports-event-registration' ) . '</a><br><br>' 213 . __( 'Congratulations on finishing the course!', 'opcion5-sports-event-registration' ); 187 214 } 188 215 } -
opcion5-sports-event-registration/trunk/modules/addons/AddonsPage.php
r3642631 r3645531 15 15 'url' => 'https://wpcompetitionregister.com/estadisticas-del-evento/', 16 16 'icon' => '📊', 17 'title' => 'Estadísticas + PDF',18 'description' => 'Informes profesionales con KPIs, gráficos, análisis por talla, provincia y más. Exporta en PDF con un clic.',19 'features' => [ 'Estadísticas automáticas del evento', 'Informe PDF descargable', 'KPIs, gráficos y métricas', 'Análisis por categoría y género'],17 'title' => __( 'Statistics + PDF', 'opcion5-sports-event-registration' ), 18 'description' => __( 'Professional reports with KPIs, charts and breakdowns by size, province and more. Export to PDF in one click.', 'opcion5-sports-event-registration' ), 19 'features' => [__( 'Automatic event statistics', 'opcion5-sports-event-registration' ), __( 'Downloadable PDF report', 'opcion5-sports-event-registration' ), __( 'KPIs, charts and metrics', 'opcion5-sports-event-registration' ), __( 'Breakdown by category and gender', 'opcion5-sports-event-registration' )], 20 20 'plans' => ['BASIC', 'PRO'], 21 21 ], … … 24 24 'url' => 'https://wpcompetitionregister.com/ficha-tecnica/', 25 25 'icon' => '📖', 26 'title' => 'Documentación técnica',27 'description' => 'Adjunta documentos ilimitados (PDF, ZIP, imágenes) en la pestaña de Información Técnica de tu evento.',28 'features' => [ 'PDF de normativa y reglamento', 'Tracks en archivos GPX/ZIP', 'Imágenes del recorrido', 'Actualizaciones continuas'],26 'title' => __( 'Event documents', 'opcion5-sports-event-registration' ), 27 'description' => __( 'Attach unlimited documents (PDF, ZIP, images) in the Race info tab of your event.', 'opcion5-sports-event-registration' ), 28 'features' => [__( 'PDF of rules and regulations', 'opcion5-sports-event-registration' ), __( 'Tracks in GPX/ZIP files', 'opcion5-sports-event-registration' ), __( 'Route images', 'opcion5-sports-event-registration' ), __( 'Ongoing updates', 'opcion5-sports-event-registration' )], 29 29 'plans' => ['BASIC', 'PRO'], 30 30 ], … … 33 33 'url' => 'https://wpcompetitionregister.com/cobros-por-stripe/', 34 34 'icon' => '💳', 35 'title' => 'Pagos con Stripe',36 'description' => 'Cobra las inscripciones con tarjeta de crédito/débito mediante Stripe Checkout. Confirmación automática por email.',37 'features' => [ 'Pago con tarjeta seguro (Stripe)', 'Confirmación automática', 'Compatible con precios por franjas', 'Registro de ingresos por evento'],35 'title' => __( 'Stripe payments', 'opcion5-sports-event-registration' ), 36 'description' => __( 'Take registration payments by credit or debit card through Stripe Checkout. Automatic confirmation by email.', 'opcion5-sports-event-registration' ), 37 'features' => [__( 'Secure card payment (Stripe)', 'opcion5-sports-event-registration' ), __( 'Automatic confirmation', 'opcion5-sports-event-registration' ), __( 'Works with date-based pricing', 'opcion5-sports-event-registration' ), __( 'Income record per event', 'opcion5-sports-event-registration' )], 38 38 'plans' => ['PRO'], 39 39 ], … … 42 42 'url' => 'https://wpcompetitionregister.com/cobros-por-paypal/', 43 43 'icon' => '🅿', 44 'title' => 'Pagos con PayPal',45 'description' => 'Permite a los participantes pagar con su cuenta PayPal o con tarjeta a través de PayPal.',46 'features' => [ 'Pago con PayPal o tarjeta', 'Confirmación automática', 'Reconocido internacionalmente', 'Registro de ingresos por evento'],44 'title' => __( 'PayPal payments', 'opcion5-sports-event-registration' ), 45 'description' => __( 'Let entrants pay with their PayPal account or by card through PayPal.', 'opcion5-sports-event-registration' ), 46 'features' => [__( 'Pay with PayPal or by card', 'opcion5-sports-event-registration' ), __( 'Automatic confirmation', 'opcion5-sports-event-registration' ), __( 'Recognised worldwide', 'opcion5-sports-event-registration' ), __( 'Income record per event', 'opcion5-sports-event-registration' )], 47 47 'plans' => ['PRO'], 48 48 ], … … 51 51 'url' => 'https://wpcompetitionregister.com/conector-con-woocommerce/', 52 52 'icon' => '🛒', 53 'title' => 'Conexión WooCommerce',54 'description' => 'Integra el checkout de WooCommerce para cobrar con cualquier pasarela instalada: Redsys, Bizum, TPV, etc.',55 'features' => [ 'Usa cualquier pasarela de WooCommerce', 'Producto por evento creado automáticamente', 'Precio dinámico por franjas', 'Compatible con Redsys, Bizum y más'],53 'title' => __( 'WooCommerce connection', 'opcion5-sports-event-registration' ), 54 'description' => __( 'Use the WooCommerce checkout to charge with any gateway you have installed: Redsys, Bizum, card terminals and so on.', 'opcion5-sports-event-registration' ), 55 'features' => [__( 'Use any WooCommerce gateway', 'opcion5-sports-event-registration' ), __( 'A product per event, created automatically', 'opcion5-sports-event-registration' ), __( 'Dynamic pricing by date', 'opcion5-sports-event-registration' ), __( 'Works with Redsys, Bizum and more', 'opcion5-sports-event-registration' )], 56 56 'plans' => ['PRO'], 57 57 ], … … 60 60 'url' => 'https://wpcompetitionregister.com/asignacion-de-dorsales/', 61 61 'icon' => '🎽', 62 'title' => 'Dorsales automáticos',63 'description' => 'Asigna dorsales únicos automáticamente según el orden de inscripción, con prefijos y rangos configurables.',64 'features' => [ 'Asignación automática al pagar', 'Prefijo y rango configurables', 'Sin duplicados ni conflictos', 'Exportación de listado de dorsales'],62 'title' => __( 'Automatic bib numbers', 'opcion5-sports-event-registration' ), 63 'description' => __( 'Assign unique bib numbers automatically in registration order, with configurable prefixes and ranges.', 'opcion5-sports-event-registration' ), 64 'features' => [__( 'Assigned automatically on payment', 'opcion5-sports-event-registration' ), __( 'Configurable prefix and range', 'opcion5-sports-event-registration' ), __( 'No duplicates or clashes', 'opcion5-sports-event-registration' ), __( 'Export the bib number list', 'opcion5-sports-event-registration' )], 65 65 'plans' => ['PRO'], 66 66 ], … … 69 69 'url' => 'https://wpcompetitionregister.com/asignacion-de-dorsales-disenador/', 70 70 'icon' => '🖨', 71 'title' => 'Dorsales + Diseñador',72 'description' => 'Todo lo del addon de Dorsales más el diseñador de dorsales físicos: PDF listo para imprenta con una página por corredor, a medida real.',73 'features' => [ 'Incluye toda la asignación de dorsales', 'PDF a medida real (200×150 / 210×150 mm)', 'Fondo con tu foto, colores por categoría', 'Talla, controles y teléfono de emergencias'],71 'title' => __( 'Bib numbers + Designer', 'opcion5-sports-event-registration' ), 72 'description' => __( 'Everything in the Bib numbers extension plus the physical bib designer: a print-ready PDF with one page per entrant, at real size.', 'opcion5-sports-event-registration' ), 73 'features' => [__( 'Includes all the bib assignment', 'opcion5-sports-event-registration' ), __( 'PDF at real size (200×150 / 210×150 mm)', 'opcion5-sports-event-registration' ), __( 'Your photo as background, colours by category', 'opcion5-sports-event-registration' ), __( 'Size, checkpoints and emergency phone', 'opcion5-sports-event-registration' )], 74 74 'plans' => ['PRO'], 75 75 ], … … 78 78 'url' => 'https://wpcompetitionregister.com/disenador-de-carteles/', 79 79 'icon' => '🖼', 80 'title' => 'Diseñador de Carteles',81 'description' => 'Diseña el cartel del evento en A3 o A2 vertical con plantillas prediseñadas totalmente editables, vista previa en vivo y PDF listo para imprenta.',82 'features' => [ 'A3/A2 vertical a medida física exacta', '4 plantillas editables (textos, colores, fuentes)', 'Datos del evento prerrellenados', 'Tu foto de fondo con capa de legibilidad'],80 'title' => __( 'Poster designer', 'opcion5-sports-event-registration' ), 81 'description' => __( 'Design your event poster in A3 or A2 portrait with fully editable templates, live preview and a print-ready PDF.', 'opcion5-sports-event-registration' ), 82 'features' => [__( 'A3/A2 portrait at exact physical size', 'opcion5-sports-event-registration' ), __( '4 editable templates (text, colours, fonts)', 'opcion5-sports-event-registration' ), __( 'Event details pre-filled', 'opcion5-sports-event-registration' ), __( 'Your background photo with a readability layer', 'opcion5-sports-event-registration' )], 83 83 'plans' => ['PRO'], 84 84 ], … … 87 87 'url' => 'https://wpcompetitionregister.com/cronometraje/', 88 88 'icon' => '⏱', 89 'title' => 'Cronometraje en meta',90 'description' => 'Toma los tiempos en meta y en puntos intermedios desde el móvil, con captura de llegadas en grupo y clasificación en vivo por punto.',91 'features' => [ 'Pantalla móvil tipo teclado', 'Puntos de control con enlace y QR únicos', 'Captura de grupos (tiempo congelado)', 'Parciales y clasificación en vivo', 'Funciona sin conexión y sincroniza'],89 'title' => __( 'Finish line timing', 'opcion5-sports-event-registration' ), 90 'description' => __( 'Take times at the finish line and at intermediate points from your phone, with group finish capture and live standings per checkpoint.', 'opcion5-sports-event-registration' ), 91 'features' => [__( 'Keypad-style mobile screen', 'opcion5-sports-event-registration' ), __( 'Checkpoints with their own link and QR', 'opcion5-sports-event-registration' ), __( 'Group capture (frozen time)', 'opcion5-sports-event-registration' ), __( 'Splits and live standings', 'opcion5-sports-event-registration' ), __( 'Works offline and syncs', 'opcion5-sports-event-registration' )], 92 92 'plans' => ['PRO'], 93 93 ], … … 96 96 'url' => 'https://wpcompetitionregister.com/lector-con-chip/', 97 97 'icon' => '🔖', 98 'title' => 'Lectura RFID por puntos de control',99 'description' => 'Cada dorsal lleva un chip RFID: en cada punto de control (intermedio o meta), el lector lo detecta automáticamente y registra el tiempo sin intervención manual.',100 'features' => [ 'Puntos de control ilimitados (salida, intermedios y meta)', 'Asociación de chip a dorsal (individual o por listado)', 'Un dorsal no se lee dos veces en el mismo punto, pero sí en puntos distintos', 'Tiempo oficial o tiempo neto (desde el chip de salida) configurable', 'Pantalla pública de seguimiento en vivo por punto'],98 'title' => __( 'RFID reading at checkpoints', 'opcion5-sports-event-registration' ), 99 'description' => __( 'Each bib carries an RFID chip: at every checkpoint (intermediate or finish) the reader detects it automatically and records the time with no manual input.', 'opcion5-sports-event-registration' ), 100 'features' => [__( 'Unlimited checkpoints (start, intermediate and finish)', 'opcion5-sports-event-registration' ), __( 'Chip-to-bib pairing (one by one or from a list)', 'opcion5-sports-event-registration' ), __( 'A bib is not read twice at the same point, but it is at different points', 'opcion5-sports-event-registration' ), __( 'Official time or net time (from the start chip), configurable', 'opcion5-sports-event-registration' ), __( 'Public live tracking screen per checkpoint', 'opcion5-sports-event-registration' )], 101 101 'plans' => ['PRO'], 102 102 ], … … 105 105 'url' => 'https://wpcompetitionregister.com/multidistancia/', 106 106 'icon' => '🏁', 107 'title' => 'Multidistancia / Sub-pruebas',108 'description' => 'Agrupa varias distancias (10K, 21K, 42K...) bajo un mismo evento, cada una con su propia inscripción, precio, cupo, dorsales y clasificación.',109 'features' => [ 'Selector de distancia en la página pública', 'Cada distancia con su precio y cupo propios', 'Reutiliza dorsales, clasificaciones y cronometraje sin cambios', 'Creación de nuevas distancias con un clic', 'Un evento no puede agruparse dos veces'],107 'title' => __( 'Multiple distances', 'opcion5-sports-event-registration' ), 108 'description' => __( 'Group several distances (10K, 21K, 42K…) under one event, each with its own registration, price, quota, bib numbers and standings.', 'opcion5-sports-event-registration' ), 109 'features' => [__( 'Distance selector on the public page', 'opcion5-sports-event-registration' ), __( 'Each distance with its own price and quota', 'opcion5-sports-event-registration' ), __( 'Reuses bib numbers, standings and timing unchanged', 'opcion5-sports-event-registration' ), __( 'Create new distances in one click', 'opcion5-sports-event-registration' ), __( 'An event cannot be grouped twice', 'opcion5-sports-event-registration' )], 110 110 'plans' => ['PRO'], 111 111 ], … … 114 114 'url' => 'https://wpcompetitionregister.com/area-privada/', 115 115 'icon' => '🔐', 116 'title' => 'Área privada de participantes',117 'description' => 'Cada participante accede con usuario y contraseña a su historial de pruebas, clasificaciones, velocidad media comparada entre eventos y diploma descargable.',118 'features' => [ 'Registro y login seguros con contraseña', 'Historial de pruebas por DNI', 'Velocidad media comparada entre eventos', 'Diploma de participación en PDF', 'Inscripción rápida en nuevos eventos'],116 'title' => __( 'Entrant private area', 'opcion5-sports-event-registration' ), 117 'description' => __( 'Each entrant signs in with a username and password to see their race history, standings, average speed compared across events and a downloadable certificate.', 'opcion5-sports-event-registration' ), 118 'features' => [__( 'Secure sign-up and login with a password', 'opcion5-sports-event-registration' ), __( 'Race history by ID number', 'opcion5-sports-event-registration' ), __( 'Average speed compared across events', 'opcion5-sports-event-registration' ), __( 'Participation certificate in PDF', 'opcion5-sports-event-registration' ), __( 'Quick registration for new events', 'opcion5-sports-event-registration' )], 119 119 'plans' => ['PRO'], 120 120 ], … … 123 123 'url' => 'https://wpcompetitionregister.com/contrarreloj/', 124 124 'icon' => '⏱', 125 'title' => 'Contrarreloj individual',126 'description' => 'Salidas de uno en uno con intervalo configurable: pantalla móvil de salida con cuenta atrás y START por dorsal, puntos intermedios y meta con el tiempo individual de cada corredor.',127 'features' => [ 'Salidas individuales con intervalo configurable', 'Cuenta atrás por corredor (pausable)', 'START por dorsal: fija el tiempo real de cada uno', 'Puntos intermedios y meta desde el móvil', 'Clasificación automática por menor tiempo empleado'],125 'title' => __( 'Individual time trial', 'opcion5-sports-event-registration' ), 126 'description' => __( 'One-by-one starts with a configurable interval: mobile start screen with countdown and START per bib, intermediate points and finish with each entrant\'s individual time.', 'opcion5-sports-event-registration' ), 127 'features' => [__( 'Individual starts with a configurable interval', 'opcion5-sports-event-registration' ), __( 'Countdown per entrant (pausable)', 'opcion5-sports-event-registration' ), __( 'START per bib: sets each entrant\'s real time', 'opcion5-sports-event-registration' ), __( 'Intermediate points and finish from your phone', 'opcion5-sports-event-registration' ), __( 'Automatic standings by shortest time', 'opcion5-sports-event-registration' )], 128 128 'plans' => ['PRO'], 129 129 ], … … 132 132 'url' => 'https://wpcompetitionregister.com/cupones-de-descuento/', 133 133 'icon' => '🎟', 134 'title' => 'Cupones de descuento',135 'description' => 'Crea códigos de descuento por importe fijo o porcentaje para las inscripciones, con límite de usos, fechas de validez e importe mínimo.',136 'features' => [ 'Descuento fijo (€) o porcentual (%)', 'Límite de usos totales y por participante', 'Válido para todos los eventos o solo algunos', 'Fechas de validez e importe mínimo', 'Validación en vivo en el formulario público'],134 'title' => __( 'Discount coupons', 'opcion5-sports-event-registration' ), 135 'description' => __( 'Create discount codes by fixed amount or percentage for registrations, with a usage limit, validity dates and a minimum amount.', 'opcion5-sports-event-registration' ), 136 'features' => [__( 'Fixed (€) or percentage (%) discount', 'opcion5-sports-event-registration' ), __( 'Limit on total uses and uses per entrant', 'opcion5-sports-event-registration' ), __( 'Valid for every event or only some', 'opcion5-sports-event-registration' ), __( 'Validity dates and minimum amount', 'opcion5-sports-event-registration' ), __( 'Live validation in the public form', 'opcion5-sports-event-registration' )], 137 137 'plans' => ['PRO'], 138 138 ], … … 141 141 'url' => 'https://wpcompetitionregister.com/clasificaciones-en-vivo/', 142 142 'icon' => '🏆', 143 'title' => 'Clasificaciones y resultados',144 'description' => 'Publica los resultados del evento: importa desde CSV o introduce manualmente posiciones por categoría y género.',145 'features' => [ 'Resultados visibles en página pública', 'Importación desde CSV', 'Posición general, categoría y género', 'Activación/ocultación por evento'],143 'title' => __( 'Standings and results', 'opcion5-sports-event-registration' ), 144 'description' => __( 'Publish the event results: import them from CSV or enter positions by category and gender manually.', 'opcion5-sports-event-registration' ), 145 'features' => [__( 'Results visible on the public page', 'opcion5-sports-event-registration' ), __( 'Import from CSV', 'opcion5-sports-event-registration' ), __( 'Overall, category and gender positions', 'opcion5-sports-event-registration' ), __( 'Show or hide per event', 'opcion5-sports-event-registration' )], 146 146 'plans' => ['PRO'], 147 147 ], … … 150 150 'url' => 'https://wpcompetitionregister.com/exportador-de-participantes-a-csv/', 151 151 'icon' => '📤', 152 'title' => 'Exportar participantes CSV',153 'description' => 'Descarga un CSV con todos los datos de participantes: contacto, categoría, talla, estado de pago y dorsal.',154 'features' => [ 'Exportación masiva en un clic', 'Incluye todos los campos del inscrito', 'Formato compatible con Excel', 'Filtro por estado de pago'],152 'title' => __( 'Export entrants to CSV', 'opcion5-sports-event-registration' ), 153 'description' => __( 'Download a CSV with all the entrant data: contact details, category, size, payment status and bib number.', 'opcion5-sports-event-registration' ), 154 'features' => [__( 'Bulk export in one click', 'opcion5-sports-event-registration' ), __( 'Includes every entrant field', 'opcion5-sports-event-registration' ), __( 'Excel-compatible format', 'opcion5-sports-event-registration' ), __( 'Filter by payment status', 'opcion5-sports-event-registration' )], 155 155 'plans' => ['BASIC', 'PRO'], 156 156 ], … … 159 159 'url' => 'https://wpcompetitionregister.com/importador-de-participantes-csv-xls/', 160 160 'icon' => '📂', 161 'title' => 'Importar CSV / XLS',162 'description' => 'Carga participantes de forma masiva desde Excel, CSV u ODS. Asistente de mapeo de columnas incluido.',163 'features' => [ 'Compatible con XLS, XLSX, CSV, ODS', 'Asistente de mapeo de columnas', 'Validación antes de importar', 'Informe de resultados detallado'],161 'title' => __( 'Import CSV / XLS', 'opcion5-sports-event-registration' ), 162 'description' => __( 'Bulk load entrants from Excel, CSV or ODS. Column mapping wizard included.', 'opcion5-sports-event-registration' ), 163 'features' => [__( 'Works with XLS, XLSX, CSV and ODS', 'opcion5-sports-event-registration' ), __( 'Column mapping wizard', 'opcion5-sports-event-registration' ), __( 'Validation before importing', 'opcion5-sports-event-registration' ), __( 'Detailed results report', 'opcion5-sports-event-registration' )], 164 164 'plans' => ['PRO'], 165 165 ], … … 168 168 'url' => 'https://wpcompetitionregister.com/avituallamientos-inteligentes/', 169 169 'icon' => '🥤', 170 'title' => 'Avituallamientos inteligentes',171 'description' => 'Calcula cuánta agua, isotónico y fruta necesitas en cada avituallamiento según los inscritos, la temperatura, la humedad y la lluvia prevista. Con lista de la compra y PDF por punto.',172 'features' => [ 'Cálculo por inscritos reales o cupo completo', 'Meteorología: temperatura, humedad y lluvia', 'Perfiles MTB, trail y ruta (vasos o botellines)', 'Margen de seguridad ajustable', 'Lista de la compra y hoja PDF por punto'],170 'title' => __( 'Smart aid stations', 'opcion5-sports-event-registration' ), 171 'description' => __( 'Work out how much water, sports drink and fruit you need at each aid station based on the entrants, the temperature, the humidity and the forecast rain. With a shopping list and a PDF per station.', 'opcion5-sports-event-registration' ), 172 'features' => [__( 'Calculated on actual entrants or full quota', 'opcion5-sports-event-registration' ), __( 'Weather: temperature, humidity and rain', 'opcion5-sports-event-registration' ), __( 'MTB, trail and road profiles (cups or bottles)', 'opcion5-sports-event-registration' ), __( 'Adjustable safety margin', 'opcion5-sports-event-registration' ), __( 'Shopping list and a PDF sheet per station', 'opcion5-sports-event-registration' )], 173 173 'plans' => ['PRO'], 174 174 ], … … 177 177 'url' => 'https://wpcompetitionregister.com/carreras-por-etapas/', 178 178 'icon' => '🏔', 179 'title' => 'Carreras por etapas',180 'description' => 'Agrupa varias etapas (días y distancias distintas) bajo una misma carrera y genera la clasificación general por suma de tiempos. Compatible con categorías, parejas, locales y multidistancia.',181 'features' => [ 'General por suma de tiempos de todas las etapas', 'Tiempo de cada etapa + diferencias al líder', 'Compatible con categorías, parejas y locales', 'Varios niveles/recorridos (corto, largo…)', 'Solo clasifican quienes completan todas las etapas'],179 'title' => __( 'Stage races', 'opcion5-sports-event-registration' ), 180 'description' => __( 'Group several stages (different days and distances) under one race and produce the overall standings by total time. Works with categories, pairs, local entrants and multiple distances.', 'opcion5-sports-event-registration' ), 181 'features' => [__( 'Overall standings by total time across all stages', 'opcion5-sports-event-registration' ), __( 'Time for each stage plus gaps to the leader', 'opcion5-sports-event-registration' ), __( 'Works with categories, pairs and local entrants', 'opcion5-sports-event-registration' ), __( 'Several levels or routes (short, long…)', 'opcion5-sports-event-registration' ), __( 'Only those who complete every stage are classified', 'opcion5-sports-event-registration' )], 182 182 'plans' => ['PRO'], 183 183 ], … … 186 186 'url' => 'https://wpcompetitionregister.com/ranking-o-campeonatos/', 187 187 'icon' => '🏆', 188 'title' => 'Rankings y Campeonatos',189 'description' => 'Agrupa varias pruebas distintas en un ranking o campeonato y saca la clasificación general por puntos o por tiempo, cruzando a los corredores por su DNI.',190 'features' => [ 'Clasificación general por puntos o por tiempo', 'Tabla de puntos configurable (o descendente)', 'Descartes: cuentan las N mejores pruebas', 'General también por categoría', 'Se publica con un shortcode en cualquier página'],188 'title' => __( 'Rankings and championships', 'opcion5-sports-event-registration' ), 189 'description' => __( 'Group several different events into a ranking or championship and produce the overall standings by points or by time, matching entrants by their ID number.', 'opcion5-sports-event-registration' ), 190 'features' => [__( 'Overall standings by points or by time', 'opcion5-sports-event-registration' ), __( 'Configurable points table (or descending)', 'opcion5-sports-event-registration' ), __( 'Drop scores: the best N events count', 'opcion5-sports-event-registration' ), __( 'Overall standings by category too', 'opcion5-sports-event-registration' ), __( 'Published with a shortcode on any page', 'opcion5-sports-event-registration' )], 191 191 'plans' => ['PRO'], 192 192 ], … … 195 195 'url' => 'https://wpcompetitionregister.com/entrega-de-dorsales/', 196 196 'icon' => '🎫', 197 'title' => 'Entrega de dorsales',198 'description' => 'Cada inscrito recibe un QR en su email. El día de la prueba tus voluntarios leen el QR desde el móvil (o buscan por apellido) y confirman la entrega, con contador de dorsales pendientes y listado de no recogidos.',199 'features' => [ 'QR de entrega en el email de confirmación', 'Pantalla móvil para voluntarios (sin usuario WP)', 'Lectura de QR + búsqueda por apellido/DNI/dorsal', 'Aviso de pago pendiente antes de entregar', 'Contador en vivo y listado de no recogidos (CSV)'],197 'title' => __( 'Bib collection', 'opcion5-sports-event-registration' ), 198 'description' => __( 'Every entrant gets a QR code by email. On race day your volunteers scan the QR from their phone (or search by surname) and confirm the handover, with a counter of pending bibs and a list of those not collected.', 'opcion5-sports-event-registration' ), 199 'features' => [__( 'Collection QR in the confirmation email', 'opcion5-sports-event-registration' ), __( 'Mobile screen for volunteers (no WordPress account needed)', 'opcion5-sports-event-registration' ), __( 'QR scanning plus search by surname, ID or bib', 'opcion5-sports-event-registration' ), __( 'Warning about pending payment before handing over', 'opcion5-sports-event-registration' ), __( 'Live counter and list of bibs not collected (CSV)', 'opcion5-sports-event-registration' )], 200 200 'plans' => ['PRO'], 201 201 ], … … 219 219 <div class="wpcr-ap-header"> 220 220 <div> 221 <h1 class="wpcr-ap-title">🔌 Extensiones</h1>222 <p class="wpcr-ap-subtitle"> Este plugin es gratuito y funciona por completo tal cual. Estas extensiones son plugins independientes, desarrollados y distribuidos aparte por el autor, que añaden funciones especializadas. Su código no forma parte de este plugin.</p>221 <h1 class="wpcr-ap-title">🔌 <?php esc_html_e( 'Extensions', 'opcion5-sports-event-registration' ); ?></h1> 222 <p class="wpcr-ap-subtitle"><?php esc_html_e( 'This plugin is free and fully functional on its own. These extensions are separate plugins, developed and distributed apart by the author, that add specialised features. Their code is not part of this plugin.', 'opcion5-sports-event-registration' ); ?></p> 223 223 </div> 224 224 </div> 225 225 226 226 <!-- ═══ Addons grid ═══ --> 227 <div class="wpcr-ap-section-title">🧩 Addons disponibles</div>227 <div class="wpcr-ap-section-title">🧩 <?php esc_html_e( 'Available extensions', 'opcion5-sports-event-registration' ); ?></div> 228 228 229 229 <div class="wpcr-addons-grid"> … … 239 239 <div class="wpcr-addon-state-pill"> 240 240 <?php if ($installed): ?> 241 <span class="pill-active">✔ Instalado</span>241 <span class="pill-active">✔ <?php esc_html_e( 'Installed', 'opcion5-sports-event-registration' ); ?></span> 242 242 <?php else: ?> 243 243 <span class="pill-buy">No instalado</span> … … 268 268 href="<?php echo esc_url( $addon['url'] ); ?>" 269 269 target="_blank" rel="noopener"> 270 Más información270 <?php esc_html_e( 'More information', 'opcion5-sports-event-registration' ); ?> 271 271 </a> 272 272 </div> -
opcion5-sports-event-registration/trunk/opcion5-sports-event-registration.php
r3642631 r3645531 4 4 Plugin URI: https://wpcompetitionregister.com 5 5 Description: Manage registrations, participants and payments for sports events (races, MTB, trail, triathlon) directly from your WordPress site. 6 Version: 1. 0.16 Version: 1.1.0 7 7 Requires at least: 6.2 8 8 Tested up to: 7.0 … … 13 13 License URI: https://www.gnu.org/licenses/gpl-2.0.html 14 14 Text Domain: opcion5-sports-event-registration 15 Domain Path: /languages 15 16 */ 16 17 … … 29 30 define('WPCR_PLUGIN_URL', plugin_dir_url(__FILE__)); 30 31 define('WPCR_PLUGIN_FILE', __FILE__); 31 define('WPCR_VERSION', '1.0.1'); 32 define('WPCR_VERSION', '1.1.0'); 33 34 /** 35 * Carga las traducciones del plugin. 36 * 37 * Se engancha a 'init' porque a partir de WordPress 6.7 cargar un dominio de 38 * texto antes de ese momento provoca el aviso de "just in time translation 39 * loading". WordPress busca primero en wp-content/languages/plugins (lo que 40 * llega desde translate.wordpress.org) y, si no lo encuentra, usa el .mo que 41 * viaja en la carpeta languages de este plugin. 42 */ 43 add_action( 'init', function () { 44 load_plugin_textdomain( 45 'opcion5-sports-event-registration', 46 false, 47 dirname( plugin_basename( __FILE__ ) ) . '/languages' 48 ); 49 } ); 32 50 33 51 // Este plugin es gratuito y totalmente funcional: gestiona todos los eventos que … … 49 67 error_log( '[WPCR] ' . $message ); 50 68 } 69 } 70 } 71 72 /** 73 * Fechas y horas con el formato que el administrador tenga configurado en 74 * Ajustes → Generales, en lugar de un formato fijo. 75 * 76 * Acepta una fecha de MySQL, un texto que entienda strtotime o un timestamp, y 77 * descarta las fechas cero que guarda MySQL cuando el campo está vacío. 78 * Devuelve $fallback si no hay una fecha utilizable. 79 */ 80 if ( ! function_exists( 'wpcr_timestamp' ) ) { 81 function wpcr_timestamp( $value ) { 82 if ( empty( $value ) ) { 83 return null; 84 } 85 if ( is_numeric( $value ) ) { 86 return (int) $value; 87 } 88 $value = trim( (string) $value ); 89 if ( $value === '0000-00-00' || $value === '0000-00-00 00:00:00' ) { 90 return null; 91 } 92 $ts = strtotime( $value ); 93 return $ts ? $ts : null; 94 } 95 } 96 97 if ( ! function_exists( 'wpcr_format_date' ) ) { 98 function wpcr_format_date( $value, $fallback = '' ) { 99 $ts = wpcr_timestamp( $value ); 100 return $ts ? date_i18n( get_option( 'date_format' ), $ts ) : $fallback; 101 } 102 } 103 104 if ( ! function_exists( 'wpcr_format_time' ) ) { 105 function wpcr_format_time( $value, $fallback = '' ) { 106 $ts = wpcr_timestamp( $value ); 107 return $ts ? date_i18n( get_option( 'time_format' ), $ts ) : $fallback; 108 } 109 } 110 111 if ( ! function_exists( 'wpcr_format_datetime' ) ) { 112 function wpcr_format_datetime( $value, $fallback = '' ) { 113 $ts = wpcr_timestamp( $value ); 114 if ( ! $ts ) { 115 return $fallback; 116 } 117 return date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $ts ); 51 118 } 52 119 } … … 311 378 // 1) Responsable del tratamiento (con datos del organizador si existen) 312 379 if ( $name !== '' ) { 313 $responsable = "El responsable del tratamiento de los datos es {$name}, organizador del evento"; 380 $responsable = sprintf( 381 /* translators: %s: organizer name */ 382 __( 'The data controller is %s, organizer of the event', 'opcion5-sports-event-registration' ), 383 $name 384 ); 314 385 } else { 315 $responsable = "El responsable del tratamiento de los datos es el organizador del evento";386 $responsable = __( 'The data controller is the organizer of the event', 'opcion5-sports-event-registration' ); 316 387 } 317 388 $contacto = []; 318 if ( $email !== '' ) { $contacto[] = "correo electrónico {$email}"; } 319 if ( $phone !== '' ) { $contacto[] = "teléfono {$phone}"; } 389 if ( $email !== '' ) { 390 /* translators: %s: contact email address */ 391 $contacto[] = sprintf( __( 'email address %s', 'opcion5-sports-event-registration' ), $email ); 392 } 393 if ( $phone !== '' ) { 394 /* translators: %s: contact phone number */ 395 $contacto[] = sprintf( __( 'phone number %s', 'opcion5-sports-event-registration' ), $phone ); 396 } 320 397 if ( $contacto ) { 321 $responsable .= ", con los siguientes datos de contacto: " . implode( ' y ', $contacto ) . "."; 398 $responsable .= sprintf( 399 /* translators: %s: list of contact details joined with "and" */ 400 __( ', with the following contact details: %s.', 'opcion5-sports-event-registration' ), 401 implode( ' ' . __( 'and', 'opcion5-sports-event-registration' ) . ' ', $contacto ) 402 ); 322 403 } else { 323 $responsable .= ", cuyos datos de contacto figuran en la información oficial del mismo."; 324 } 325 $responsable .= " En caso de gestionarse a través de plataformas externas, estas actuarán como encargadas del tratamiento."; 326 327 $text = "En cumplimiento del Reglamento (UE) 2016/679 General de Protección de Datos (RGPD) y de la Ley Orgánica 3/2018 (LOPDGDD), le informamos sobre el tratamiento de sus datos personales al realizar una inscripción en este evento. 328 329 1. Responsable del Tratamiento 404 $responsable .= __( ', whose contact details appear in the official information for the event.', 'opcion5-sports-event-registration' ); 405 } 406 $responsable .= ' ' . __( 'Where the event is managed through external platforms, these act as data processors.', 'opcion5-sports-event-registration' ); 407 408 /* 409 * Plantilla por defecto de la política de privacidad. Mantiene las 410 * referencias a la normativa española (RGPD + LOPDGDD) por decisión del 411 * autor. El organizador puede sustituirla entera desde la pestaña 412 * Opciones del evento. 413 */ 414 $text = __( 'In accordance with Regulation (EU) 2016/679 (GDPR) and Spanish Organic Law 3/2018 (LOPDGDD), we inform you about the processing of your personal data when you register for this event.', 'opcion5-sports-event-registration' ) . " 415 416 " . __( '1. Data Controller', 'opcion5-sports-event-registration' ) . " 330 417 {$responsable} 331 418 332 2. Finalidad del Tratamiento 333 Sus datos serán tratados para: 334 - Gestionar su inscripción y participación. 335 - Verificar identidad y evitar inscripciones duplicadas. 336 - Comunicar avisos, cambios, horarios u otra información relevante. 337 - Gestionar pagos y facturación. 338 - Emitir listados, dorsales, clasificaciones y resultados deportivos. 339 - Gestionar seguros deportivos cuando proceda. 340 - Enviar certificados de participación o resultados. 341 342 3. Legitimación 343 El tratamiento se basa en la ejecución de un contrato (gestión de inscripción), el consentimiento explícito del participante, obligaciones legales y el interés legítimo del organizador en publicar listados o resultados. 344 345 4. Datos Tratados 346 Datos identificativos (nombre, apellidos, DNI, fecha nacimiento), contacto (email, teléfono, localidad), datos deportivos (club, categoría, talla), datos económicos y datos vinculados a la participación (tiempos, clasificación, dorsal). 347 348 5. Publicación de Listados y Resultados 349 Podrán publicarse listados de inscritos, dorsales, resultados y clasificaciones. El usuario puede solicitar el enmascaramiento de ciertos datos si el organizador lo permite. 350 351 6. Cesiones de Datos 352 Los datos podrán comunicarse a empresas de cronometraje, aseguradoras, plataformas de inscripción, autoridades competentes o proveedores necesarios para el evento. No se realizarán transferencias internacionales no autorizadas. 353 354 7. Conservación 355 Los datos se conservarán durante la gestión del evento y el plazo legal aplicable. Los resultados pueden conservarse con fines históricos. 356 357 8. Derechos 358 El usuario puede ejercer sus derechos de acceso, rectificación, supresión, oposición, limitación, portabilidad y revocación contactando con el responsable del evento" . ( $email !== '' ? " en {$email}" : '' ) . ". 359 360 9. Seguridad 361 El organizador aplicará medidas técnicas y organizativas adecuadas para proteger sus datos. 362 363 10. Aceptación 364 Al inscribirse, el usuario declara haber leído y aceptado esta política de privacidad."; 419 " . __( '2. Purpose of the Processing', 'opcion5-sports-event-registration' ) . " 420 " . __( 'Your data will be processed in order to:', 'opcion5-sports-event-registration' ) . " 421 - " . __( 'Manage your registration and participation.', 'opcion5-sports-event-registration' ) . " 422 - " . __( 'Verify your identity and prevent duplicate registrations.', 'opcion5-sports-event-registration' ) . " 423 - " . __( 'Send notices, changes, schedules and other relevant information.', 'opcion5-sports-event-registration' ) . " 424 - " . __( 'Manage payments and invoicing.', 'opcion5-sports-event-registration' ) . " 425 - " . __( 'Produce entrant lists, bib numbers, standings and sports results.', 'opcion5-sports-event-registration' ) . " 426 - " . __( 'Manage sports insurance where applicable.', 'opcion5-sports-event-registration' ) . " 427 - " . __( 'Send participation certificates or results.', 'opcion5-sports-event-registration' ) . " 428 429 " . __( '3. Legal Basis', 'opcion5-sports-event-registration' ) . " 430 " . __( 'The processing is based on the performance of a contract (managing your registration), the explicit consent of the entrant, legal obligations and the legitimate interest of the organizer in publishing lists or results.', 'opcion5-sports-event-registration' ) . " 431 432 " . __( '4. Data Processed', 'opcion5-sports-event-registration' ) . " 433 " . __( 'Identification data (first name, surname, ID number, date of birth), contact data (email, phone, town), sports data (club, category, size), financial data and data linked to your participation (times, standings, bib number).', 'opcion5-sports-event-registration' ) . " 434 435 " . __( '5. Publication of Lists and Results', 'opcion5-sports-event-registration' ) . " 436 " . __( 'Entrant lists, bib numbers, results and standings may be published. You may ask for certain data to be masked if the organizer allows it.', 'opcion5-sports-event-registration' ) . " 437 438 " . __( '6. Data Disclosure', 'opcion5-sports-event-registration' ) . " 439 " . __( 'Your data may be disclosed to timing companies, insurers, registration platforms, the competent authorities or suppliers needed for the event. No unauthorised international transfers will be made.', 'opcion5-sports-event-registration' ) . " 440 441 " . __( '7. Retention', 'opcion5-sports-event-registration' ) . " 442 " . __( 'Data will be kept for as long as the event is being managed and for the applicable legal period. Results may be kept for historical purposes.', 'opcion5-sports-event-registration' ) . " 443 444 " . __( '8. Your Rights', 'opcion5-sports-event-registration' ) . " 445 " . __( 'You may exercise your rights of access, rectification, erasure, objection, restriction, portability and withdrawal of consent by contacting the person responsible for the event', 'opcion5-sports-event-registration' ) 446 . ( $email !== '' ? ' ' . sprintf( /* translators: %s: contact email address */ __( 'at %s', 'opcion5-sports-event-registration' ), $email ) : '' ) . ". 447 448 " . __( '9. Security', 'opcion5-sports-event-registration' ) . " 449 " . __( 'The organizer will apply appropriate technical and organisational measures to protect your data.', 'opcion5-sports-event-registration' ) . " 450 451 " . __( '10. Acceptance', 'opcion5-sports-event-registration' ) . " 452 " . __( 'By registering, you declare that you have read and accepted this privacy policy.', 'opcion5-sports-event-registration' ); 365 453 366 454 return $text; -
opcion5-sports-event-registration/trunk/public/ajax-wpcr-dni.php
r3642215 r3645531 92 92 */ 93 93 if ( ! check_ajax_referer( 'wpcr_dni_lookup', 'nonce', false ) ) { 94 wp_send_json_error( [ 'msg' => 'Sesión caducada. Recarga la página e inténtalo de nuevo.'] );94 wp_send_json_error( [ 'msg' => __( 'Your session has expired. Reload the page and try again.', 'opcion5-sports-event-registration' ) ] ); 95 95 } 96 96 … … 102 102 103 103 if ($dni === '') { 104 wp_send_json_error(['msg' => 'DNI vacío']);104 wp_send_json_error(['msg' => __( 'Empty ID number', 'opcion5-sports-event-registration' )]); 105 105 } 106 106 … … 133 133 if ( ! $valid ) { 134 134 wp_send_json_error([ 135 'msg' => 'DNI/NIE no válido. Comprueba el número y la letra.',135 'msg' => __( 'Invalid ID number. Check the digits and the letter.', 'opcion5-sports-event-registration' ), 136 136 'invalid_dni' => true, 137 137 ]); … … 191 191 } 192 192 if (!check_ajax_referer('wpcr_dni_lookup', 'nonce', false)) { 193 wp_send_json_error( 'Token de seguridad no válido.', 403);193 wp_send_json_error( __( 'Invalid security token.', 'opcion5-sports-event-registration' ), 403 ); 194 194 } 195 195 … … 197 197 198 198 if ($dni === '') { 199 wp_send_json_error( 'DNI vacío');199 wp_send_json_error( __( 'Empty ID number', 'opcion5-sports-event-registration' ) ); 200 200 } 201 201 -
opcion5-sports-event-registration/trunk/public/class-wpcr-payment-mails.php
r3642215 r3645531 26 26 27 27 $subject = $event['wpcr_mail_paid_subject'] 28 ?? 'Pago confirmado - ' . $event['name']; 28 ?? sprintf( 29 /* translators: %s: event name */ 30 __( 'Payment confirmed - %s', 'opcion5-sports-event-registration' ), 31 $event['name'] 32 ); 29 33 34 /* 35 * Plantilla por defecto. Los marcadores entre llaves ({nombre}, 36 * {nombre_evento}, {precio}) son los que sustituye WPCR_Mailer y los que 37 * el organizador escribe en sus propias plantillas: no se traducen, o las 38 * plantillas ya guardadas dejarían de rellenar los datos. 39 */ 30 40 $template = $event['wpcr_mail_paid_body'] 31 ?? " 32 <h2>✅ Pago confirmado</h2> 33 <p>Hola {nombre},</p> 34 <p>Tu inscripción en <b>{nombre_evento}</b> ha sido confirmada.</p> 35 <p><b>Importe pagado:</b> {precio} €</p> 36 <p>¡Te esperamos!</p> 37 "; 41 ?? ' 42 <h2>✅ ' . __( 'Payment confirmed', 'opcion5-sports-event-registration' ) . '</h2> 43 <p>' . __( 'Hi', 'opcion5-sports-event-registration' ) . ' {nombre},</p> 44 <p>' . sprintf( 45 /* translators: %s: the {nombre_evento} placeholder, replaced with the event name */ 46 __( 'Your registration for %s has been confirmed.', 'opcion5-sports-event-registration' ), 47 '<b>{nombre_evento}</b>' 48 ) . '</p> 49 <p><b>' . __( 'Amount paid:', 'opcion5-sports-event-registration' ) . '</b> {precio} €</p> 50 <p>' . __( 'See you there!', 'opcion5-sports-event-registration' ) . '</p> 51 '; 38 52 39 53 $mailer->send_mail( -
opcion5-sports-event-registration/trunk/public/class-wpcr-payment-page.php
r3642215 r3645531 61 61 // phpcs:disable WordPress.Security.NonceVerification.Recommended 62 62 if (empty($_GET['token'])) { 63 wp_die( 'Token no válido.');63 wp_die( esc_html__( 'Invalid token.', 'opcion5-sports-event-registration' ) ); 64 64 } 65 65 … … 105 105 106 106 if (!$participant || !$event) { 107 wp_die( 'Datos de inscripción no válidos.');107 wp_die( esc_html__( 'Invalid registration data.', 'opcion5-sports-event-registration' ) ); 108 108 } 109 109 … … 121 121 // phpcs:disable WordPress.Security.NonceVerification.Recommended 122 122 if (empty($_GET['token'])) { 123 wp_die( 'Token de pago no válido.');123 wp_die( esc_html__( 'Invalid payment token.', 'opcion5-sports-event-registration' ) ); 124 124 } 125 125 … … 210 210 211 211 default: 212 wp_die( 'Método de pago no soportado.');212 wp_die( esc_html__( 'Unsupported payment method.', 'opcion5-sports-event-registration' ) ); 213 213 } 214 214 -
opcion5-sports-event-registration/trunk/public/class-wpcr-public-list.php
r3642215 r3645531 141 141 <a href="<?php echo esc_url( $url_prox ); ?>" 142 142 style="padding:10px 22px;text-decoration:none;font-weight:600;border-bottom:3px solid <?php echo esc_attr($view==='proximos'?'#2271b1':'transparent'); ?>;color:<?php echo esc_attr($view==='proximos'?'#2271b1':'#666'); ?>;"> 143 Próximos eventos143 <?php esc_html_e( 'Upcoming events', 'opcion5-sports-event-registration' ); ?> 144 144 </a> 145 145 <a href="<?php echo esc_url( $url_pas ); ?>" 146 146 style="padding:10px 22px;text-decoration:none;font-weight:600;border-bottom:3px solid <?php echo esc_attr($view==='pasados'?'#2271b1':'transparent'); ?>;color:<?php echo esc_attr($view==='pasados'?'#2271b1':'#666'); ?>;"> 147 Eventos pasados147 <?php esc_html_e( 'Past events', 'opcion5-sports-event-registration' ); ?> 148 148 </a> 149 149 </div> … … 153 153 154 154 <select name="modality"> 155 <option value=""> Modalidad</option>155 <option value=""><?php esc_html_e( 'Discipline', 'opcion5-sports-event-registration' ); ?></option> 156 156 <option value="mtb" <?php selected($mod,'mtb'); ?>>MTB</option> 157 <option value="carrera" <?php selected($mod,'carrera'); ?>> Carrera</option>157 <option value="carrera" <?php selected($mod,'carrera'); ?>><?php esc_html_e( 'Running', 'opcion5-sports-event-registration' ); ?></option> 158 158 <option value="trail" <?php selected($mod,'trail'); ?>>Trail</option> 159 159 </select> 160 160 161 161 <select name="provincia"> 162 <option value=""> Provincia</option>162 <option value=""><?php esc_html_e( 'Province', 'opcion5-sports-event-registration' ); ?></option> 163 163 <?php foreach (WPCR_Data_Model::get_provincias() as $pv): ?> 164 164 <option value="<?php echo esc_attr($pv); ?>" <?php selected($prov, $pv); ?>> … … 169 169 170 170 <select name="mes"> 171 <option value=""> Mes</option>171 <option value=""><?php esc_html_e( 'Month', 'opcion5-sports-event-registration' ); ?></option> 172 172 <?php foreach ($meses as $m): ?> 173 173 <option value="<?php echo esc_attr($m['valor']); ?>" … … 178 178 </select> 179 179 180 <button type="submit"> Filtrar</button>180 <button type="submit"><?php esc_html_e( 'Filter', 'opcion5-sports-event-registration' ); ?></button> 181 181 </form> 182 182 … … 184 184 <div class="wpcr-event-grid"> 185 185 <?php if (empty($events)): ?> 186 <p><em> No hay eventos próximos que coincidan con los filtros.</em></p>186 <p><em><?php esc_html_e( 'There are no events matching these filters.', 'opcion5-sports-event-registration' ); ?></em></p> 187 187 <?php endif; ?> 188 188 … … 217 217 $start_time_raw = $e['start_time'] ?? ''; 218 218 $start_time = ($start_time_raw && $start_time_raw !== "00:00:00") 219 ? date_i18n("H:i", strtotime($start_time_raw)) . "h"219 ? wpcr_format_time($start_time_raw, "-") 220 220 : "-"; 221 221 … … 223 223 $reg_close_raw = $e['reg_close'] ?? ''; 224 224 225 $reg_open = ($reg_open_raw && $reg_open_raw !== '0000-00-00 00:00:00') 226 ? date_i18n("d/m/Y H:i", strtotime($reg_open_raw)) . "h" 227 : "-"; 228 229 $reg_close = ($reg_close_raw && $reg_close_raw !== '0000-00-00 00:00:00') 230 ? date_i18n("d/m/Y H:i", strtotime($reg_close_raw)) . "h" 231 : "-"; 225 $reg_open = wpcr_format_datetime($reg_open_raw, "-"); 226 $reg_close = wpcr_format_datetime($reg_close_raw, "-"); 232 227 233 228 // --------------------------------------------------------- … … 247 242 if ($insc_open_ts && $now < $insc_open_ts) { 248 243 249 $btn = "<div class='wpcr-event-btn upcoming'> PRÓXIMAMENTE…</div>";244 $btn = "<div class='wpcr-event-btn upcoming'>" . esc_html__( 'COMING SOON…', 'opcion5-sports-event-registration' ) . "</div>"; 250 245 251 246 } elseif ($insc_open_ts && $insc_close_ts && $now >= $insc_open_ts && $now <= $insc_close_ts) { 252 247 253 248 if ($full) { 254 $btn = "<div class='wpcr-event-btn full'> SIN PLAZAS DISPONIBLES</div>";249 $btn = "<div class='wpcr-event-btn full'>" . esc_html__( 'NO PLACES LEFT', 'opcion5-sports-event-registration' ) . "</div>"; 255 250 } else { 256 $btn = "<a href='" . esc_url($url_evento) . "' class='wpcr-event-btn active'> INSCRIPCIONES ABIERTAS</a>";251 $btn = "<a href='" . esc_url($url_evento) . "' class='wpcr-event-btn active'>" . esc_html__( 'REGISTRATION OPEN', 'opcion5-sports-event-registration' ) . "</a>"; 257 252 } 258 253 259 254 } else { 260 255 261 $btn = "<div class='wpcr-event-btn closed'> INSCRIPCIONES CERRADAS</div>";256 $btn = "<div class='wpcr-event-btn closed'>" . esc_html__( 'REGISTRATION CLOSED', 'opcion5-sports-event-registration' ) . "</div>"; 262 257 } 263 258 ?> … … 282 277 ?> 283 278 <a href="<?php echo esc_url( $url_evento ); ?>" class="wpcr-live-badge" style="text-decoration:none;margin:2px 0 6px;"> 284 <span class="wpcr-live-dot"></span> En directo279 <span class="wpcr-live-dot"></span> <?php esc_html_e( 'Live', 'opcion5-sports-event-registration' ); ?> 285 280 </a> 286 281 <?php endif; ?> … … 316 311 $mod_label = ! empty( $mod_name ) ? $mod_name : ( $e['event_type'] ?? '' ); 317 312 ?> 318 <strong> Modalidad:</strong> <?php echo esc_html( $mod_label ); ?><br>319 <strong> Fecha del evento:</strong> <?php echo esc_html( date_i18n('d/m/Y', strtotime($e['event_date'])) ); ?><br>320 <strong> Localidad:</strong> <?php echo esc_html($e['localidad']); ?><br>321 <strong> Provincia:</strong> <?php echo esc_html($e['provincia']); ?><br>322 <strong> Hora de salida:</strong> <?php echo esc_html($start_time); ?><br>323 <strong> Apertura de inscrip.:</strong> <?php echo esc_html($reg_open); ?><br>324 <strong> Cierre de inscrip.:</strong> <?php echo esc_html($reg_close); ?><br>325 <strong> Inscritos / Plazas:</strong> <?php echo (int) $total . " / " . esc_html( $plazas_label ); ?><br>313 <strong><?php esc_html_e( 'Discipline:', 'opcion5-sports-event-registration' ); ?></strong> <?php echo esc_html( $mod_label ); ?><br> 314 <strong><?php esc_html_e( 'Event date:', 'opcion5-sports-event-registration' ); ?></strong> <?php echo esc_html( wpcr_format_date( $e['event_date'] ) ); ?><br> 315 <strong><?php esc_html_e( 'Town:', 'opcion5-sports-event-registration' ); ?></strong> <?php echo esc_html($e['localidad']); ?><br> 316 <strong><?php esc_html_e( 'Province:', 'opcion5-sports-event-registration' ); ?></strong> <?php echo esc_html($e['provincia']); ?><br> 317 <strong><?php esc_html_e( 'Start time:', 'opcion5-sports-event-registration' ); ?></strong> <?php echo esc_html($start_time); ?><br> 318 <strong><?php esc_html_e( 'Registration opens:', 'opcion5-sports-event-registration' ); ?></strong> <?php echo esc_html($reg_open); ?><br> 319 <strong><?php esc_html_e( 'Registration closes:', 'opcion5-sports-event-registration' ); ?></strong> <?php echo esc_html($reg_close); ?><br> 320 <strong><?php esc_html_e( 'Entrants / Places:', 'opcion5-sports-event-registration' ); ?></strong> <?php echo (int) $total . " / " . esc_html( $plazas_label ); ?><br> 326 321 </p> 327 322 </div> … … 348 343 349 344 if (empty($public_id)) { 350 return '<p> No se ha especificado un evento válido.</p>';345 return '<p>' . esc_html__( 'No valid event was specified.', 'opcion5-sports-event-registration' ) . '</p>'; 351 346 } 352 347 … … 361 356 362 357 if (!$event) { 363 return '<p> Evento no encontrado.</p>';358 return '<p>' . esc_html__( 'Event not found.', 'opcion5-sports-event-registration' ) . '</p>'; 364 359 } 365 360 … … 385 380 386 381 if ( empty( $participants ) ) { 387 return '<p> No hay participantes inscritos aún.</p>';382 return '<p>' . esc_html__( 'There are no entrants yet.', 'opcion5-sports-event-registration' ) . '</p>'; 388 383 } 389 384 … … 439 434 foreach($participants as $p){ 440 435 $cat = trim($p['category_name'] ?? ''); 441 if($cat == '') $cat = "Sin categoría";436 if($cat == '') $cat = __( 'No category', 'opcion5-sports-event-registration' ); 442 437 443 438 if(!isset($counts[$cat])) $counts[$cat] = 0; … … 523 518 524 519 <div class="wpcr-summary-item wpcr-summary-total" data-cat=""> 525 Total:<?php echo (int) $total; ?>520 <?php esc_html_e( 'Total:', 'opcion5-sports-event-registration' ); ?> <?php echo (int) $total; ?> 526 521 </div> 527 522 … … 537 532 <!-- 🔍 COLUMNA DERECHA — BUSCADOR --> 538 533 <div class="wpcr-search-box"> 539 <input type="text" id="wpcr-search" placeholder=" Buscar nombre o club…">534 <input type="text" id="wpcr-search" placeholder="<?php echo esc_attr__( 'Search name or club…', 'opcion5-sports-event-registration' ); ?>"> 540 535 </div> 541 536 … … 545 540 <thead> 546 541 <tr class="wpcr-row"> 547 <th data-sort="name"> Nombre</th>548 <th data-sort="surname"> Apellidos</th>549 <th data-sort="category"> Categoría</th>550 <th data-sort="club"> Club</th>542 <th data-sort="name"><?php esc_html_e( 'Name', 'opcion5-sports-event-registration' ); ?></th> 543 <th data-sort="surname"><?php esc_html_e( 'Surname', 'opcion5-sports-event-registration' ); ?></th> 544 <th data-sort="category"><?php esc_html_e( 'Category', 'opcion5-sports-event-registration' ); ?></th> 545 <th data-sort="club"><?php esc_html_e( 'Club', 'opcion5-sports-event-registration' ); ?></th> 551 546 <?php if ($show_localidad): ?> 552 <th data-sort="localidad"> Localidad</th>547 <th data-sort="localidad"><?php esc_html_e( 'Town', 'opcion5-sports-event-registration' ); ?></th> 553 548 <?php endif; ?> 554 549 555 <th> Estado</th>556 <th> Acción</th>550 <th><?php esc_html_e( 'Status', 'opcion5-sports-event-registration' ); ?></th> 551 <th><?php esc_html_e( 'Action', 'opcion5-sports-event-registration' ); ?></th> 557 552 558 553 </tr> … … 618 613 if ( in_array( $payment_type, ['invited','manual','woocommerce'], true ) 619 614 || $pay_status === 'paid' ) { 620 echo "<span style='color:#007700;font-weight:bold;'>✔ Inscrito</span>";615 echo "<span style='color:#007700;font-weight:bold;'>✔ " . esc_html__( 'Registered', 'opcion5-sports-event-registration' ) . "</span>"; 621 616 } 622 617 /* 🕐 Transferencia bancaria pendiente de confirmar → Preinscrito */ 623 618 elseif ( $pay_method === 'bank_transfer' && $pay_status === 'pending' ) { 624 echo "<span style='color:#2271b1;font-weight:bold;'>🕐 Preinscrito</span>";619 echo "<span style='color:#2271b1;font-weight:bold;'>🕐 " . esc_html__( 'Pre-registered', 'opcion5-sports-event-registration' ) . "</span>"; 625 620 } 626 621 /* 🔒 Lista de espera */ 627 622 elseif ( $waitlist == 1 ) { 628 echo "<span style='color:#555;'>🔒 Reserva</span>";623 echo "<span style='color:#555;'>🔒 " . esc_html__( 'Reserve', 'opcion5-sports-event-registration' ) . "</span>"; 629 624 } 630 625 /* ⏳ Pendiente de pago */ 631 626 else { 632 echo "<span style='color:#c40000;font-weight:bold;'>⏳ Pendiente de pago</span>";627 echo "<span style='color:#c40000;font-weight:bold;'>⏳ " . esc_html__( 'Payment pending', 'opcion5-sports-event-registration' ) . "</span>"; 633 628 } 634 629 ?> … … 640 635 if ( in_array( $payment_type, ['invited','manual','woocommerce'], true ) 641 636 || $pay_status === 'paid' ) { 642 echo "<span style='color:#007700;font-weight:bold;'>🟢 Plaza confirmada</span>";637 echo "<span style='color:#007700;font-weight:bold;'>🟢 " . esc_html__( 'Place confirmed', 'opcion5-sports-event-registration' ) . "</span>"; 643 638 } 644 639 elseif ( $pay_method === 'bank_transfer' && $pay_status === 'pending' ) { 645 640 // Transferencia pendiente: no hay acción pública, la confirma el administrador 646 echo "<span style='color:#777;font-style:italic;'> Pendiente de confirmación</span>";641 echo "<span style='color:#777;font-style:italic;'>" . esc_html__( 'Awaiting confirmation', 'opcion5-sports-event-registration' ) . "</span>"; 647 642 } 648 643 elseif ( $waitlist == 1 ) { 649 echo "<span style='color:#555;font-style:italic;'> En lista de espera</span>";644 echo "<span style='color:#555;font-style:italic;'>" . esc_html__( 'On the waiting list', 'opcion5-sports-event-registration' ) . "</span>"; 650 645 } 651 646 else { 652 647 if ( $reg_is_closed ) { 653 echo "<span style='color:#999;font-style:italic;'> Plazo cerrado</span>";648 echo "<span style='color:#999;font-style:italic;'>" . esc_html__( 'Registration closed', 'opcion5-sports-event-registration' ) . "</span>"; 654 649 } else { 655 650 $pay_url = wpcr_endpoint_url( 'pago', [ 'token' => $pay_token ] ); 656 echo "<a href='" . esc_url( $pay_url ) . "' style='color:#007bff;font-weight:bold;text-decoration:underline;'>💳 Pagar ahora</a>";651 echo "<a href='" . esc_url( $pay_url ) . "' style='color:#007bff;font-weight:bold;text-decoration:underline;'>💳 " . esc_html__( 'Pay now', 'opcion5-sports-event-registration' ) . "</a>"; 657 652 } 658 653 } -
opcion5-sports-event-registration/trunk/public/class-wpcr-public.php
r3642215 r3645531 72 72 true 73 73 ); 74 /* 75 * Los textos del JS viajan aquí: un fichero .js no lo alcanza el .mo, así 76 * que se traducen en PHP y se pasan ya traducidos al navegador. 77 */ 74 78 wp_localize_script('wpcr-frontend','wpcr_ajax',[ 75 79 'url'=>admin_url('admin-ajax.php'), 76 'nonce'=>wp_create_nonce('wpcr_dni_lookup') 80 'nonce'=>wp_create_nonce('wpcr_dni_lookup'), 81 'i18n'=>[ 82 'invalidDni' => __( 'Invalid ID number. Check the digits and the letter.', 'opcion5-sports-event-registration' ), 83 'checkError' => __( 'Something went wrong checking the ID number. Please try again.', 'opcion5-sports-event-registration' ), 84 'alreadyIn' => __( 'This ID number is already registered for this event.', 'opcion5-sports-event-registration' ), 85 'recognised' => __( 'We recognised you from previous registrations', 'opcion5-sports-event-registration' ), 86 'labelName' => __( 'Name:', 'opcion5-sports-event-registration' ), 87 'labelEmail' => __( 'Email:', 'opcion5-sports-event-registration' ), 88 'labelPhone' => __( 'Phone:', 'opcion5-sports-event-registration' ), 89 'labelTown' => __( 'Town:', 'opcion5-sports-event-registration' ), 90 'useMyData' => __( 'That is me, use my details', 'opcion5-sports-event-registration' ), 91 'dataChanged' => __( 'They have changed, update them', 'opcion5-sports-event-registration' ), 92 'willUseSaved' => __( 'We will use your saved details. Fill in what is missing (size, etc.) and press Send.', 'opcion5-sports-event-registration' ), 93 ], 77 94 ]); 78 95 } … … 94 111 $event=$this->get_event_data($public_id); 95 112 96 if(!$event) return "<div class='wpcr-message wpcr-error'> No hay eventos disponibles.</div>";113 if(!$event) return "<div class='wpcr-message wpcr-error'>" . esc_html__( 'No events available.', 'opcion5-sports-event-registration' ) . "</div>"; 97 114 98 115 $event_id=intval($event['id']); … … 119 136 // phpcs:ignore WordPress.Security.NonceVerification.Recommended 120 137 if(isset($_GET['wpcr_message']) && sanitize_text_field(wp_unslash($_GET['wpcr_message']))=='success'){ 121 return "<div class='wpcr-message wpcr-success'>Registro completado en <b>" . esc_html($event_name) . "</b></div>"; 138 return "<div class='wpcr-message wpcr-success'>" . sprintf( 139 /* translators: %s: event name */ 140 esc_html__( 'Registration completed for %s', 'opcion5-sports-event-registration' ), 141 '<b>' . esc_html($event_name) . '</b>' 142 ) . "</div>"; 122 143 } 123 144 … … 131 152 132 153 <h2 class="wpcr-card-title"><?php echo esc_html($event_name); ?></h2> 133 <p class="wpcr-card-subtitle"> Completa tu identificación para comenzar la inscripción.</p>134 135 <h3 class="wpcr-step-title"> Paso 1: Identificación</h3>154 <p class="wpcr-card-subtitle"><?php esc_html_e( 'Enter your ID to start the registration.', 'opcion5-sports-event-registration' ); ?></p> 155 156 <h3 class="wpcr-step-title"><?php esc_html_e( 'Step 1: Identification', 'opcion5-sports-event-registration' ); ?></h3> 136 157 137 158 … … 144 165 <div id="wpcr-step-1" class="wpcr-box"> 145 166 146 <p><label> Nacionalidad*</label>167 <p><label><?php esc_html_e( 'Nationality', 'opcion5-sports-event-registration' ); ?> *</label> 147 168 <select id="wpcr_nationality" name="nationality" required> 148 <option value="ES"> España</option>149 <option value="OTRO"> Otro</option>169 <option value="ES"><?php esc_html_e( 'Spain', 'opcion5-sports-event-registration' ); ?></option> 170 <option value="OTRO"><?php esc_html_e( 'Other', 'opcion5-sports-event-registration' ); ?></option> 150 171 </select></p> 151 172 152 <p><label> DNI*</label>173 <p><label><?php esc_html_e( 'ID number', 'opcion5-sports-event-registration' ); ?> *</label> 153 174 <input type="text" id="dni" name="dni" required></p> 154 175 155 <button type="button" id="wpcr-check-dni-btn"> Comprobar</button>176 <button type="button" id="wpcr-check-dni-btn"><?php esc_html_e( 'Check', 'opcion5-sports-event-registration' ); ?></button> 156 177 <div id="wpcr-dni-feedback"></div> 157 178 </div> 158 179 159 180 <div id="wpcr-step-2" class="wpcr-box" style="display:none;margin-top:20px;padding:20px;border-radius:8px;border:1px solid #ccc;"> 160 <h3> Completa tus datos</h3>161 162 <p><label> Nombre*</label><input type="text" name="first_name" required></p>163 <p><label> 1er Apellido*</label><input type="text" name="middle_name" required></p>164 <p><label> 2º Apellido</label><input type="text" name="last_name"></p>165 <p><label> Fecha nacimiento*</label><input type="date" name="dob" required></p>166 167 <p><label> Género*</label><br>168 <label><input type="radio" name="gender" value="M" required> Masculino</label>169 <label><input type="radio" name="gender" value="F" required> Femenino</label>181 <h3><?php esc_html_e( 'Complete your details', 'opcion5-sports-event-registration' ); ?></h3> 182 183 <p><label><?php esc_html_e( 'First name', 'opcion5-sports-event-registration' ); ?> *</label><input type="text" name="first_name" required></p> 184 <p><label><?php esc_html_e( 'First surname', 'opcion5-sports-event-registration' ); ?> *</label><input type="text" name="middle_name" required></p> 185 <p><label><?php esc_html_e( 'Second surname', 'opcion5-sports-event-registration' ); ?></label><input type="text" name="last_name"></p> 186 <p><label><?php esc_html_e( 'Date of birth', 'opcion5-sports-event-registration' ); ?> *</label><input type="date" name="dob" required></p> 187 188 <p><label><?php esc_html_e( 'Gender', 'opcion5-sports-event-registration' ); ?> *</label><br> 189 <label><input type="radio" name="gender" value="M" required> <?php esc_html_e( 'Male', 'opcion5-sports-event-registration' ); ?></label> 190 <label><input type="radio" name="gender" value="F" required> <?php esc_html_e( 'Female', 'opcion5-sports-event-registration' ); ?></label> 170 191 </p> 171 192 172 <p><label> Localidad*</label><input type="text" name="localidad" required></p>173 <p><label> Provincia*</label><input type="text" name="provincia" required></p>174 175 <p><label> Teléfono*</label><input type="tel" name="phone" required></p>176 <p><label> Email*</label><input type="email" name="email" required></p>177 <p><label> Club / Equipo</label><input type="text" name="club_team" value="independiente"></p>193 <p><label><?php esc_html_e( 'Town', 'opcion5-sports-event-registration' ); ?> *</label><input type="text" name="localidad" required></p> 194 <p><label><?php esc_html_e( 'Province', 'opcion5-sports-event-registration' ); ?> *</label><input type="text" name="provincia" required></p> 195 196 <p><label><?php esc_html_e( 'Phone', 'opcion5-sports-event-registration' ); ?> *</label><input type="tel" name="phone" required></p> 197 <p><label><?php esc_html_e( 'Email', 'opcion5-sports-event-registration' ); ?> *</label><input type="email" name="email" required></p> 198 <p><label><?php esc_html_e( 'Club / Team', 'opcion5-sports-event-registration' ); ?></label><input type="text" name="club_team" value="<?php echo esc_attr__( 'independent', 'opcion5-sports-event-registration' ); ?>"></p> 178 199 <?php 179 200 // ===================================== … … 191 212 && !empty($event_data['tallas_options']) ): 192 213 193 $tallas_label = $event_data['tallas_label'] ?: "Selecciona tu talla";214 $tallas_label = $event_data['tallas_label'] ?: __( 'Select your size', 'opcion5-sports-event-registration' ); 194 215 $tallas_opciones = array_filter(array_map('trim', explode(",", $event_data['tallas_options']))); 195 216 ?> … … 197 218 <label><?php echo esc_html($tallas_label); ?> *</label><br> 198 219 <select name="talla" required> 199 <option value="" disabled selected> Seleccione una talla</option>220 <option value="" disabled selected><?php esc_html_e( 'Select a size', 'opcion5-sports-event-registration' ); ?></option> 200 221 <?php foreach($tallas_opciones as $t): ?> 201 222 <option value="<?php echo esc_attr($t); ?>"><?php echo esc_html($t); ?></option> … … 211 232 $pairs_enabled_evt = ! empty( $event['pairs_enabled'] ); 212 233 $pair_cats_evt = array_filter( explode( ',', $event['pair_categories'] ?? '' ) ); 213 $pair_cat_labels = [ 'male' => 'Pareja masculina', 'mixed' => 'Pareja mixta', 'female' => 'Pareja femenina' ]; 234 $pair_cat_labels = [ 235 'male' => __( "Men's pair", 'opcion5-sports-event-registration' ), 236 'mixed' => __( 'Mixed pair', 'opcion5-sports-event-registration' ), 237 'female' => __( "Women's pair", 'opcion5-sports-event-registration' ), 238 ]; 214 239 215 240 // Código de pareja precargado desde el enlace compartido (?pair=XXXX) … … 229 254 ?> 230 255 <div class="wpcr-pairs-box" style="margin:16px 0;padding:14px;background:#f0f4ff;border:1px solid #c0d0f0;border-radius:8px;"> 231 <p style="margin:0 0 8px;font-weight:600;">👥 Modalidad de inscripción</p>256 <p style="margin:0 0 8px;font-weight:600;">👥 <?php esc_html_e( 'Registration type', 'opcion5-sports-event-registration' ); ?></p> 232 257 233 258 <?php if ( $prefill_pair_row ): ?> 234 259 <p style="margin:0 0 8px;padding:8px 12px;background:#f0fdf4;border:1px solid #bbf7d0;border-radius:6px;font-size:14px;"> 235 ✔ Te estás inscribiendo como pareja de 236 <strong><?php echo esc_html( trim( $prefill_pair_row['first_name'] . ' ' . $prefill_pair_row['middle_name'] ) ); ?></strong> 237 (<?php echo esc_html( $pair_cat_labels[ $prefill_pair_row['pair_category'] ] ?? 'Pareja' ); ?>). 260 ✔ <?php printf( 261 /* translators: 1: partner name, 2: pair category, for example "Mixed pair" */ 262 esc_html__( 'You are registering as the partner of %1$s (%2$s).', 'opcion5-sports-event-registration' ), 263 '<strong>' . esc_html( trim( $prefill_pair_row['first_name'] . ' ' . $prefill_pair_row['middle_name'] ) ) . '</strong>', 264 esc_html( $pair_cat_labels[ $prefill_pair_row['pair_category'] ] ?? __( 'Pair', 'opcion5-sports-event-registration' ) ) 265 ); ?> 238 266 </p> 239 267 <input type="hidden" name="wpcr_pair_mode" value="pair"> … … 242 270 243 271 <label style="margin-right:16px;"> 244 <input type="radio" name="wpcr_pair_mode" value="individual" checked> Individual272 <input type="radio" name="wpcr_pair_mode" value="individual" checked> <?php esc_html_e( 'Individual', 'opcion5-sports-event-registration' ); ?> 245 273 </label> 246 274 <label> 247 <input type="radio" name="wpcr_pair_mode" value="pair"> Por parejas275 <input type="radio" name="wpcr_pair_mode" value="pair"> <?php esc_html_e( 'As a pair', 'opcion5-sports-event-registration' ); ?> 248 276 </label> 249 277 250 278 <div id="wpcr-pair-options" style="display:none;margin-top:12px;"> 251 <p style="margin:0 0 4px;"><label> Modalidad de pareja*</label><br>279 <p style="margin:0 0 4px;"><label><?php esc_html_e( 'Pair category', 'opcion5-sports-event-registration' ); ?> *</label><br> 252 280 <select name="wpcr_pair_category"> 253 281 <?php foreach ( $pair_cats_evt as $pc ): if ( ! isset( $pair_cat_labels[ $pc ] ) ) continue; ?> … … 256 284 </select> 257 285 </p> 258 <p style="margin:10px 0 4px;"><label> ¿Tu pareja ya se ha inscrito? Introduce su código de pareja (opcional)</label><br>259 <input type="text" name="wpcr_pair_join_code" placeholder=" Ej: PAR-XXXXXX" style="text-transform:uppercase;">286 <p style="margin:10px 0 4px;"><label><?php esc_html_e( 'Has your partner already registered? Enter their pair code (optional)', 'opcion5-sports-event-registration' ); ?></label><br> 287 <input type="text" name="wpcr_pair_join_code" placeholder="<?php echo esc_attr__( 'e.g. PAR-XXXXXX', 'opcion5-sports-event-registration' ); ?>" style="text-transform:uppercase;"> 260 288 </p> 261 289 <p style="margin:8px 0 0;font-size:13px;color:#555;"> 262 Si eres el primero de la pareja, deja el código vacío: al terminar tu inscripción recibirás 263 un código y un enlace para que tu pareja complete la suya. Cada uno paga su propia inscripción. 290 <?php esc_html_e( 'If you are the first of the pair, leave the code empty: once you finish you will get a code and a link so your partner can complete theirs. Each of you pays for your own registration.', 'opcion5-sports-event-registration' ); ?> 264 291 </p> 265 292 </div> … … 363 390 echo '<div class="wpcr-price-box">'; 364 391 365 echo "<p><strong> Precio base:</strong> " . number_format($base_price, 2, ',', '.') . " €</p>";392 echo "<p><strong>" . esc_html__( 'Base price:', 'opcion5-sports-event-registration' ) . "</strong> " . number_format($base_price, 2, ',', '.') . " €</p>"; 366 393 367 394 /* ===================================================== … … 384 411 if (!empty($price_extras)): 385 412 386 echo "<p><strong> Extras opcionales:</strong></p>";413 echo "<p><strong>" . esc_html__( 'Optional extras:', 'opcion5-sports-event-registration' ) . "</strong></p>"; 387 414 echo '<div class="wpcr-extras-box">'; 388 415 … … 407 434 esc_html( $label ), 408 435 esc_attr( $name ), 409 esc_html__( 'N inguno', 'opcion5-sports-event-registration' ),436 esc_html__( 'None', 'opcion5-sports-event-registration' ), 410 437 esc_attr( $p ), 411 esc_html( 'Añadir (+' . $price_txt . ')' ) 438 esc_html( sprintf( 439 /* translators: %s: extra price, already formatted with the currency */ 440 __( 'Add (+%s)', 'opcion5-sports-event-registration' ), 441 $price_txt 442 ) ) 412 443 ); 413 444 else: … … 448 479 449 480 <div id="wpcr-total-box" style="margin-top:20px;font-size:18px;font-weight:bold;"> 450 Total inscripción:<span id="wpcr-total-amount">481 <?php esc_html_e( 'Registration total:', 'opcion5-sports-event-registration' ); ?> <span id="wpcr-total-amount"> 451 482 <?php echo number_format($base_price, 2, ',', '.'); ?> € 452 483 </span> … … 487 518 488 519 <span> 489 He leído y acepto la 490 <a href="#" id="wpcr-privacy-link" style="color:#0073aa; text-decoration:underline;"> 491 política de privacidad 492 </a>. 520 <?php printf( 521 /* translators: %s: link with the text "privacy policy" */ 522 esc_html__( 'I have read and accept the %s.', 'opcion5-sports-event-registration' ), 523 '<a href="#" id="wpcr-privacy-link" style="color:#0073aa; text-decoration:underline;">' 524 . esc_html__( 'privacy policy', 'opcion5-sports-event-registration' ) 525 . '</a>' 526 ); ?> 493 527 </span> 494 528 </label> 495 <p id="wpcr-privacy-error" 529 <p id="wpcr-privacy-error" 496 530 style="color:#d63638; font-size:13px; margin-top:6px; display:none;"> 497 Debes aceptar la política de privacidad para continuar.531 <?php esc_html_e( 'You must accept the privacy policy to continue.', 'opcion5-sports-event-registration' ); ?> 498 532 </p> 499 533 … … 519 553 </span> 520 554 521 <h2 style="margin-top:0;"> Política de privacidad</h2>522 <div id="wpcr-modal-content" 555 <h2 style="margin-top:0;"><?php esc_html_e( 'Privacy policy', 'opcion5-sports-event-registration' ); ?></h2> 556 <div id="wpcr-modal-content" 523 557 style="font-size:15px; line-height:1.5; color:#333;"> 524 Cargando…558 <?php esc_html_e( 'Loading…', 'opcion5-sports-event-registration' ); ?> 525 559 </div> 526 560 </div> … … 598 632 <p style="text-align:center;margin-top:2px;"> 599 633 <button type="submit" name="wpcr_register_submit" class="wpcr-submit-btn"> 600 Finalizar inscripción634 <?php esc_html_e( 'Complete registration', 'opcion5-sports-event-registration' ); ?> 601 635 </button> 602 636 </p> … … 641 675 642 676 if(!$public_id){ 643 return "<p style='color:red;'> Debes indicar un public_id → [wpcr_list event=\"PUBLIC_ID\"]</p>";677 return "<p style='color:red;'>" . esc_html__( 'You must provide a public_id → [wpcr_list event="PUBLIC_ID"]', 'opcion5-sports-event-registration' ) . "</p>"; 644 678 } 645 679 … … 663 697 // 3️⃣ Validación 664 698 if(empty($public_id)){ 665 return "<p style='color:red;'>⚠ No se ha especificado ningún public_id.</p>";699 return "<p style='color:red;'>⚠ " . esc_html__( 'No public_id was specified.', 'opcion5-sports-event-registration' ) . "</p>"; 666 700 } 667 701 … … 673 707 674 708 if(!$event){ 675 return "<p>⚠ Evento no encontrado.</p>";709 return "<p>⚠ " . esc_html__( 'Event not found.', 'opcion5-sports-event-registration' ) . "</p>"; 676 710 } 677 711 … … 695 729 // Datos básicos del evento 696 730 $event_name = esc_html($event['name']); 697 $description = !empty($event['description']) ? wp_kses_post(wpautop($event['description'])) : "<i> Descripción no disponible.</i>";731 $description = !empty($event['description']) ? wp_kses_post(wpautop($event['description'])) : "<i>" . esc_html__( 'Description not available.', 'opcion5-sports-event-registration' ) . "</i>"; 698 732 699 733 // Obtener el nombre de la modalidad tal como se introdujo en la administración … … 710 744 $lugar_salida = $event['start_location'] ?? ""; 711 745 $fecha_evento_raw = $event['event_date'] ?? ""; 712 $fecha_evento = $fecha_evento_raw && $fecha_evento_raw !== "0000-00-00" 713 ? date_i18n("d/m/Y", strtotime($fecha_evento_raw)) 714 : ""; 746 $fecha_evento = wpcr_format_date( $fecha_evento_raw ); 715 747 716 748 $start_time_raw = $event['start_time'] ?? ""; 717 $start_time = $start_time_raw ? date_i18n("H:i", strtotime($start_time_raw))."h" : "-";749 $start_time = wpcr_format_time( $start_time_raw, "-" ); 718 750 719 751 $reg_open_raw = $event['reg_open'] ?? ""; 720 752 $reg_close_raw = $event['reg_close'] ?? ""; 721 753 722 $reg_open = $reg_open_raw ? date_i18n("d/m/Y H:i", strtotime($reg_open_raw))."h" : "-";723 $reg_close = $reg_close_raw ? date_i18n("d/m/Y H:i", strtotime($reg_close_raw))."h" : "-";754 $reg_open = wpcr_format_datetime( $reg_open_raw, "-" ); 755 $reg_close = wpcr_format_datetime( $reg_close_raw, "-" ); 724 756 725 757 // Estado inscripción (necesario antes de renderizar el botón) … … 765 797 $price = isset($r['price']) ? floatval($r['price']) : null; 766 798 if (!$price) continue; 767 $from_fmt = $from ? date_i18n('d/m/Y', strtotime($from)) : ''; 768 $to_fmt = $to ? date_i18n('d/m/Y', strtotime($to)) : ''; 769 if ($from_fmt && $to_fmt) $label = "Del {$from_fmt} al {$to_fmt}"; 770 elseif ($from_fmt) $label = "Desde {$from_fmt}"; 771 elseif ($to_fmt) $label = "Hasta {$to_fmt}"; 772 else $label = ''; 799 $from_fmt = wpcr_format_date( $from ); 800 $to_fmt = wpcr_format_date( $to ); 801 if ($from_fmt && $to_fmt) { 802 /* translators: 1: start date, 2: end date */ 803 $label = sprintf( __( 'From %1$s to %2$s', 'opcion5-sports-event-registration' ), $from_fmt, $to_fmt ); 804 } elseif ($from_fmt) { 805 /* translators: %s: start date */ 806 $label = sprintf( __( 'From %s', 'opcion5-sports-event-registration' ), $from_fmt ); 807 } elseif ($to_fmt) { 808 /* translators: %s: end date */ 809 $label = sprintf( __( 'Until %s', 'opcion5-sports-event-registration' ), $to_fmt ); 810 } else { 811 $label = ''; 812 } 773 813 $rows[] = ['label' => $label, 'price' => number_format($price, 2, ',', '.') . ' €']; 774 814 } … … 816 856 <!-- PESTAÑAS - TABS --> 817 857 <div class="wpcr-tabs"> 818 <button class="wpcr-tab-btn active" data-tab="info">ℹ DETALLES</button>819 <button class="wpcr-tab-btn" data-tab="tech">📁 FICHA TÉCNICA</button>820 <button class="wpcr-tab-btn" data-tab="form">📝 INSCRIPCIÓN</button>821 <button class="wpcr-tab-btn" data-tab="list">📋 INSCRITOS</button>858 <button class="wpcr-tab-btn active" data-tab="info">ℹ <?php esc_html_e( 'DETAILS', 'opcion5-sports-event-registration' ); ?></button> 859 <button class="wpcr-tab-btn" data-tab="tech">📁 <?php esc_html_e( 'RACE INFO', 'opcion5-sports-event-registration' ); ?></button> 860 <button class="wpcr-tab-btn" data-tab="form">📝 <?php esc_html_e( 'REGISTRATION', 'opcion5-sports-event-registration' ); ?></button> 861 <button class="wpcr-tab-btn" data-tab="list">📋 <?php esc_html_e( 'ENTRANTS', 'opcion5-sports-event-registration' ); ?></button> 822 862 <?php if ( ( function_exists('wpcr_is_addon_active') && wpcr_is_addon_active('wpcr-results') ) || $wpcr_is_stage_event ) : ?> 823 <button class="wpcr-tab-btn" data-tab="results">🏁 <?php echo $wpcr_is_stage_event ? 'CLASIFICACIONES' : 'RESULTADOS'; ?><?php if ( $wpcr_live ) : ?> <span class="wpcr-live-dot" title="En directo"></span><?php endif; ?></button>863 <button class="wpcr-tab-btn" data-tab="results">🏁 <?php echo $wpcr_is_stage_event ? esc_html__( 'STANDINGS', 'opcion5-sports-event-registration' ) : esc_html__( 'RESULTS', 'opcion5-sports-event-registration' ); ?><?php if ( $wpcr_live ) : ?> <span class="wpcr-live-dot" title="<?php echo esc_attr__( 'Live', 'opcion5-sports-event-registration' ); ?>"></span><?php endif; ?></button> 824 864 <?php endif; ?> 825 865 <?php if ( ( function_exists('wpcr_is_addon_active') && wpcr_is_addon_active('wpcr-participant-area') ) ) : ?> 826 <button class="wpcr-tab-btn" data-tab="area-privada">🔐 ACCESO PARTICIPANTES</button>866 <button class="wpcr-tab-btn" data-tab="area-privada">🔐 <?php esc_html_e( 'PARTICIPANT ACCESS', 'opcion5-sports-event-registration' ); ?></button> 827 867 <?php endif; ?> 828 868 </div> … … 835 875 <h2 class="wpcr-event-title"><?php echo esc_html($event_name); ?> 836 876 <?php if ( $wpcr_live ) : ?> 837 <a href="#" class="wpcr-live-badge wpcr-live-goto" style="text-decoration:none;margin-left:8px;"><span class="wpcr-live-dot"></span> En directo</a>877 <a href="#" class="wpcr-live-badge wpcr-live-goto" style="text-decoration:none;margin-left:8px;"><span class="wpcr-live-dot"></span> <?php esc_html_e( 'Live', 'opcion5-sports-event-registration' ); ?></a> 838 878 <?php endif; ?> 839 879 </h2> … … 849 889 ?> 850 890 851 <p><span class="wpcr-meta"> Modalidad:</span> <?php echo esc_html($modalidad); ?></p>891 <p><span class="wpcr-meta"><?php esc_html_e( 'Discipline:', 'opcion5-sports-event-registration' ); ?></span> <?php echo esc_html($modalidad); ?></p> 852 892 853 893 <?php 854 894 if (!empty($localidad)) { 855 echo "<p><span class='wpcr-meta'> Ubicación:</span> " . esc_html($localidad);895 echo "<p><span class='wpcr-meta'>" . esc_html__( 'Location:', 'opcion5-sports-event-registration' ) . "</span> " . esc_html($localidad); 856 896 if (!empty($provincia)) echo " (" . esc_html($provincia) . ")"; 857 897 echo "</p>"; 858 898 } 859 if (!empty($lugar_salida)) echo "<p><span class='wpcr-meta'> Lugar de salida:</span> " . esc_html($lugar_salida) . "</p>";860 if (!empty($fecha_evento)) echo "<p><span class='wpcr-meta'> Fecha de celebración:</span> " . esc_html($fecha_evento) . "</p>";861 if (!empty($start_time_raw) && $start_time_raw !== "00:00:00") echo "<p><span class='wpcr-meta'> Hora de salida:</span> " . esc_html($start_time) . "</p>";862 if (!empty($reg_open_raw) && $reg_open_raw !== "0000-00-00 00:00:00") echo "<p><span class='wpcr-meta'> Apertura de inscrip.:</span> " . esc_html($reg_open) . "</p>";863 if (!empty($reg_close_raw) && $reg_close_raw !== "0000-00-00 00:00:00") echo "<p><span class='wpcr-meta'> Cierre de inscrip.:</span> " . esc_html($reg_close) . "</p>";899 if (!empty($lugar_salida)) echo "<p><span class='wpcr-meta'>" . esc_html__( 'Start location:', 'opcion5-sports-event-registration' ) . "</span> " . esc_html($lugar_salida) . "</p>"; 900 if (!empty($fecha_evento)) echo "<p><span class='wpcr-meta'>" . esc_html__( 'Event date:', 'opcion5-sports-event-registration' ) . "</span> " . esc_html($fecha_evento) . "</p>"; 901 if (!empty($start_time_raw) && $start_time_raw !== "00:00:00") echo "<p><span class='wpcr-meta'>" . esc_html__( 'Start time:', 'opcion5-sports-event-registration' ) . "</span> " . esc_html($start_time) . "</p>"; 902 if (!empty($reg_open_raw) && $reg_open_raw !== "0000-00-00 00:00:00") echo "<p><span class='wpcr-meta'>" . esc_html__( 'Registration opens:', 'opcion5-sports-event-registration' ) . "</span> " . esc_html($reg_open) . "</p>"; 903 if (!empty($reg_close_raw) && $reg_close_raw !== "0000-00-00 00:00:00") echo "<p><span class='wpcr-meta'>" . esc_html__( 'Registration closes:', 'opcion5-sports-event-registration' ) . "</span> " . esc_html($reg_close) . "</p>"; 864 904 ?> 865 905 … … 900 940 <div class="wpcr-price-section"> 901 941 902 <p><span class="wpcr-meta"> Precio base:</span>942 <p><span class="wpcr-meta"><?php esc_html_e( 'Base price:', 'opcion5-sports-event-registration' ); ?></span> 903 943 <strong><?php echo number_format($base_price, 2, ',', '.'); ?> €</strong> 904 944 </p> … … 909 949 if ( $show_results_btn && ( ( function_exists('wpcr_is_addon_active') && wpcr_is_addon_active('wpcr-results') ) || $wpcr_is_stage_event ) ) : ?> 910 950 <a href="javascript:void(0);" class="wpcr-btn-insc" data-goto-tab="results" 911 style="background:#0059D1;">🏁 CLASIFICACIONES</a>951 style="background:#0059D1;">🏁 <?php esc_html_e( 'STANDINGS', 'opcion5-sports-event-registration' ); ?></a> 912 952 <?php elseif ( ! $show_results_btn ) : ?> 913 <a href="javascript:void(0);" class="wpcr-btn-insc" data-goto-tab="form"> INSCRIBIRME</a>953 <a href="javascript:void(0);" class="wpcr-btn-insc" data-goto-tab="form"><?php esc_html_e( 'REGISTER', 'opcion5-sports-event-registration' ); ?></a> 914 954 <?php endif; ?> 915 955 … … 930 970 <div id="wpcr-countdown-title" 931 971 style="font-size:22px; font-weight:700; color:#002e77; margin-bottom:8px;"> 932 Quedan...972 <?php esc_html_e( 'Time left...', 'opcion5-sports-event-registration' ); ?> 933 973 </div> 934 974 <div id="wpcr-countdown" 935 975 style="font-size:24px; font-weight:bold; color:#003d99;"> 936 Cargando cuenta atrás…976 <?php esc_html_e( 'Loading countdown…', 'opcion5-sports-event-registration' ); ?> 937 977 </div> 938 978 </div> 939 979 940 <?php wpcr_inline_js( 'var wpcrCountdownStart = ' . wp_json_encode( (string) $start_datetime_js ) . ";\n" . <<<'JS' 980 <?php wpcr_inline_js( 'var wpcrCountdownStart = ' . wp_json_encode( (string) $start_datetime_js ) . ";\n" 981 // Los textos viajan en una variable serializada: dentro del nowdoc 982 // no se pueden traducir porque PHP no procesa nada ahí dentro. 983 . 'var wpcrCountdownI18n = ' . wp_json_encode( [ 984 'noDate' => __( 'Date not available', 'opcion5-sports-event-registration' ), 985 'finished' => __( 'The event has finished.', 'opcion5-sports-event-registration' ), 986 'started' => __( 'The event has started!', 'opcion5-sports-event-registration' ), 987 'timeLeft' => __( 'Time left...', 'opcion5-sports-event-registration' ), 988 ] ) . ";\n" . <<<'JS' 941 989 document.addEventListener("DOMContentLoaded", function() { 942 990 // cuenta atrás - defensiva: si no hay fecha, no romper … … 950 998 const now = new Date().getTime(); 951 999 if (isNaN(eventStart)) { 952 countdownEl. innerHTML = "Fecha no disponible";1000 countdownEl.textContent = wpcrCountdownI18n.noDate; 953 1001 return; 954 1002 } 955 1003 if (now > eventEnd) { 956 titleEl. innerHTML= "";957 countdownEl. innerHTML = "El evento ha finalizado.";1004 titleEl.textContent = ""; 1005 countdownEl.textContent = wpcrCountdownI18n.finished; 958 1006 return; 959 1007 } 960 1008 if (now >= eventStart && now <= eventEnd) { 961 titleEl. innerHTML= "";962 countdownEl. innerHTML = "¡¡ El evento ha comenzado !!";1009 titleEl.textContent = ""; 1010 countdownEl.textContent = wpcrCountdownI18n.started; 963 1011 return; 964 1012 } … … 968 1016 const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); 969 1017 const seconds = Math.floor((distance % (1000 * 60)) / 1000); 970 titleEl. innerHTML = "Quedan...";971 countdownEl. innerHTML= days + "d " + hours + "h " + minutes + "m " + seconds + "s";1018 titleEl.textContent = wpcrCountdownI18n.timeLeft; 1019 countdownEl.textContent = days + "d " + hours + "h " + minutes + "m " + seconds + "s"; 972 1020 } 973 1021 updateCountdown(); … … 984 1032 <div class="wpcr-right" style="text-align:center;"> 985 1033 <?php if($poster_url): ?> 986 <img src="<?php echo esc_url($poster_url); ?>" class="wpcr-poster" alt=" Cartel del evento" />1034 <img src="<?php echo esc_url($poster_url); ?>" class="wpcr-poster" alt="<?php echo esc_attr__( 'Event poster', 'opcion5-sports-event-registration' ); ?>" /> 987 1035 <?php endif; ?> 988 1036 … … 1005 1053 'x' => [ 'label' => 'X (Twitter)', 'svg' => '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M18.24 2.25h3.31l-7.23 8.26 8.5 11.24h-6.66l-5.21-6.82-5.97 6.82H1.67l7.73-8.84L1.25 2.25h6.83l4.71 6.23 5.45-6.23Zm-1.16 17.52h1.83L7.08 4.13H5.12l11.96 15.64Z"/></svg>' ], 1006 1054 'instagram' => [ 'label' => 'Instagram', 'svg' => '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2.16c3.2 0 3.58.01 4.85.07 1.17.05 1.8.25 2.23.41.56.22.96.48 1.38.9.42.42.68.82.9 1.38.16.42.36 1.06.41 2.23.06 1.27.07 1.65.07 4.85s-.01 3.58-.07 4.85c-.05 1.17-.25 1.8-.41 2.23a3.7 3.7 0 0 1-.9 1.38c-.42.42-.82.68-1.38.9-.42.16-1.06.36-2.23.41-1.27.06-1.65.07-4.85.07s-3.58-.01-4.85-.07c-1.17-.05-1.8-.25-2.23-.41a3.72 3.72 0 0 1-1.38-.9 3.72 3.72 0 0 1-.9-1.38c-.16-.42-.36-1.06-.41-2.23-.06-1.27-.07-1.65-.07-4.85s.01-3.58.07-4.85c.05-1.17.25-1.8.41-2.23.22-.56.48-.96.9-1.38.42-.42.82-.68 1.38-.9.42-.16 1.06-.36 2.23-.41 1.27-.06 1.65-.07 4.85-.07M12 0C8.74 0 8.33.01 7.05.07 5.78.13 4.9.33 4.14.63a5.88 5.88 0 0 0-2.13 1.38A5.88 5.88 0 0 0 .63 4.14C.33 4.9.13 5.78.07 7.05.01 8.33 0 8.74 0 12s.01 3.67.07 4.95c.06 1.27.26 2.15.56 2.91.31.8.72 1.47 1.38 2.13a5.88 5.88 0 0 0 2.13 1.38c.76.3 1.64.5 2.91.56C8.33 23.99 8.74 24 12 24s3.67-.01 4.95-.07c1.27-.06 2.15-.26 2.91-.56a5.88 5.88 0 0 0 2.13-1.38 5.88 5.88 0 0 0 1.38-2.13c.3-.76.5-1.64.56-2.91.06-1.28.07-1.69.07-4.95s-.01-3.67-.07-4.95c-.06-1.27-.26-2.15-.56-2.91a5.88 5.88 0 0 0-1.38-2.13A5.88 5.88 0 0 0 19.86.63c-.76-.3-1.64-.5-2.91-.56C15.67.01 15.26 0 12 0Zm0 5.84A6.16 6.16 0 1 0 18.16 12 6.16 6.16 0 0 0 12 5.84Zm0 10.15A4 4 0 1 1 16 12a4 4 0 0 1-4 3.99Zm7.84-10.4a1.44 1.44 0 1 1-1.44-1.44 1.44 1.44 0 0 1 1.44 1.44Z"/></svg>' ], 1007 'web' => [ 'label' => 'Página web', 'svg' => '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2Zm7.93 9h-3.02a15.65 15.65 0 0 0-1.27-5.75A8.03 8.03 0 0 1 19.93 11ZM12 4.04A13.87 13.87 0 0 1 14.9 11H9.1A13.87 13.87 0 0 1 12 4.04ZM4.07 13h3.02a15.65 15.65 0 0 0 1.27 5.75A8.03 8.03 0 0 1 4.07 13Zm3.02-2H4.07a8.03 8.03 0 0 1 4.29-5.75A15.65 15.65 0 0 0 7.09 11ZM12 19.96A13.87 13.87 0 0 1 9.1 13h5.8a13.87 13.87 0 0 1-2.9 6.96Zm3.64-1.21A15.65 15.65 0 0 0 16.91 13h3.02a8.03 8.03 0 0 1-4.29 5.75Z"/></svg>' ],1008 'otros' => [ 'label' => 'Otros canales', 'svg' => '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M10.59 13.41a1 1 0 0 1 0-1.41l2.83-2.83a1 1 0 0 1 1.41 1.41l-2.83 2.83a1 1 0 0 1-1.41 0Zm-2.12 4.95a3 3 0 0 1-4.24-4.24l2.83-2.83a3 3 0 0 1 4.24 0 1 1 0 0 1-1.41 1.41 1 1 0 0 0-1.41 0l-2.83 2.83a1 1 0 0 0 1.41 1.41l1.41-1.41a1 1 0 0 1 1.42 1.42Zm11.31-7.07-2.83 2.83a3 3 0 0 1-4.24 0 1 1 0 0 1 1.41-1.41 1 1 0 0 0 1.41 0l2.83-2.83a1 1 0 1 0-1.41-1.41l-1.41 1.41a1 1 0 0 1-1.42-1.42l1.42-1.41a3 3 0 0 1 4.24 4.24Z"/></svg>' ],1055 'web' => [ 'label' => __( 'Website', 'opcion5-sports-event-registration' ), 'svg' => '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2Zm7.93 9h-3.02a15.65 15.65 0 0 0-1.27-5.75A8.03 8.03 0 0 1 19.93 11ZM12 4.04A13.87 13.87 0 0 1 14.9 11H9.1A13.87 13.87 0 0 1 12 4.04ZM4.07 13h3.02a15.65 15.65 0 0 0 1.27 5.75A8.03 8.03 0 0 1 4.07 13Zm3.02-2H4.07a8.03 8.03 0 0 1 4.29-5.75A15.65 15.65 0 0 0 7.09 11ZM12 19.96A13.87 13.87 0 0 1 9.1 13h5.8a13.87 13.87 0 0 1-2.9 6.96Zm3.64-1.21A15.65 15.65 0 0 0 16.91 13h3.02a8.03 8.03 0 0 1-4.29 5.75Z"/></svg>' ], 1056 'otros' => [ 'label' => __( 'Other channels', 'opcion5-sports-event-registration' ), 'svg' => '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M10.59 13.41a1 1 0 0 1 0-1.41l2.83-2.83a1 1 0 0 1 1.41 1.41l-2.83 2.83a1 1 0 0 1-1.41 0Zm-2.12 4.95a3 3 0 0 1-4.24-4.24l2.83-2.83a3 3 0 0 1 4.24 0 1 1 0 0 1-1.41 1.41 1 1 0 0 0-1.41 0l-2.83 2.83a1 1 0 0 0 1.41 1.41l1.41-1.41a1 1 0 0 1 1.42 1.42Zm11.31-7.07-2.83 2.83a3 3 0 0 1-4.24 0 1 1 0 0 1 1.41-1.41 1 1 0 0 0 1.41 0l2.83-2.83a1 1 0 1 0-1.41-1.41l-1.41 1.41a1 1 0 0 1-1.42-1.42l1.42-1.41a3 3 0 0 1 4.24 4.24Z"/></svg>' ], 1009 1057 ]; 1010 1058 ?> 1011 1059 <div class="wpcr-comm-channels"> 1012 <h4 class="wpcr-comm-title"><?php echo count( $comm_channels ) === 1 ? 'Canal de comunicación del evento' : 'Canales de comunicación del evento'; ?></h4> 1060 <h4 class="wpcr-comm-title"><?php echo esc_html( _n( 1061 'Event communication channel', 1062 'Event communication channels', 1063 count( $comm_channels ), 1064 'opcion5-sports-event-registration' 1065 ) ); ?></h4> 1013 1066 <div class="wpcr-comm-icons"> 1014 1067 <?php foreach ( $comm_icons as $key => $icon ) : … … 1043 1096 1044 1097 if (!empty($event['organizer_name_public']) && !empty($event['organizer_name'])) { 1045 $org_rows[ 'Organizador'] = esc_html($event['organizer_name']);1098 $org_rows[ __( 'Organizer', 'opcion5-sports-event-registration' ) ] = esc_html($event['organizer_name']); 1046 1099 } 1047 1100 1048 1101 if (!empty($event['organizer_email_public']) && !empty($event['organizer_email'])) { 1049 $org_rows[ 'Email'] = '<a href="mailto:' . esc_attr($event['organizer_email']) . '">' .1102 $org_rows[ __( 'Email', 'opcion5-sports-event-registration' ) ] = '<a href="mailto:' . esc_attr($event['organizer_email']) . '">' . 1050 1103 esc_html($event['organizer_email']) . '</a>'; 1051 1104 } 1052 1105 1053 1106 if (!empty($event['organizer_phone_public']) && !empty($event['organizer_phone'])) { 1054 $org_rows[ 'Teléfono'] = esc_html($event['organizer_phone']);1107 $org_rows[ __( 'Phone', 'opcion5-sports-event-registration' ) ] = esc_html($event['organizer_phone']); 1055 1108 } 1056 1109 ?> 1057 1110 1058 1111 <?php if (!empty($org_rows)): ?> 1059 <h3 style="margin-top:0;"> Datos del organizador</h3>1112 <h3 style="margin-top:0;"><?php esc_html_e( 'Organizer details', 'opcion5-sports-event-registration' ); ?></h3> 1060 1113 <table class="wpcr-tech-table"> 1061 1114 <?php foreach ($org_rows as $label => $value): ?> … … 1076 1129 1077 1130 if ( ! empty( $event['start_time'] ) ) { 1078 $ficha_rows[ 'Hora de salida'] = esc_html( substr( $event['start_time'], 0, 5 ) ) . 'h';1131 $ficha_rows[ __( 'Start time', 'opcion5-sports-event-registration' ) ] = esc_html( wpcr_format_time( $event['start_time'] ) ); 1079 1132 } 1080 1133 if ( ! empty( $event['reg_open'] ) && $event['reg_open'] !== '0000-00-00 00:00:00' ) { 1081 $ficha_rows[ 'Apertura de inscripciones'] = esc_html( date_i18n( 'd/m/Y H:i', strtotime( $event['reg_open'] )) );1134 $ficha_rows[ __( 'Registration opens', 'opcion5-sports-event-registration' ) ] = esc_html( wpcr_format_datetime( $event['reg_open'] ) ); 1082 1135 } 1083 1136 if ( ! empty( $event['reg_close'] ) && $event['reg_close'] !== '0000-00-00 00:00:00' ) { 1084 $ficha_rows[ 'Cierre de inscripciones'] = esc_html( date_i18n( 'd/m/Y H:i', strtotime( $event['reg_close'] )) );1137 $ficha_rows[ __( 'Registration closes', 'opcion5-sports-event-registration' ) ] = esc_html( wpcr_format_datetime( $event['reg_close'] ) ); 1085 1138 } 1086 1139 if ( ! empty( $event['start_location'] ) ) { 1087 $ficha_rows[ 'Lugar de salida'] = esc_html( $event['start_location'] );1140 $ficha_rows[ __( 'Start location', 'opcion5-sports-event-registration' ) ] = esc_html( $event['start_location'] ); 1088 1141 } 1089 1142 … … 1095 1148 ) ); 1096 1149 $disponibles = max( 0, (int) $event['max_participants'] - $inscritos_count ); 1097 $ficha_rows['Plazas disponibles'] = $disponibles . ' de ' . (int) $event['max_participants']; 1150 $ficha_rows[ __( 'Places available', 'opcion5-sports-event-registration' ) ] = sprintf( 1151 /* translators: 1: places still free, 2: total places */ 1152 __( '%1$d of %2$d', 'opcion5-sports-event-registration' ), 1153 $disponibles, 1154 (int) $event['max_participants'] 1155 ); 1098 1156 } 1099 1157 … … 1105 1163 ) ); 1106 1164 $pairs_disponibles = max( 0, (int) $event['pairs_max_couples'] - $started_pairs ); 1107 $ficha_rows['Plazas de parejas'] = $pairs_disponibles . ' de ' . (int) $event['pairs_max_couples']; 1165 $ficha_rows[ __( 'Pair places', 'opcion5-sports-event-registration' ) ] = sprintf( 1166 /* translators: 1: pair places still free, 2: total pair places */ 1167 __( '%1$d of %2$d', 'opcion5-sports-event-registration' ), 1168 $pairs_disponibles, 1169 (int) $event['pairs_max_couples'] 1170 ); 1108 1171 } 1109 1172 … … 1115 1178 ) ); 1116 1179 if ( $ficha_cats ) { 1117 $ficha_rows[ 'Categorías'] = esc_html( implode( ', ', $ficha_cats ) );1180 $ficha_rows[ __( 'Categories', 'opcion5-sports-event-registration' ) ] = esc_html( implode( ', ', $ficha_cats ) ); 1118 1181 } 1119 1182 } … … 1123 1186 1124 1187 if ( $ficha_price_mode === 'free' ) { 1125 $ficha_rows[ 'Precio'] = 'Gratuito';1188 $ficha_rows[ __( 'Price', 'opcion5-sports-event-registration' ) ] = __( 'Free', 'opcion5-sports-event-registration' ); 1126 1189 } elseif ( $ficha_price_mode === 'fixed' && (float) ( $event['fixed_price'] ?? 0 ) > 0 ) { 1127 $ficha_rows[ 'Precio'] = number_format( (float) $event['fixed_price'], 2, ',', '.' ) . ' €';1190 $ficha_rows[ __( 'Price', 'opcion5-sports-event-registration' ) ] = number_format( (float) $event['fixed_price'], 2, ',', '.' ) . ' €'; 1128 1191 } elseif ( $ficha_price_mode === 'ranges' ) { 1129 1192 $ficha_ranges = json_decode( $event['price_ranges'] ?? '[]', true ); … … 1136 1199 $from = $r['start'] ?? ( $r['from'] ?? '' ); 1137 1200 $to = $r['end'] ?? ( $r['to'] ?? '' ); 1138 $from_fmt = $from ? date_i18n( 'd/m/Y', strtotime( $from ) ) : '';1139 $to_fmt = $to ? date_i18n( 'd/m/Y', strtotime( $to ) ) : '';1201 $from_fmt = wpcr_format_date( $from ); 1202 $to_fmt = wpcr_format_date( $to ); 1140 1203 1141 1204 if ( $from_fmt && $to_fmt ) { 1142 $label = "Del {$from_fmt} al {$to_fmt}"; 1205 /* translators: 1: start date, 2: end date */ 1206 $label = sprintf( __( 'From %1$s to %2$s', 'opcion5-sports-event-registration' ), $from_fmt, $to_fmt ); 1143 1207 } elseif ( $from_fmt ) { 1144 $label = "Desde {$from_fmt}"; 1208 /* translators: %s: start date */ 1209 $label = sprintf( __( 'From %s', 'opcion5-sports-event-registration' ), $from_fmt ); 1145 1210 } elseif ( $to_fmt ) { 1146 $label = "Hasta {$to_fmt}"; 1211 /* translators: %s: end date */ 1212 $label = sprintf( __( 'Until %s', 'opcion5-sports-event-registration' ), $to_fmt ); 1147 1213 } else { 1148 1214 continue; … … 1153 1219 } 1154 1220 if ( $range_lines ) { 1155 $ficha_rows[ 'Precio por franjas'] = implode( '<br>', $range_lines );1221 $ficha_rows[ __( 'Price by date', 'opcion5-sports-event-registration' ) ] = implode( '<br>', $range_lines ); 1156 1222 } 1157 1223 } … … 1169 1235 } 1170 1236 if ( $extra_lines ) { 1171 $ficha_rows[ 'Extras opcionales'] = implode( '<br>', $extra_lines );1237 $ficha_rows[ __( 'Optional extras', 'opcion5-sports-event-registration' ) ] = implode( '<br>', $extra_lines ); 1172 1238 } 1173 1239 ?> 1174 1240 1175 1241 <?php if ( ! empty( $ficha_rows ) ) : ?> 1176 <h3 style="margin-top:30px;"> Ficha técnica</h3>1242 <h3 style="margin-top:30px;"><?php esc_html_e( 'Race info', 'opcion5-sports-event-registration' ); ?></h3> 1177 1243 <table class="wpcr-tech-table"> 1178 1244 <?php foreach ( $ficha_rows as $label => $value ) : ?> … … 1198 1264 1199 1265 <?php if ( $ficha_distances_html !== '' ) : ?> 1200 <h3 style="margin-top:30px;"> Distancias y precios</h3>1266 <h3 style="margin-top:30px;"><?php esc_html_e( 'Distances and prices', 'opcion5-sports-event-registration' ); ?></h3> 1201 1267 <?php echo wp_kses( $ficha_distances_html, wpcr_kses_allowed_html() ); ?> 1202 1268 <?php endif; ?> … … 1212 1278 <?php if ( ! empty( $event['tech_observations'] ) ) : ?> 1213 1279 <div style="margin:16px 0;padding:14px 16px;background:#f8fafc;border-left:3px solid #0077cc;border-radius:6px;"> 1214 <strong style="display:block;margin-bottom:6px;"> Observaciones</strong>1280 <strong style="display:block;margin-bottom:6px;"><?php esc_html_e( 'Notes', 'opcion5-sports-event-registration' ); ?></strong> 1215 1281 <div style="white-space:pre-line;color:#333;font-size:14px;line-height:1.5;"><?php echo wp_kses_post( $event['tech_observations'] ); ?></div> 1216 1282 </div> … … 1234 1300 1235 1301 <?php if (!empty($docs)): ?> 1236 <h3 style="margin-top:30px;"> Documentación técnica</h3>1302 <h3 style="margin-top:30px;"><?php esc_html_e( 'Event documents', 'opcion5-sports-event-registration' ); ?></h3> 1237 1303 1238 1304 <table class="wpcr-tech-docs"> 1239 1305 <thead> 1240 1306 <tr> 1241 <th style="width:8%;text-align:center;"> Tipo</th>1242 <th style="width:20%;"> Título</th>1243 <th style="width:52%;"> Descripción</th>1244 <th style="width:20%;"> Documento</th>1307 <th style="width:8%;text-align:center;"><?php esc_html_e( 'Type', 'opcion5-sports-event-registration' ); ?></th> 1308 <th style="width:20%;"><?php esc_html_e( 'Title', 'opcion5-sports-event-registration' ); ?></th> 1309 <th style="width:52%;"><?php esc_html_e( 'Description', 'opcion5-sports-event-registration' ); ?></th> 1310 <th style="width:20%;"><?php esc_html_e( 'Document', 'opcion5-sports-event-registration' ); ?></th> 1245 1311 </tr> 1246 1312 </thead> … … 1275 1341 download 1276 1342 class="wpcr-download-btn"> 1277 Descargar1343 <?php esc_html_e( 'Download', 'opcion5-sports-event-registration' ); ?> 1278 1344 </a> 1279 1345 </td> … … 1307 1373 <div style="text-align:center;padding:35px 20px;background:#f0f7ff;border:1px solid #b3d4ff;border-radius:8px;margin-top:15px;"> 1308 1374 <p style="font-size:22px;margin:0 0 6px;">🗓️</p> 1309 <p style="font-size:17px;font-weight:600;margin:0 0 4px;">Las inscripciones aún no están abiertas</p> 1310 <p style="color:#555;margin:0 0 16px;">Abrirán el <strong><?php echo esc_html($reg_open); ?></strong></p> 1375 <p style="font-size:17px;font-weight:600;margin:0 0 4px;"><?php esc_html_e( 'Registration is not open yet', 'opcion5-sports-event-registration' ); ?></p> 1376 <p style="color:#555;margin:0 0 16px;"><?php printf( 1377 /* translators: %s: date and time when registration opens */ 1378 esc_html__( 'It opens on %s', 'opcion5-sports-event-registration' ), 1379 '<strong>' . esc_html($reg_open) . '</strong>' 1380 ); ?></p> 1311 1381 <div id="wpcr-reg-countdown" style="font-size:26px;font-weight:700;color:#0077cc;letter-spacing:2px;">--</div> 1312 <p style="color:#888;font-size:12px;margin:6px 0 0;"> días · horas · minutos · segundos</p>1382 <p style="color:#888;font-size:12px;margin:6px 0 0;"><?php esc_html_e( 'days · hours · minutes · seconds', 'opcion5-sports-event-registration' ); ?></p> 1313 1383 </div> 1314 <?php wpcr_inline_js( 'var wpcrRegOpenTs = ' . (int) $open_ts . ";\n" . <<<'JS' 1384 <?php wpcr_inline_js( 'var wpcrRegOpenTs = ' . (int) $open_ts . ";\n" 1385 . 'var wpcrRegOpenMsg = ' . wp_json_encode( __( 'Now open!', 'opcion5-sports-event-registration' ) ) . ";\n" . <<<'JS' 1315 1386 (function(){ 1316 1387 var target = wpcrRegOpenTs * 1000; … … 1318 1389 function tick(){ 1319 1390 var diff = target - Date.now(); 1320 if(diff <= 0){ el.textContent = '¡Ya abiertas!'; return; }1391 if(diff <= 0){ el.textContent = wpcrRegOpenMsg; return; } 1321 1392 var d = Math.floor(diff/86400000); 1322 1393 var h = Math.floor((diff%86400000)/3600000); … … 1334 1405 <div style="text-align:center;padding:35px 20px;background:#fff3f3;border:1px solid #ffb3b3;border-radius:8px;margin-top:15px;"> 1335 1406 <p style="font-size:22px;margin:0 0 6px;">🔒</p> 1336 <p style="font-size:17px;font-weight:600;margin:0 0 6px;"> Inscripciones cerradas</p>1407 <p style="font-size:17px;font-weight:600;margin:0 0 6px;"><?php esc_html_e( 'Registration closed', 'opcion5-sports-event-registration' ); ?></p> 1337 1408 <?php if ( $close_ts && $now > $close_ts ) : ?> 1338 <p style="color:#555;margin:0;">El plazo de inscripción finalizó el <strong><?php echo esc_html($reg_close); ?></strong>.</p> 1409 <p style="color:#555;margin:0;"><?php printf( 1410 /* translators: %s: date and time when registration closed */ 1411 esc_html__( 'Registration closed on %s.', 'opcion5-sports-event-registration' ), 1412 '<strong>' . esc_html($reg_close) . '</strong>' 1413 ); ?></p> 1339 1414 <?php elseif ( ( function_exists('wpcr_is_addon_active') && wpcr_is_addon_active('wpcr-results') ) || $wpcr_is_stage_event ) : ?> 1340 <p style="color:#555;margin:0;">Este evento ya se ha celebrado. Consulta las clasificaciones en la pestaña <strong>🏁 Resultados</strong>.</p> 1415 <p style="color:#555;margin:0;"><?php printf( 1416 /* translators: %s: name of the results tab, in bold */ 1417 esc_html__( 'This event has already taken place. See the standings in the %s tab.', 'opcion5-sports-event-registration' ), 1418 '<strong>🏁 ' . esc_html__( 'RESULTS', 'opcion5-sports-event-registration' ) . '</strong>' 1419 ); ?></p> 1341 1420 <?php else : ?> 1342 <p style="color:#555;margin:0;"> Este evento ya se ha celebrado.</p>1421 <p style="color:#555;margin:0;"><?php esc_html_e( 'This event has already taken place.', 'opcion5-sports-event-registration' ); ?></p> 1343 1422 <?php endif; ?> 1344 1423 </div> … … 1348 1427 <?php if ( $close_ts ) : ?> 1349 1428 <div style="background:#fff8e1;border:1px solid #ffe082;border-radius:6px;padding:10px 16px;margin-bottom:14px;font-size:14px;display:flex;align-items:center;gap:8px;"> 1350 ⚠️ <span>Las inscripciones cierran el <strong><?php echo esc_html($reg_close); ?></strong></span> 1429 ⚠️ <span><?php printf( 1430 /* translators: %s: date and time when registration closes */ 1431 esc_html__( 'Registration closes on %s', 'opcion5-sports-event-registration' ), 1432 '<strong>' . esc_html($reg_close) . '</strong>' 1433 ); ?></span> 1351 1434 </div> 1352 1435 <?php endif; ?> … … 1371 1454 <div id="wpcr-live-box" style="border:2px solid #fca5a5;border-radius:10px;padding:16px 18px;margin:15px 0;background:#fff;"> 1372 1455 <div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px;"> 1373 <span class="wpcr-live-badge"><span class="wpcr-live-dot"></span> En directo</span>1374 <strong style="font-size:16px;"> Seguimiento de la carrera</strong>1456 <span class="wpcr-live-badge"><span class="wpcr-live-dot"></span> <?php esc_html_e( 'Live', 'opcion5-sports-event-registration' ); ?></span> 1457 <strong style="font-size:16px;"><?php esc_html_e( 'Race tracking', 'opcion5-sports-event-registration' ); ?></strong> 1375 1458 <span id="wpcr-live-updated" style="font-size:12px;color:#888;margin-left:auto;"></span> 1376 1459 </div> 1377 1460 <div id="wpcr-live-points" style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px;"></div> 1378 <div id="wpcr-live-table" style="overflow-x:auto;"><p style="color:#888;"> Cargando tiempos…</p></div>1379 <p style="margin:10px 0 0;font-size:12px;color:#888;"> Tiempos provisionales por punto de control, actualizados automáticamente. La clasificación oficial se publica al finalizar la carrera.</p>1461 <div id="wpcr-live-table" style="overflow-x:auto;"><p style="color:#888;"><?php esc_html_e( 'Loading times…', 'opcion5-sports-event-registration' ); ?></p></div> 1462 <p style="margin:10px 0 0;font-size:12px;color:#888;"><?php esc_html_e( 'Provisional times by checkpoint, updated automatically. The official standings are published once the race is over.', 'opcion5-sports-event-registration' ); ?></p> 1380 1463 </div> 1381 1464 <?php … … 1383 1466 'ajax' => admin_url( 'admin-ajax.php' ), 1384 1467 'ev' => $public_id, 1468 'i18n' => [ 1469 'noTimes' => __( 'No times recorded yet. As soon as the timekeepers start marking, they will show up here.', 'opcion5-sports-event-registration' ), 1470 'noPoint' => __( 'No times at this checkpoint yet.', 'opcion5-sports-event-registration' ), 1471 'pos' => __( 'Pos.', 'opcion5-sports-event-registration' ), 1472 'bib' => __( 'Bib', 'opcion5-sports-event-registration' ), 1473 'name' => __( 'Name', 'opcion5-sports-event-registration' ), 1474 'category' => __( 'Category', 'opcion5-sports-event-registration' ), 1475 'time' => __( 'Time', 'opcion5-sports-event-registration' ), 1476 'retired' => __( 'RETIRED', 'opcion5-sports-event-registration' ), 1477 'raceOver' => __( 'The race has finished. See the official standings below.', 'opcion5-sports-event-registration' ), 1478 ], 1385 1479 ] ) . ";\n" . <<<'JS' 1386 1480 (function(){ … … 1406 1500 var points = data.points || []; 1407 1501 if (!points.length){ 1408 document.getElementById('wpcr-live-table').innerHTML = '<p style="color:#888;"> Todavía no hay tiempos registrados. En cuanto los cronometradores empiecen a marcar, aparecerán aquí.</p>';1502 document.getElementById('wpcr-live-table').innerHTML = '<p style="color:#888;">' + esc(wpcrLiveCfg.i18n.noTimes) + '</p>'; 1409 1503 return; 1410 1504 } … … 1419 1513 if (!pt) return; 1420 1514 if (!pt.ranking.length){ 1421 document.getElementById('wpcr-live-table').innerHTML = '<p style="color:#888;"> Sin tiempos en este punto todavía.</p>';1515 document.getElementById('wpcr-live-table').innerHTML = '<p style="color:#888;">' + esc(wpcrLiveCfg.i18n.noPoint) + '</p>'; 1422 1516 return; 1423 1517 } 1424 1518 var html = '<table style="width:100%;border-collapse:collapse;font-size:14px;"><thead><tr style="background:#f5f5f5;text-align:left;">' 1425 + '<th style="padding:8px 10px;width:60px;"> Pos.</th><th style="padding:8px 10px;width:70px;">Dorsal</th>'1426 + '<th style="padding:8px 10px;"> Nombre</th><th style="padding:8px 10px;">Categoría</th><th style="padding:8px 10px;width:100px;">Tiempo</th></tr></thead><tbody>';1519 + '<th style="padding:8px 10px;width:60px;">' + esc(wpcrLiveCfg.i18n.pos) + '</th><th style="padding:8px 10px;width:70px;">' + esc(wpcrLiveCfg.i18n.bib) + '</th>' 1520 + '<th style="padding:8px 10px;">' + esc(wpcrLiveCfg.i18n.name) + '</th><th style="padding:8px 10px;">' + esc(wpcrLiveCfg.i18n.category) + '</th><th style="padding:8px 10px;width:100px;">' + esc(wpcrLiveCfg.i18n.time) + '</th></tr></thead><tbody>'; 1427 1521 pt.ranking.forEach(function(r){ 1428 1522 var ret = !!r.retired; … … 1430 1524 + '<td style="padding:7px 10px;font-weight:700;">' + esc(r.pos) + '</td>' 1431 1525 + '<td style="padding:7px 10px;font-weight:700;">' + esc(r.dorsal) + '</td>' 1432 + '<td style="padding:7px 10px;">' + esc(r.name) + (ret ? ' · RETIRADO': '') + '</td>'1526 + '<td style="padding:7px 10px;">' + esc(r.name) + (ret ? ' · ' + esc(wpcrLiveCfg.i18n.retired) : '') + '</td>' 1433 1527 + '<td style="padding:7px 10px;">' + esc(r.cat) + '</td>' 1434 1528 + '<td style="padding:7px 10px;font-variant-numeric:tabular-nums;' + (ret ? 'text-decoration:line-through;' : '') + '">' + esc(r.tiempo) + '</td></tr>'; … … 1456 1550 if (res.data.finished){ 1457 1551 stopped = true; 1458 box.innerHTML = '<p style="margin:0;font-weight:600;color:#166534;">🏁 La carrera ha finalizado. Consulta las clasificaciones oficiales más abajo.</p>';1552 box.innerHTML = '<p style="margin:0;font-weight:600;color:#166534;">🏁 ' + esc(wpcrLiveCfg.i18n.raceOver) + '</p>'; 1459 1553 return; 1460 1554 } … … 1705 1799 if ( ! $valid_dni ) { 1706 1800 wp_die( 1707 '<h2 style="color:red;">❌ DNI/NIE no válido</h2>' 1708 . '<p>El DNI o NIE introducido (<strong>' . esc_html( $dni_raw ) . '</strong>) no tiene un formato o letra de control correctos.</p>' 1709 . '<p><a href="javascript:history.back()">← Volver al formulario</a></p>', 1710 'DNI no válido', 1801 '<h2 style="color:red;">❌ ' . esc_html__( 'Invalid ID number', 'opcion5-sports-event-registration' ) . '</h2>' 1802 . '<p>' . sprintf( 1803 /* translators: %s: the ID number entered by the user */ 1804 esc_html__( 'The ID number entered (%s) does not have a valid format or check letter.', 'opcion5-sports-event-registration' ), 1805 '<strong>' . esc_html( $dni_raw ) . '</strong>' 1806 ) . '</p>' 1807 . '<p><a href="javascript:history.back()">← ' . esc_html__( 'Back to the form', 'opcion5-sports-event-registration' ) . '</a></p>', 1808 esc_html__( 'Invalid ID number', 'opcion5-sports-event-registration' ), 1711 1809 [ 'response' => 400 ] 1712 1810 ); … … 1725 1823 if ( $ya_inscrito ) { 1726 1824 wp_die( 1727 '<h2 style="color:red;">❌ Ya estás inscrito</h2>' 1728 . '<p>El DNI <strong>' . esc_html( $dni_raw ) . '</strong> ya figura como inscrito en este evento.</p>' 1729 . '<p><a href="javascript:history.back()">← Volver al formulario</a></p>', 1730 'Ya inscrito', 1825 '<h2 style="color:red;">❌ ' . esc_html__( 'You are already registered', 'opcion5-sports-event-registration' ) . '</h2>' 1826 . '<p>' . sprintf( 1827 /* translators: %s: the ID number entered by the user */ 1828 esc_html__( 'The ID number %s is already registered for this event.', 'opcion5-sports-event-registration' ), 1829 '<strong>' . esc_html( $dni_raw ) . '</strong>' 1830 ) . '</p>' 1831 . '<p><a href="javascript:history.back()">← ' . esc_html__( 'Back to the form', 'opcion5-sports-event-registration' ) . '</a></p>', 1832 esc_html__( 'You are already registered', 'opcion5-sports-event-registration' ), 1731 1833 [ 'response' => 409 ] 1732 1834 ); … … 1763 1865 if ( ! $pair_join_partner ) { 1764 1866 wp_die( 1765 '<h2 style="color:red;">❌ Código de pareja no válido</h2>'1766 . '<p> El código introducido no existe, ya está completo o no pertenece a este evento.</p>'1767 . '<p><a href="javascript:history.back()">← Volver al formulario</a></p>',1768 'Código de pareja no válido', [ 'response' => 400 ]1867 '<h2 style="color:red;">❌ ' . esc_html__( 'Invalid pair code', 'opcion5-sports-event-registration' ) . '</h2>' 1868 . '<p>' . esc_html__( 'The code you entered does not exist, is already complete or does not belong to this event.', 'opcion5-sports-event-registration' ) . '</p>' 1869 . '<p><a href="javascript:history.back()">← ' . esc_html__( 'Back to the form', 'opcion5-sports-event-registration' ) . '</a></p>', 1870 esc_html__( 'Invalid pair code', 'opcion5-sports-event-registration' ), [ 'response' => 400 ] 1769 1871 ); 1770 1872 } … … 1778 1880 1779 1881 if ( ! $coherente ) { 1780 $labels = [ 'male' => 'masculina', 'female' => 'femenina', 'mixed' => 'mixta' ]; 1882 $labels = [ 1883 'male' => __( "men's", 'opcion5-sports-event-registration' ), 1884 'female' => __( "women's", 'opcion5-sports-event-registration' ), 1885 'mixed' => __( 'mixed', 'opcion5-sports-event-registration' ), 1886 ]; 1781 1887 wp_die( 1782 '<h2 style="color:red;">❌ Género no compatible con la modalidad</h2>' 1783 . '<p>Esta pareja es de modalidad <strong>' . esc_html( $labels[ $pcat ] ?? $pcat ) . '</strong> y tu género seleccionado no es compatible.</p>' 1784 . '<p><a href="javascript:history.back()">← Volver al formulario</a></p>', 1785 'Modalidad de pareja no compatible', [ 'response' => 400 ] 1888 '<h2 style="color:red;">❌ ' . esc_html__( 'Gender not compatible with this pair category', 'opcion5-sports-event-registration' ) . '</h2>' 1889 . '<p>' . sprintf( 1890 /* translators: %s: pair category, for example "mixed" */ 1891 esc_html__( 'This is a %s pair and the gender you selected is not compatible.', 'opcion5-sports-event-registration' ), 1892 '<strong>' . esc_html( $labels[ $pcat ] ?? $pcat ) . '</strong>' 1893 ) . '</p>' 1894 . '<p><a href="javascript:history.back()">← ' . esc_html__( 'Back to the form', 'opcion5-sports-event-registration' ) . '</a></p>', 1895 esc_html__( 'Gender not compatible with this pair category', 'opcion5-sports-event-registration' ), [ 'response' => 400 ] 1786 1896 ); 1787 1897 } … … 1798 1908 if ( ! in_array( $pair_category, $allowed_pair_cats, true ) ) { 1799 1909 wp_die( 1800 '<h2 style="color:red;">❌ Modalidad de pareja no válida</h2>'1801 . '<p><a href="javascript:history.back()">← Volver al formulario</a></p>',1802 'Modalidad no válida', [ 'response' => 400 ]1910 '<h2 style="color:red;">❌ ' . esc_html__( 'Invalid pair category', 'opcion5-sports-event-registration' ) . '</h2>' 1911 . '<p><a href="javascript:history.back()">← ' . esc_html__( 'Back to the form', 'opcion5-sports-event-registration' ) . '</a></p>', 1912 esc_html__( 'Invalid pair category', 'opcion5-sports-event-registration' ), [ 'response' => 400 ] 1803 1913 ); 1804 1914 } … … 1807 1917 if ( ( $pair_category === 'male' && $my_gender !== 'M' ) || ( $pair_category === 'female' && $my_gender !== 'F' ) ) { 1808 1918 wp_die( 1809 '<h2 style="color:red;">❌ Género no compatible con la modalidad de pareja elegida</h2>'1810 . '<p><a href="javascript:history.back()">← Volver al formulario</a></p>',1811 'Modalidad de pareja no compatible', [ 'response' => 400 ]1919 '<h2 style="color:red;">❌ ' . esc_html__( 'Gender not compatible with the pair category you chose', 'opcion5-sports-event-registration' ) . '</h2>' 1920 . '<p><a href="javascript:history.back()">← ' . esc_html__( 'Back to the form', 'opcion5-sports-event-registration' ) . '</a></p>', 1921 esc_html__( 'Gender not compatible with this pair category', 'opcion5-sports-event-registration' ), [ 'response' => 400 ] 1812 1922 ); 1813 1923 } … … 1822 1932 if ( $started_pairs >= (int) $evt_pairs['pairs_max_couples'] ) { 1823 1933 wp_die( 1824 '<h2 style="color:red;"> El cupo de parejas está completo</h2>'1825 . '<p> No se aceptan más inscripciones por parejas para este evento.</p>',1826 'Cupo de parejas completo', [ 'response' => 409 ]1934 '<h2 style="color:red;">' . esc_html__( 'The pair quota is full', 'opcion5-sports-event-registration' ) . '</h2>' 1935 . '<p>' . esc_html__( 'No more pair registrations are being accepted for this event.', 'opcion5-sports-event-registration' ) . '</p>', 1936 esc_html__( 'The pair quota is full', 'opcion5-sports-event-registration' ), [ 'response' => 409 ] 1827 1937 ); 1828 1938 } … … 1898 2008 if ( $current >= intval($event['max_participants']) ) { 1899 2009 1900 wp_die( "1901 <h2 style='color:red;'>El cupo está completo</h2>1902 <p>No se aceptan más inscripciones para este evento.</p>1903 ");2010 wp_die( 2011 "<h2 style='color:red;'>" . esc_html__( 'The event is full', 'opcion5-sports-event-registration' ) . "</h2>" 2012 . "<p>" . esc_html__( 'No more registrations are being accepted for this event.', 'opcion5-sports-event-registration' ) . "</p>" 2013 ); 1904 2014 } 1905 2015 } … … 1924 2034 if (!$participant_id) { 1925 2035 wpcr_debug_log('WPCR insert error: ' . $wpdb->last_error); 1926 wp_die( esc_html__( 'No se pudo completar tu inscripción. Por favor, inténtalo de nuevo o contacta con el organizador.', 'opcion5-sports-event-registration') );2036 wp_die( esc_html__( 'Your registration could not be completed. Please try again or contact the organizer.', 'opcion5-sports-event-registration' ) ); 1927 2037 } 1928 2038 … … 1973 2083 1974 2084 if (!$payment || empty($payment['payment_token'])) { 1975 wp_die( '❌ No se pudo crear el pago asociado a la inscripción.');2085 wp_die( '❌ ' . esc_html__( 'The payment for this registration could not be created.', 'opcion5-sports-event-registration' ) ); 1976 2086 } 1977 2087 … … 2004 2114 // Asunto 2005 2115 $subject = get_post_meta($event_id, 'wpcr_mail_ins_subject', true) 2006 ?: 'Inscripción recibida - ' . $event['name']; 2116 ?: sprintf( 2117 /* translators: %s: event name */ 2118 __( 'Registration received - %s', 'opcion5-sports-event-registration' ), 2119 $event['name'] 2120 ); 2007 2121 2008 2122 // Plantilla … … 2014 2128 2015 2129 <h2 style='color:#0d47a1;margin-bottom:5px;font-size:24px;font-weight:800;'> 2016 ⏱ ¡Inscripción realizada!2130 ⏱ " . esc_html__( 'Registration received!', 'opcion5-sports-event-registration' ) . " 2017 2131 </h2> 2018 2132 2019 2133 <p style='font-size:16px;margin-top:5px;color:#0a2540;'> 2020 Hola <b>{nombre}</b>, ya estás pre-inscrito en el evento: 2134 " . sprintf( 2135 /* translators: %s: the {nombre} placeholder, replaced with the participant name */ 2136 esc_html__( 'Hi %s, you are now pre-registered for the event:', 'opcion5-sports-event-registration' ), 2137 '<b>{nombre}</b>' 2138 ) . " 2021 2139 </p> 2022 2140 … … 2028 2146 2029 2147 <p style='font-size:15px;'> 2030 <b>💶 Precio actual:</b>2148 <b>💶 " . esc_html__( 'Current price:', 'opcion5-sports-event-registration' ) . "</b> 2031 2149 <span style='font-size:17px;color:#004cff;'><b>{precio} €</b></span> 2032 2150 </p> 2033 2151 2034 2152 <p style='font-size:15px;margin-top:10px;'> 2035 Para confirmar tu plaza debes completar el pago. 2153 " . esc_html__( 'To confirm your place you need to complete the payment.', 'opcion5-sports-event-registration' ) . " 2036 2154 </p> 2037 2155 … … 2041 2159 style='font-size:18px;font-weight:bold;padding:14px 28px;display:inline-block; 2042 2160 text-decoration:none;color:#ffffff;font-family:Arial,sans-serif;'> 2043 🏁 Pagar inscripción ahora2161 🏁 " . esc_html__( 'Pay for my registration now', 'opcion5-sports-event-registration' ) . " 2044 2162 </a> 2045 2163 </td></tr></table> … … 2052 2170 if ( ! empty( $save['pair_code'] ) && ( $save['pair_status'] ?? '' ) === 'open' ) { 2053 2171 2054 $pair_labels = [ 'male' => 'Pareja masculina', 'mixed' => 'Pareja mixta', 'female' => 'Pareja femenina' ]; 2055 $pair_label = $pair_labels[ $save['pair_category'] ] ?? 'Pareja'; 2172 $pair_labels = [ 2173 'male' => __( "Men's pair", 'opcion5-sports-event-registration' ), 2174 'mixed' => __( 'Mixed pair', 'opcion5-sports-event-registration' ), 2175 'female' => __( "Women's pair", 'opcion5-sports-event-registration' ), 2176 ]; 2177 $pair_label = $pair_labels[ $save['pair_category'] ] ?? __( 'Pair', 'opcion5-sports-event-registration' ); 2056 2178 2057 2179 $event_page_url = function_exists( 'wpcr_get_event_page_url' ) ? wpcr_get_event_page_url() : home_url( '/' ); … … 2066 2188 padding:20px;border-radius:10px;border:2px solid #0d47a1;margin-top:15px;'> 2067 2189 <tr><td align='center'> 2068 <h3 style='color:#0d47a1;margin:0 0 8px;'>👥 Inscripción por parejas — " . esc_html( $pair_label ) . "</h3> 2190 <h3 style='color:#0d47a1;margin:0 0 8px;'>👥 " . sprintf( 2191 /* translators: %s: pair category, for example "Mixed pair" */ 2192 esc_html__( 'Pair registration — %s', 'opcion5-sports-event-registration' ), 2193 esc_html( $pair_label ) 2194 ) . "</h3> 2069 2195 <p style='font-size:15px;margin:0 0 10px;'> 2070 Falta que tu pareja complete su inscripción. Comparte con él/ella este código: 2196 " . esc_html__( 'Your partner still has to complete their registration. Share this code with them:', 'opcion5-sports-event-registration' ) . " 2071 2197 </p> 2072 2198 <p style='font-size:26px;font-weight:800;letter-spacing:2px;color:#0d47a1;margin:0 0 12px;'> 2073 2199 " . esc_html( $save['pair_code'] ) . " 2074 2200 </p> 2075 <p style='font-size:14px;margin:0 0 14px;'> O envíale directamente este enlace para inscribirse ya vinculado contigo:</p>2201 <p style='font-size:14px;margin:0 0 14px;'>" . esc_html__( 'Or send them this link so they register already linked to you:', 'opcion5-sports-event-registration' ) . "</p> 2076 2202 <table role='presentation' cellspacing='0' cellpadding='0' border='0' align='center'> 2077 2203 <tr><td bgcolor='#0d47a1' style='border-radius:6px;'> … … 2079 2205 style='font-size:15px;font-weight:bold;padding:11px 22px;display:inline-block; 2080 2206 text-decoration:none;color:#ffffff;font-family:Arial,sans-serif;'> 2081 👥 Completar inscripción de mi pareja2207 👥 " . esc_html__( 'Complete my partner registration', 'opcion5-sports-event-registration' ) . " 2082 2208 </a> 2083 2209 </td></tr></table> 2084 2210 <p style='font-size:12px;color:#555;margin:12px 0 0;'> 2085 Cada corredor paga su propia inscripción. La pareja quedará confirmada cuando ambos hayáis completado el proceso. 2211 " . esc_html__( 'Each entrant pays for their own registration. The pair is confirmed once you have both completed the process.', 'opcion5-sports-event-registration' ) . " 2086 2212 </p> 2087 2213 </td></tr></table> -
opcion5-sports-event-registration/trunk/public/views/payment-bank-transfer.php
r3642215 r3645531 14 14 ?> 15 15 <!DOCTYPE html> 16 <html lang=" es">16 <html lang="<?php echo esc_attr( str_replace( '_', '-', get_bloginfo( 'language' ) ) ); ?>"> 17 17 <head> 18 18 <meta charset="utf-8"> 19 19 <meta name="viewport" content="width=device-width, initial-scale=1"> 20 20 21 <title> Pago por transferencia</title>21 <title><?php esc_html_e( 'Bank transfer payment', 'opcion5-sports-event-registration' ); ?></title> 22 22 23 23 <?php … … 35 35 <div class="wpcr-box"> 36 36 37 <h1> Pago por transferencia bancaria</h1>37 <h1><?php esc_html_e( 'Bank transfer payment', 'opcion5-sports-event-registration' ); ?></h1> 38 38 39 39 <p> 40 Hola <b><?php echo esc_html($participant['first_name']); ?></b>, 41 para confirmar tu inscripción en: 40 <?php printf( 41 /* translators: %s: participant first name */ 42 esc_html__( 'Hi %s, to confirm your registration for:', 'opcion5-sports-event-registration' ), 43 '<b>' . esc_html( $participant['first_name'] ) . '</b>' 44 ); ?> 42 45 </p> 43 46 … … 45 48 46 49 <p> 47 <b> Importe a pagar:</b> <?php echo esc_html($amount); ?> €50 <b><?php esc_html_e( 'Amount to pay:', 'opcion5-sports-event-registration' ); ?></b> <?php echo esc_html($amount); ?> € 48 51 </p> 49 52 50 53 <hr style="margin:30px 0;border-color:#ccd9ff;"> 51 54 52 <p> Realiza la transferencia con los siguientes datos:</p>55 <p><?php esc_html_e( 'Make the transfer using these details:', 'opcion5-sports-event-registration' ); ?></p> 53 56 54 57 <ul class="wpcr-bank-list"> … … 58 61 </li> 59 62 <li> 60 <strong> Beneficiario:</strong>61 <?php echo esc_html($event['bank_beneficiary'] ?? 'Organización del evento'); ?>63 <strong><?php esc_html_e( 'Payee:', 'opcion5-sports-event-registration' ); ?></strong> 64 <?php echo esc_html($event['bank_beneficiary'] ?? __( 'Event organizer', 'opcion5-sports-event-registration' )); ?> 62 65 </li> 63 66 <li> 64 <strong> Concepto:</strong>67 <strong><?php esc_html_e( 'Reference:', 'opcion5-sports-event-registration' ); ?></strong> 65 68 <?php echo esc_html($reference); ?> 66 69 </li> … … 68 71 69 72 <div class="wpcr-payment-warning"> 70 ⚠️ La plaza no se confirma hasta que confirmemos la transferencia.73 ⚠️ <?php esc_html_e( 'Your place is not confirmed until we have received the transfer.', 'opcion5-sports-event-registration' ); ?> 71 74 </div> 72 75 73 76 <p class="wpcr-muted" style="margin-top:18px;"> 74 Puedes cerrar esta página. Te avisaremos cuando el pago sea validado.77 <?php esc_html_e( 'You can close this page. We will let you know once the payment has been validated.', 'opcion5-sports-event-registration' ); ?> 75 78 </p> 76 79 -
opcion5-sports-event-registration/trunk/public/wpcr-inscripcion-confirmada.php
r3642215 r3645531 40 40 <div class="wpcr-confirm-box wpcr-confirm-paid"> 41 41 <div class="wpcr-confirm-icon">✅</div> 42 <h1><?php esc_html_e( ' ¡Pago completado!', 'opcion5-sports-event-registration' ); ?></h1>43 <p><?php printf( 44 /* translators: %s nombre del participante */45 esc_html__( 'H ola %s, tu inscripción está confirmada y el pago recibido.', 'opcion5-sports-event-registration' ),42 <h1><?php esc_html_e( 'Payment complete!', 'opcion5-sports-event-registration' ); ?></h1> 43 <p><?php printf( 44 /* translators: %s: participant first name */ 45 esc_html__( 'Hi %s, your registration is confirmed and your payment has been received.', 'opcion5-sports-event-registration' ), 46 46 '<strong>' . esc_html( $participant['first_name'] ) . '</strong>' 47 47 ); ?></p> … … 49 49 <p class="wpcr-confirm-amount"> 50 50 <?php echo esc_html( number_format( $amount, 2, ',', '.' ) ); ?> € 51 <span class="wpcr-confirm-badge wpcr-badge-paid"><?php esc_html_e( 'Pa gado', 'opcion5-sports-event-registration' ); ?></span>51 <span class="wpcr-confirm-badge wpcr-badge-paid"><?php esc_html_e( 'Paid', 'opcion5-sports-event-registration' ); ?></span> 52 52 </p> 53 53 </div> … … 58 58 <div class="wpcr-confirm-box"> 59 59 <div class="wpcr-confirm-icon">🎉</div> 60 <h1><?php esc_html_e( ' ¡Inscripción registrada!', 'opcion5-sports-event-registration' ); ?></h1>61 <p><?php printf( 62 /* translators: %s: nombre del participante */63 esc_html__( 'H ola %s, tu inscripción en el evento está pendiente de pago.', 'opcion5-sports-event-registration' ),60 <h1><?php esc_html_e( 'Registration received!', 'opcion5-sports-event-registration' ); ?></h1> 61 <p><?php printf( 62 /* translators: %s: participant first name */ 63 esc_html__( 'Hi %s, your registration is awaiting payment.', 'opcion5-sports-event-registration' ), 64 64 '<strong>' . esc_html( $participant['first_name'] ) . '</strong>' 65 65 ); ?></p> 66 66 <h2 class="wpcr-confirm-event"><?php echo esc_html( $event['name'] ); ?></h2> 67 67 <p class="wpcr-confirm-amount"> 68 <?php esc_html_e( ' Importe a abonar:', 'opcion5-sports-event-registration' ); ?>68 <?php esc_html_e( 'Amount to pay:', 'opcion5-sports-event-registration' ); ?> 69 69 <strong><?php echo esc_html( number_format( $amount, 2, ',', '.' ) ); ?> €</strong> 70 70 </p> … … 72 72 <!-- DATOS BANCARIOS --> 73 73 <div class="wpcr-bank-box"> 74 <h3>🏦 <?php esc_html_e( ' Datos para la transferencia', 'opcion5-sports-event-registration' ); ?></h3>74 <h3>🏦 <?php esc_html_e( 'Bank transfer details', 'opcion5-sports-event-registration' ); ?></h3> 75 75 <table class="wpcr-bank-table"> 76 76 <?php if ( $bank_name ) : ?> 77 77 <tr> 78 <th><?php esc_html_e( 'Ban co', 'opcion5-sports-event-registration' ); ?></th>78 <th><?php esc_html_e( 'Bank', 'opcion5-sports-event-registration' ); ?></th> 79 79 <td><?php echo esc_html( $bank_name ); ?></td> 80 80 </tr> … … 82 82 <?php if ( $account_name ) : ?> 83 83 <tr> 84 <th><?php esc_html_e( ' Titular', 'opcion5-sports-event-registration' ); ?></th>84 <th><?php esc_html_e( 'Account holder', 'opcion5-sports-event-registration' ); ?></th> 85 85 <td><?php echo esc_html( $account_name ); ?></td> 86 86 </tr> … … 99 99 <?php endif; ?> 100 100 <tr> 101 <th><?php esc_html_e( ' Concepto / Referencia', 'opcion5-sports-event-registration' ); ?></th>101 <th><?php esc_html_e( 'Payment reference', 'opcion5-sports-event-registration' ); ?></th> 102 102 <td class="wpcr-bank-ref"><?php echo esc_html( $reference ); ?></td> 103 103 </tr> 104 104 <tr> 105 <th><?php esc_html_e( ' Importe', 'opcion5-sports-event-registration' ); ?></th>105 <th><?php esc_html_e( 'Amount', 'opcion5-sports-event-registration' ); ?></th> 106 106 <td><strong><?php echo esc_html( number_format( $amount, 2, ',', '.' ) ); ?> €</strong></td> 107 107 </tr> … … 109 109 110 110 <div class="wpcr-bank-notice"> 111 ⚠️ <?php esc_html_e( ' Indica siempre el concepto/referencia en la transferencia. Tu plaza quedará reservada durante 48 horas hasta confirmar el pago.', 'opcion5-sports-event-registration' ); ?>111 ⚠️ <?php esc_html_e( 'Always include the payment reference in your transfer. Your place is held for 48 hours until the payment is confirmed.', 'opcion5-sports-event-registration' ); ?> 112 112 </div> 113 113 </div> … … 120 120 <div class="wpcr-confirm-box"> 121 121 <div class="wpcr-confirm-icon">🎉</div> 122 <h1><?php esc_html_e( ' ¡Inscripción registrada!', 'opcion5-sports-event-registration' ); ?></h1>123 <p><?php printf( 124 /* translators: %s: nombre del participante */125 esc_html__( 'H ola %s, completa el pago para confirmar tu plaza.', 'opcion5-sports-event-registration' ),122 <h1><?php esc_html_e( 'Registration received!', 'opcion5-sports-event-registration' ); ?></h1> 123 <p><?php printf( 124 /* translators: %s: participant first name */ 125 esc_html__( 'Hi %s, complete the payment to confirm your place.', 'opcion5-sports-event-registration' ), 126 126 '<strong>' . esc_html( $participant['first_name'] ) . '</strong>' 127 127 ); ?></p> 128 128 <h2 class="wpcr-confirm-event"><?php echo esc_html( $event['name'] ); ?></h2> 129 129 <p class="wpcr-confirm-amount"> 130 <?php esc_html_e( ' Importe:', 'opcion5-sports-event-registration' ); ?>130 <?php esc_html_e( 'Amount:', 'opcion5-sports-event-registration' ); ?> 131 131 <strong><?php echo esc_html( number_format( $amount, 2, ',', '.' ) ); ?> €</strong> 132 132 </p> 133 133 <a class="wpcr-confirm-btn" href="<?php echo esc_url( $payment_url ); ?>"> 134 💳 <?php esc_html_e( 'Pa gar ahora', 'opcion5-sports-event-registration' ); ?>134 💳 <?php esc_html_e( 'Pay now', 'opcion5-sports-event-registration' ); ?> 135 135 </a> 136 136 <p class="wpcr-confirm-note"> 137 <?php esc_html_e( ' La plaza no se confirma hasta completar el pago.', 'opcion5-sports-event-registration' ); ?>137 <?php esc_html_e( 'Your place is not confirmed until the payment is complete.', 'opcion5-sports-event-registration' ); ?> 138 138 </p> 139 139 </div> … … 145 145 if ( ! empty( $participant['pair_code'] ) && ( $participant['pair_status'] ?? '' ) === 'open' ) : 146 146 147 $pair_labels = [ 'male' => 'Pareja masculina', 'mixed' => 'Pareja mixta', 'female' => 'Pareja femenina' ]; 148 $pair_label = $pair_labels[ $participant['pair_category'] ?? '' ] ?? 'Pareja'; 147 $pair_labels = [ 148 'male' => __( "Men's pair", 'opcion5-sports-event-registration' ), 149 'mixed' => __( 'Mixed pair', 'opcion5-sports-event-registration' ), 150 'female' => __( "Women's pair", 'opcion5-sports-event-registration' ), 151 ]; 152 $pair_label = $pair_labels[ $participant['pair_category'] ?? '' ] ?? __( 'Pair', 'opcion5-sports-event-registration' ); 149 153 150 154 $event_page_url = function_exists( 'wpcr_get_event_page_url' ) ? wpcr_get_event_page_url() : home_url( '/' ); … … 153 157 $event_page_url 154 158 ); 155 $pair_share_text = rawurlencode( '¡Nos hemos apuntado juntos a ' . $event['name'] . '! Completa tu inscripción como mi pareja aquí: ' . $pair_link ); 159 $pair_share_text = rawurlencode( 160 sprintf( 161 /* translators: 1: event name, 2: registration link */ 162 __( 'We have signed up together for %1$s! Complete your registration as my partner here: %2$s', 'opcion5-sports-event-registration' ), 163 $event['name'], 164 $pair_link 165 ) 166 ); 156 167 ?> 157 168 <div class="wpcr-confirm-box" style="margin-top:20px;border-top-color:#0d47a1;"> 158 169 <div class="wpcr-confirm-icon">👥</div> 159 <h1 style="font-size:22px !important;">Inscripción por parejas — <?php echo esc_html( $pair_label ); ?></h1> 160 <p>Falta que tu pareja complete su inscripción. Comparte con él/ella este código:</p> 170 <h1 style="font-size:22px !important;"><?php printf( 171 /* translators: %s: pair category, for example "Mixed pair" */ 172 esc_html__( 'Pair registration — %s', 'opcion5-sports-event-registration' ), 173 esc_html( $pair_label ) 174 ); ?></h1> 175 <p><?php esc_html_e( 'Your partner still has to complete their registration. Share this code with them:', 'opcion5-sports-event-registration' ); ?></p> 161 176 <p style="font-size:30px;font-weight:800;letter-spacing:3px;color:#0d47a1;margin:10px 0;"> 162 177 <?php echo esc_html( $participant['pair_code'] ); ?> 163 178 </p> 164 <p> O envíale directamente el enlace de inscripción:</p>179 <p><?php esc_html_e( 'Or send them the registration link directly:', 'opcion5-sports-event-registration' ); ?></p> 165 180 <p style="word-break:break-all;font-size:13px;background:#f0f4ff;padding:10px;border-radius:6px;"> 166 181 <?php echo esc_url( $pair_link ); ?> … … 168 183 <a class="wpcr-confirm-btn" style="background:#25D366;" 169 184 href="https://wa.me/?text=<?php echo esc_attr( $pair_share_text ); ?>" target="_blank" rel="noopener"> 170 📲 Enviar por WhatsApp185 📲 <?php esc_html_e( 'Send by WhatsApp', 'opcion5-sports-event-registration' ); ?> 171 186 </a> 172 187 <p class="wpcr-confirm-note"> 173 Cada corredor paga su propia inscripción. La pareja quedará confirmada cuando ambos completéis el proceso. 174 También te hemos enviado el código por email. 188 <?php esc_html_e( 'Each entrant pays for their own registration. The pair is confirmed once you have both completed the process. We have also emailed you the code.', 'opcion5-sports-event-registration' ); ?> 175 189 </p> 176 190 </div> … … 178 192 <div class="wpcr-confirm-box" style="margin-top:20px;border-top-color:#1a9e3f;"> 179 193 <div class="wpcr-confirm-icon">👥</div> 180 <h1 style="font-size:22px !important;">¡Pareja completa!</h1> 181 <p>Tu inscripción ha quedado vinculada correctamente con la de tu pareja 182 (código <strong><?php echo esc_html( $participant['pair_code'] ); ?></strong>). 183 Recordad que la plaza de cada uno se confirma con su propio pago.</p> 194 <h1 style="font-size:22px !important;"><?php esc_html_e( 'Pair complete!', 'opcion5-sports-event-registration' ); ?></h1> 195 <p><?php printf( 196 /* translators: %s: pair code */ 197 esc_html__( 'Your registration is now linked to your partner\'s (code %s). Remember that each place is confirmed by its own payment.', 'opcion5-sports-event-registration' ), 198 '<strong>' . esc_html( $participant['pair_code'] ) . '</strong>' 199 ); ?></p> 184 200 </div> 185 201 <?php endif; ?> -
opcion5-sports-event-registration/trunk/readme.txt
r3642631 r3645531 5 5 Tested up to: 7.0 6 6 Requires PHP: 7.4 7 Stable tag: 1. 0.17 Stable tag: 1.1.0 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 33 33 34 34 Every feature listed above is included and works with this plugin alone. There are no license keys, usage limits, trial periods or locked features of any kind. 35 36 **Available in 6 languages** 37 38 The plugin is written in English and ships with translations for Spanish, French, German, Italian and Portuguese. It picks the language configured in your WordPress site automatically, so both you and your entrants see it in your own language. The privacy policy template is intentionally left in its original wording, since it refers to Spanish data protection law and you should adapt it to your own country. 35 39 36 40 **Shortcodes** … … 79 83 == Changelog == 80 84 85 = 1.1.0 = 86 * The plugin is now translatable. Its interface is written in English and includes translations for Spanish, French, German, Italian and Portuguese, chosen automatically from your WordPress language setting. 87 * Dates and times now follow the format you set in Settings → General, instead of a fixed one. 88 * The privacy policy template is kept in its original wording on purpose: it refers to Spanish data protection law, so adapt it to your own country from the event Options tab. 89 81 90 = 1.0.1 = 82 91 * Plugin renamed to "Sports Event Registration by CronoMeta". … … 88 97 == Upgrade Notice == 89 98 99 = 1.1.0 = 100 The plugin is now available in six languages and follows your WordPress date format. 101 90 102 = 1.0.1 = 91 103 Cosmetic release: new plugin name and corrected links in the extensions catalogue.
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)