[ Index ]

PHP Cross Reference of GlotPress

title

Body

[close]

/gp-templates/ -> helper-functions.php (source)

   1  <?php
   2  /**
   3   * Defines helper functions used by GlotPress.
   4   *
   5   * @package GlotPress
   6   * @since 1.0.0
   7   */
   8  
   9  /**
  10   * Prepare an original string to be printed out in a translation row by adding encoding special
  11   * characters, adding glossary entires and other markup.
  12   *
  13   * @param string $text A single style handle to enqueue or an array or style handles to enqueue.
  14   *
  15   * @return string The prepared string for output.
  16   */
  17  function prepare_original( $text ) {
  18      // Glossaries are injected into the translations prior to escaping and prepare_original() being run.
  19      $glossary_entries = array();
  20      $text = preg_replace_callback( '!(<span class="glossary-word"[^>]+>)!i', function( $m ) use ( &$glossary_entries ) {
  21          $item_number = count( $glossary_entries );
  22          $glossary_entries[ $item_number ] = $m[0];
  23          return "<span GLOSSARY={$item_number}>";
  24      }, $text );
  25  
  26      // Wrap full HTML tags with a notranslate class
  27      $text = preg_replace( '/(&lt;.+?&gt;)/', '<span class="notranslate">\\1</span>', $text );
  28      // Break out & back into notranslate for translatable attributes
  29      $text = preg_replace( '/(title|aria-label)=([\'"])([^\\2]+?)\\2/', '\\1=\\2</span>\\3<span class="notranslate">\\2', $text );
  30      // Wrap placeholders with notranslate
  31      $text = preg_replace( '/(%(\d+\$(?:\d+)?)?[bcdefgosuxEFGX])/', '<span class="notranslate">\\1</span>', $text );
  32  
  33      // Put the glossaries back!
  34      $text = preg_replace_callback( '!(<span GLOSSARY=(\d+)>)!', function( $m ) use ( $glossary_entries ) {
  35          return $glossary_entries[ $m[2] ];
  36      }, $text );
  37  
  38      $text = str_replace( array( "\r", "\n" ), "<span class='invisibles' title='" . esc_attr__( 'New line', 'glotpress' ) . "'>&crarr;</span>\n", $text );
  39      $text = str_replace( "\t", "<span class='invisibles' title='" . esc_attr__( 'Tab character', 'glotpress' ) . "'>&rarr;</span>\t", $text );
  40  
  41      return $text;
  42  }
  43  
  44  /**
  45   * Prepares a translation string to be printed out in a translation row by adding an 'extra' return/newline if
  46   * it starts with one.
  47   *
  48   * @since 2.4.0
  49   *
  50   * @param string $text A single style handle to enqueue or an array or style handles to enqueue.
  51   * @return string The prepared string for output.
  52   */
  53  function gp_prepare_translation_textarea( $text ) {
  54      if ( gp_startswith( $text, "\r\n" ) ) {
  55          $text = "\r\n" . $text;
  56      } elseif ( gp_startswith( $text, "\n" ) ) {
  57          $text = "\n" . $text;
  58      }
  59  
  60      return $text;
  61  }
  62  
  63  /**
  64   * Sort a set of glossary entries by length for use in map_glossary_entries_to_translation_originals().
  65   *
  66   * @param array $glossary_entries An array of glossary entries to sort.
  67   *
  68   * @return array The sorted entries.
  69   */
  70  function gp_sort_glossary_entries_terms( $glossary_entries ) {
  71      if ( empty ( $glossary_entries ) ) {
  72          return;
  73      }
  74  
  75      $glossary_entries_terms = array();
  76  
  77      // Create array of glossary terms, longest first.
  78      foreach ( $glossary_entries as $key => $value ) {
  79          $terms = array();
  80  
  81          $quoted_term = preg_quote( $value->term, '/' );
  82  
  83          $terms[] = $quoted_term;
  84          $terms[] = $quoted_term . 's';
  85  
  86          if ( 'y' === substr( $value->term, -1 ) ) {
  87              $terms[] = preg_quote( substr( $value->term, 0, -1 ), '/' ) . 'ies';
  88          } elseif ( 'f' === substr( $value->term, -1 ) ) {
  89              $terms[] = preg_quote( substr( $value->term, 0, -1 ), '/' ) . 'ves';
  90          } elseif ( 'fe' === substr( $value->term, -2 ) ) {
  91              $terms[] = preg_quote( substr( $value->term, 0, -2 ), '/' ) . 'ves';
  92          } else {
  93              if ( 'an' === substr( $value->term, -2 ) ) {
  94                  $terms[] = preg_quote( substr( $value->term, 0, -2 ), '/' ) . 'en';
  95              }
  96              $terms[] = $quoted_term . 'es';
  97              $terms[] = $quoted_term . 'ed';
  98              $terms[] = $quoted_term . 'ing';
  99          }
 100  
 101          $glossary_entries_terms[ $key ] = implode( '|', $terms );
 102      }
 103  
 104      uasort( $glossary_entries_terms, function( $a, $b ) { return gp_strlen($a) < gp_strlen($b); } );
 105  
 106      return $glossary_entries_terms;
 107  }
 108  
 109  /**
 110   * Add markup to a translation original to identify the glossary terms.
 111   *
 112   * @param GP_Translation $translation            A GP Translation object.
 113   * @param GP_Glossary    $glossary               A GP Glossary object.
 114   * @param array          $glossary_entries_terms A list of terms to highligh.
 115   *
 116   * @return obj The marked up translation entry.
 117   */
 118  function map_glossary_entries_to_translation_originals( $translation, $glossary, $glossary_entries_terms = null ) {
 119      $glossary_entries = $glossary->get_entries();
 120      if ( empty( $glossary_entries ) ) {
 121          return $translation;
 122      }
 123  
 124      if ( null === $glossary_entries_terms || ! is_array( $glossary_entries_terms ) ) {
 125          $glossary_entries_terms = gp_sort_glossary_entries_terms( $glossary_entries );
 126      }
 127  
 128      $glossary_entries_terms_array = array();
 129      $glossary_term_reference      = array();
 130  
 131      // Since glossary entries terms have been returned as an array of strings, we need to break it up and create back references.
 132      foreach ( $glossary_entries_terms as $i => $terms ) {
 133          // Split the terms in to an array and make sure they are all lower case for later use.
 134          $term_list = explode( '|', $terms );
 135          $term_list = array_map( 'strtolower', $term_list );
 136  
 137          foreach ( $term_list as $term ) {
 138              // Add the term to the terms array.
 139              $glossary_entries_terms_array[] = $term;
 140              // Make a back reference to the term's glossary entry.
 141              $glossary_term_reference[ $term ][] = $i;
 142          }
 143      }
 144  
 145      // Split the singular string on word boundaries.
 146      $singular_split    = preg_split( '/\b/', $translation->singular );
 147      $singular_combined = '';
 148  
 149      // Loop through each chunk of the split to find glossary terms.
 150      foreach ( $singular_split as $chunk ) {
 151          // Create an escaped version for use later on.
 152          $escaped_chunk = esc_translation( $chunk );
 153  
 154          // Create a lower case version to compare with the glossary terms.
 155          $lower_chunk = strtolower( $chunk );
 156  
 157          // Search the glossary terms for a matching entry.
 158          if ( false !== array_search( $lower_chunk, $glossary_entries_terms_array, true ) ) {
 159              $glossary_data = array();
 160  
 161              // Add glossary data for each matching entry.
 162              foreach ( $glossary_term_reference[ $lower_chunk ] as $glossary_entry_id ) {
 163                  // Get the glossary entry based on the back reference we created earlier.
 164                  $glossary_entry = $glossary_entries[ $glossary_entry_id ];
 165  
 166                  // If this is a locale glossary, make a note for the user.
 167                  $locale_entry = '';
 168                  if ( $glossary_entry->glossary_id !== $glossary->id ) {
 169                      /* translators: Denotes an entry from the locale glossary in the tooltip */
 170                      $locale_entry = _x( 'Locale Glossary', 'Bubble', 'glotpress' );
 171                  }
 172  
 173                  // Create the data to be added to the span.
 174                  $glossary_data[] = array(
 175                      'translation'  => $glossary_entry->translation,
 176                      'pos'          => $glossary_entry->part_of_speech,
 177                      'comment'      => $glossary_entry->comment,
 178                      'locale_entry' => $locale_entry,
 179                  );
 180              }
 181  
 182              // Add the span and chunk to our output.
 183              $singular_combined .= '<span class="glossary-word" data-translations="' . htmlspecialchars( wp_json_encode( $glossary_data ), ENT_QUOTES, 'UTF-8' ) . '">' . $escaped_chunk . '</span>';
 184          } else {
 185              // No term was found so just add the escaped chunk to the output.
 186              $singular_combined .= $escaped_chunk;
 187          }
 188      }
 189  
 190      // Assign the output to the translation.
 191      $translation->singular_glossary_markup = $singular_combined;
 192  
 193      // Add glossary terms to the plural if we have one.
 194      if ( $translation->plural ) {
 195          // Split the plural string on word boundaries.
 196          $plural_split    = preg_split( '/\b/', $translation->plural );
 197          $plural_combined = '';
 198  
 199          // Loop through each chunk of the split to find glossary terms.
 200          foreach ( $plural_split as $chunk ) {
 201              // Create an escaped version for use later on.
 202              $escaped_chunk = esc_translation( $chunk );
 203  
 204              // Create a lower case version to compare with the glossary terms.
 205              $lower_chunk = strtolower( $chunk );
 206  
 207              // Search the glossary terms for a matching entry.
 208              if ( false !== array_search( $lower_chunk, $glossary_entries_terms_array, true ) ) {
 209                  $glossary_data = array();
 210  
 211                  // Add glossary data for each matching entry.
 212                  foreach ( $glossary_term_reference[ $lower_chunk ] as $glossary_entry_id ) {
 213                      // Get the glossary entry based on the back reference we created earlier.
 214                      $glossary_entry = $glossary_entries[ $glossary_entry_id ];
 215  
 216                      // If this is a locale glossary, make a note for the user.
 217                      $locale_entry = '';
 218                      if ( $glossary_entry->glossary_id !== $glossary->id ) {
 219                          /* translators: Denotes an entry from the locale glossary in the tooltip */
 220                          $locale_entry = _x( 'Locale Glossary', 'Bubble', 'glotpress' );
 221                      }
 222  
 223                      // Create the data to be added to the span.
 224                      $glossary_data[] = array(
 225                          'translation'  => $glossary_entry->translation,
 226                          'pos'          => $glossary_entry->part_of_speech,
 227                          'comment'      => $glossary_entry->comment,
 228                          'locale_entry' => $locale_entry,
 229                      );
 230                  }
 231  
 232                  // Add the span and chunk to our output.
 233                  $plural_combined .= '<span class="glossary-word" data-translations="' . htmlspecialchars( wp_json_encode( $glossary_data ), ENT_QUOTES, 'UTF-8' ) . '">' . $escaped_chunk . '</span>';
 234              } else {
 235                  // No term was found so just add the escaped chunk to the output.
 236                  $plural_combined .= $escaped_chunk;
 237              }
 238          }
 239  
 240          // Assign the output to the translation.
 241          $translation->plural_glossary_markup = $plural_combined;
 242      }
 243  
 244      return $translation;
 245  }
 246  
 247  function textareas( $entry, $permissions, $index = 0 ) {
 248      list( $can_edit, $can_approve ) = $permissions;
 249      $disabled = $can_edit ? '' : 'disabled="disabled"';
 250      ?>
 251      <div class="textareas">
 252          <?php
 253          if ( isset( $entry->warnings[ $index ] ) ) :
 254              $referenceable = $entry->warnings[ $index ];
 255  
 256              foreach ( $referenceable as $key => $value ) :
 257              ?>
 258                  <div class="warning secondary">
 259                      <strong><?php _e( 'Warning:', 'glotpress' ); ?></strong> <?php echo esc_html( $value ); ?>
 260  
 261                      <?php if ( $can_approve ) : ?>
 262                          <a href="#" class="discard-warning" data-nonce="<?php echo esc_attr( wp_create_nonce( 'discard-warning_' . $index . $key ) ); ?>" data-key="<?php echo esc_attr( $key ); ?>" data-index="<?php echo esc_attr( $index ); ?>"><?php _e( 'Discard', 'glotpress' ); ?></a>
 263                      <?php endif; ?>
 264                  </div>
 265          <?php
 266              endforeach;
 267  
 268          endif;
 269          ?>
 270          <blockquote class="translation"><em><small><?php echo prepare_original( esc_translation( gp_array_get( $entry->translations, $index ) ) ); // WPCS: XSS ok. ?></small></em></blockquote>
 271          <textarea class="foreign-text" name="translation[<?php echo esc_attr( $entry->original_id ); ?>][]" id="translation_<?php echo esc_attr( $entry->original_id ); ?>_<?php echo esc_attr( $index ); ?>" <?php echo $disabled; // WPCS: XSS ok. ?>><?php echo gp_prepare_translation_textarea( esc_translation( gp_array_get( $entry->translations, $index ) ) ); // WPCS: XSS ok. ?></textarea>
 272  
 273          <p>
 274              <?php
 275              if ( $can_edit ) {
 276                  gp_entry_actions();
 277              }
 278              elseif ( is_user_logged_in() ) {
 279                  _e( 'You are not allowed to edit this translation.', 'glotpress' );
 280              }
 281              else {
 282                  printf( __( 'You <a href="%s">have to log in</a> to edit this translation.', 'glotpress' ), esc_url( wp_login_url( gp_url_current() ) ) );
 283              }
 284              ?>
 285          </p>
 286      </div>
 287      <?php
 288  }
 289  
 290  function display_status( $status ) {
 291      $status_labels = [
 292          'current'  => _x( 'current', 'Single Status', 'glotpress' ),
 293          'waiting'  => _x( 'waiting', 'Single Status', 'glotpress' ),
 294          'fuzzy'    => _x( 'fuzzy', 'Single Status', 'glotpress' ),
 295          'old'      => _x( 'old', 'Single Status', 'glotpress' ),
 296          'rejected' => _x( 'rejected', 'Single Status', 'glotpress' ),
 297      ];
 298      if ( isset( $status_labels[ $status ] ) ) {
 299          $status = $status_labels[ $status ];
 300      }
 301      $status = preg_replace( '/^[+-]/', '', $status);
 302      return $status ? $status : _x( 'untranslated', 'Single Status', 'glotpress' );
 303  }
 304  
 305  function references( $project, $entry ) {
 306  
 307      /**
 308       * Filter whether to show references of a translation string on a translation row.
 309       *
 310       * @since 1.0.0
 311       *
 312       * @param boolean           $references Whether to show references.
 313       * @param GP_Project        $project    The current project.
 314       * @param Translation_Entry $entry      Translation entry object.
 315       */
 316      $show_references = apply_filters( 'gp_show_references', (bool) $entry->references, $project, $entry );
 317  
 318      if ( ! $show_references ) return;
 319      ?>
 320      <dl><dt>
 321      <?php _e( 'References:', 'glotpress' ); ?>
 322      <ul class="refs">
 323          <?php
 324          foreach( $entry->references as $reference ):
 325              list( $file, $line ) = array_pad( explode( ':', $reference ), 2, 0 );
 326              if ( $source_url = $project->source_url( $file, $line ) ):
 327                  ?>
 328                  <li><a target="_blank" tabindex="-1" href="<?php echo $source_url; ?>"><?php echo $file.':'.$line ?></a></li>
 329                  <?php
 330              else :
 331                  echo "<li>$file:$line</li>";
 332              endif;
 333          endforeach;
 334          ?>
 335      </ul></dt></dl>
 336  <?php
 337  }
 338  
 339  /**
 340   * Output the bulk actions toolbar in the translations page.
 341   *
 342   * @param string $bulk_action     The URL to submit the form to.
 343   * @param string $can_write       Can the current user write translations to the database.
 344   * @param string $translation_set The current translation set.
 345   * @param string $location        The location of this toolbar, used to make id's unique for each instance on a page.
 346   */
 347  function gp_translations_bulk_actions_toolbar( $bulk_action, $can_write, $translation_set, $location = 'top' ) {
 348  ?>
 349  <form id="bulk-actions-toolbar-<?php echo esc_attr( $location ); ?>" class="filters-toolbar bulk-actions" action="<?php echo $bulk_action; // WPCS: XSS Ok. ?>" method="post">
 350      <div>
 351      <select name="bulk[action]" id="bulk-action-<?php echo esc_attr( $location ); ?>" class="bulk-action">
 352          <option value="" selected="selected"><?php _e( 'Bulk Actions', 'glotpress' ); ?></option>
 353          <option value="approve"><?php _ex( 'Approve', 'Action', 'glotpress' ); ?></option>
 354          <option value="reject"><?php _ex( 'Reject', 'Action', 'glotpress' ); ?></option>
 355          <option value="fuzzy"><?php _ex( 'Fuzzy', 'Action', 'glotpress' ); ?></option>
 356      <?php if ( $can_write ) : ?>
 357          <option value="set-priority" class="hide-if-no-js"><?php _e( 'Set Priority', 'glotpress' ); ?></option>
 358      <?php endif; ?>
 359          <?php
 360  
 361          /**
 362           * Fires inside the bulk action menu for translation sets.
 363           *
 364           * Printing out option elements here will add those to the translation
 365           * bulk options drop down menu.
 366           *
 367           * @since 1.0.0
 368           *
 369           * @param GP_Translation_Set $set The translation set.
 370           */
 371          do_action( 'gp_translation_set_bulk_action', $translation_set );
 372          ?>
 373      </select>
 374      <?php if ( $can_write ) : ?>
 375      <select name="bulk[priority]" id="bulk-priority-<?php echo esc_attr( $location ); ?>" class="bulk-priority hidden">
 376      <?php
 377      $labels = [
 378          'hidden' => _x( 'hidden', 'Priority', 'glotpress' ),
 379          'low'    => _x( 'low', 'Priority', 'glotpress' ),
 380          'normal' => _x( 'normal', 'Priority', 'glotpress' ),
 381          'high'   => _x( 'high', 'Priority', 'glotpress' ),
 382      ];
 383  
 384      foreach ( GP::$original->get_static( 'priorities' ) as $value => $label ) {
 385          if ( isset( $labels[ $label ] ) ) {
 386              $label = $labels[ $label ];
 387          }
 388  
 389          echo "\t<option value='" . esc_attr( $value ) . "' " . selected( 'normal', $value, false ) . '>' . esc_html( $label ) . "</option>\n"; // WPCS: XSS Ok.
 390      }
 391      ?>
 392      </select>
 393      <?php endif; ?>
 394      <input type="hidden" name="bulk[redirect_to]" value="<?php echo esc_attr( gp_url_current() ); ?>" id="bulk-redirect_to-<?php echo esc_attr( $location ); ?>" />
 395      <input type="hidden" name="bulk[row-ids]" value="" id="bulk-row-ids-<?php echo esc_attr( $location ); ?>" />
 396      <input type="submit" class="button" value="<?php esc_attr_e( 'Apply', 'glotpress' ); ?>" />
 397      </div>
 398      <?php
 399          $nonce = gp_route_nonce_field( 'bulk-actions', false );
 400          $nonce = str_replace( 'id="_gp_route_nonce"', 'id="_gp_route_nonce_' . esc_attr( $location ) . '"', $nonce );
 401          echo $nonce; // WPCS: XSS Ok.
 402      ?>
 403  </form>
 404  <?php
 405  }


Generated: Fri Nov 22 01:01:58 2019 Cross-referenced by PHPXref 0.7.1