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


Generated: Fri Sep 25 01:01:51 2020 Cross-referenced by PHPXref 0.7.1