[ Index ]

PHP Cross Reference of GlotPress

title

Body

[close]

/gp-includes/things/ -> translation-set.php (source)

   1  <?php
   2  /**
   3   * Things: GP_Translation_Set class
   4   *
   5   * @package GlotPress
   6   * @subpackage Things
   7   * @since 1.0.0
   8   */
   9  
  10  /**
  11   * Core class used to implement the translation sets.
  12   *
  13   * @since 1.0.0
  14   */
  15  class GP_Translation_Set extends GP_Thing {
  16  
  17      var $table_basename           = 'gp_translation_sets';
  18      var $field_names              = array( 'id', 'name', 'slug', 'project_id', 'locale' );
  19      var $non_db_field_names       = array( 'current_count', 'untranslated_count', 'waiting_count', 'fuzzy_count', 'all_count', 'warnings_count', 'percent_translated', 'wp_locale', 'last_modified' );
  20      var $int_fields               = array( 'id', 'project_id' );
  21      var $non_updatable_attributes = array( 'id' );
  22  
  23      /**
  24       * ID of the translation set.
  25       *
  26       * @var int
  27       */
  28      public $id;
  29  
  30      /**
  31       * Name of the translation set.
  32       *
  33       * @var string
  34       */
  35      public $name;
  36  
  37      /**
  38       * Slug of the translation set.
  39       *
  40       * @var string
  41       */
  42      public $slug;
  43  
  44      /**
  45       * Project ID of the translation set.
  46       *
  47       * @var int
  48       */
  49      public $project_id;
  50  
  51      /**
  52       * Locale of the translation set.
  53       *
  54       * @var string
  55       */
  56      public $locale;
  57  
  58      /**
  59       * GP project of the translation set.
  60       *
  61       * @var GP_Project
  62       */
  63      public $project;
  64  
  65      /**
  66       * Number of waiting translations.
  67       *
  68       * @var int
  69       */
  70      public $waiting_count;
  71  
  72      /**
  73       * Number of fuzzy translations.
  74       *
  75       * @var int
  76       */
  77      public $fuzzy_count;
  78  
  79      /**
  80       * Number of untranslated originals.
  81       *
  82       * @var int
  83       */
  84      public $untranslated_count;
  85  
  86      /**
  87       * Number of current translations.
  88       *
  89       * @var int
  90       */
  91      public $current_count;
  92  
  93      /**
  94       * Number of translations with warnings.
  95       *
  96       * @var int
  97       */
  98      public $warnings_count;
  99  
 100      /**
 101       * Number of all originals.
 102       *
 103       * @var int
 104       */
 105      public $all_count;
 106  
 107      /**
 108       * Sets restriction rules for fields.
 109       *
 110       * @since 1.0.0
 111       *
 112       * @param GP_Validation_Rules $rules The validation rules instance.
 113       */
 114  	public function restrict_fields( $rules ) {
 115          $rules->name_should_not_be( 'empty' );
 116          $rules->slug_should_not_be( 'empty' );
 117          $rules->locale_should_not_be( 'empty' );
 118          $rules->project_id_should_not_be( 'empty' );
 119      }
 120  
 121      /**
 122       * Normalizes an array with key-value pairs representing
 123       * a GP_Translation_Set object.
 124       *
 125       * @since 1.0.0
 126       *
 127       * @param array $args Arguments for a GP_Translation_Set object.
 128       * @return array Normalized arguments for a GP_Translation_Set object.
 129       */
 130  	public function normalize_fields( $args ) {
 131          $args = parent::normalize_fields( $args );
 132  
 133          if ( isset( $args['name'] ) && empty( $args['name'] ) ) {
 134              if ( isset( $args['locale'] ) && ! empty( $args['locale'] ) ) {
 135                  $locale       = GP_locales::by_slug( $args['locale'] );
 136                  $args['name'] = $locale->english_name;
 137              }
 138          }
 139  
 140          if ( isset( $args['slug'] ) && ! $args['slug'] ) {
 141              $args['slug'] = 'default';
 142          }
 143  
 144          if ( ! empty( $args['slug'] ) ) {
 145              $args['slug'] = gp_sanitize_slug( $args['slug'] );
 146          }
 147  
 148          return $args;
 149      }
 150  
 151      /**
 152       * Returns the English name of a locale.
 153       *
 154       * If the slug of the locale is not 'default' then the name of the
 155       * current translation sets gets added as a suffix.
 156       *
 157       * @since 1.0.0
 158       *
 159       * @param  string $separator Separator, in case the slug is not 'default'. Default: '&rarr;'.
 160       * @return string The English name of a locale.
 161       */
 162  	public function name_with_locale( $separator = '&rarr;' ) {
 163          $locale = GP_Locales::by_slug( $this->locale );
 164          $parts  = array( $locale->english_name );
 165  
 166          if ( 'default' !== $this->slug ) {
 167              $parts[] = $this->name;
 168          }
 169  
 170          return implode( '&nbsp;' . $separator . '&nbsp;', $parts );
 171      }
 172  
 173  	public function by_project_id_slug_and_locale( $project_id, $slug, $locale_slug ) {
 174          $result = $this->one(
 175              "SELECT * FROM $this->table
 176              WHERE slug = %s AND project_id= %d AND locale = %s",
 177              $slug,
 178              $project_id,
 179              $locale_slug
 180          );
 181  
 182          if ( ! $result && 0 === $project_id ) {
 183              $result = $this->create(
 184                  array(
 185                      'project_id' => $project_id,
 186                      'name'       => GP_Locales::by_slug( $locale_slug )->english_name,
 187                      'slug'       => $slug,
 188                      'locale'     => $locale_slug,
 189                  )
 190              );
 191          }
 192  
 193          return $result;
 194      }
 195  
 196  	public function by_locale( $locale_slug ) {
 197          return $this->many(
 198              "SELECT * FROM $this->table
 199              WHERE locale = %s",
 200              $locale_slug
 201          );
 202      }
 203  
 204  	public function existing_locales() {
 205          global $wpdb;
 206  
 207          // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
 208          return $wpdb->get_col( "SELECT DISTINCT(locale) FROM $this->table" );
 209      }
 210  
 211  	public function existing_slugs() {
 212          global $wpdb;
 213  
 214          // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
 215          return $wpdb->get_col( "SELECT DISTINCT(slug) FROM $this->table" );
 216      }
 217  
 218  	public function by_project_id( $project_id ) {
 219          return $this->many(
 220              "SELECT * FROM $this->table
 221              WHERE project_id = %d ORDER BY name ASC",
 222              $project_id
 223          );
 224      }
 225  
 226      /**
 227       * Import translations from a Translations object.
 228       *
 229       * @param  Translations $translations   the translations to be imported to this translation-set.
 230       * @param  string       $desired_status 'current', 'waiting' or 'fuzzy'.
 231       * @return boolean or void
 232       */
 233  	public function import( $translations, $desired_status = 'current' ) {
 234          wp_raise_memory_limit( 'gp_translations_import' );
 235  
 236          if ( ! isset( $this->project ) || ! $this->project ) {
 237              $this->project = GP::$project->get( $this->project_id );
 238          }
 239  
 240          // Fuzzy is also checked in the flags, but if all strings in an import are fuzzy, fuzzy status can be forced.
 241          if ( ! in_array( $desired_status, array( 'current', 'waiting', 'fuzzy' ), true ) ) {
 242              return false;
 243          }
 244  
 245          $locale = GP_Locales::by_slug( $this->locale );
 246          $user   = wp_get_current_user();
 247  
 248          $existing_translations = array();
 249  
 250          $current_translations_list        = GP::$translation->for_translation(
 251              $this->project,
 252              $this,
 253              'no-limit',
 254              array(
 255                  'status'     => 'current',
 256                  'translated' => 'yes',
 257              )
 258          );
 259          $existing_translations['current'] = new Translations();
 260          foreach ( $current_translations_list as $entry ) {
 261              $existing_translations['current']->add_entry( $entry );
 262          }
 263          unset( $current_translations_list );
 264  
 265          $translations_added = 0;
 266          foreach ( $translations->entries as $entry ) {
 267              if ( empty( $entry->translations ) ) {
 268                  continue;
 269              }
 270  
 271              $is_fuzzy = in_array( 'fuzzy', $entry->flags, true );
 272  
 273              /**
 274               * Filter whether to import fuzzy translations.
 275               *
 276               * @since 1.0.0
 277               *
 278               * @param bool              $import_over  Import fuzzy translation. Default true.
 279               * @param Translation_Entry $entry        Translation entry object to import.
 280               * @param Translations      $translations Translations collection.
 281               */
 282              if ( $is_fuzzy && ! apply_filters( 'gp_translation_set_import_fuzzy_translations', true, $entry, $translations ) ) {
 283                  continue;
 284              }
 285  
 286              /**
 287               * Filters the the status of imported translations of a translation set.
 288               *
 289               * @since 1.0.0
 290               * @since 2.3.0 Added `$new_translation` and `$old_translation` parameters.
 291               *
 292               * @param string              $status          The status of imported translations.
 293               * @param Translation_Entry   $new_translation Translation entry object to import.
 294               * @param GP_Translation|null $old_translation The previous translation.
 295               */
 296              $entry->status = apply_filters( 'gp_translation_set_import_status', $is_fuzzy ? 'fuzzy' : $desired_status, $entry, null );
 297  
 298              $entry->warnings = maybe_unserialize( GP::$translation_warnings->check( $entry->singular, $entry->plural, $entry->translations, $locale ) );
 299              if ( ! empty( $entry->warnings ) && 'current' === $entry->status ) {
 300                  $entry->status = 'waiting';
 301              }
 302  
 303              // Lazy load other entries.
 304              if ( ! isset( $existing_translations[ $entry->status ] ) ) {
 305                  $existing_translations_list              = GP::$translation->for_translation(
 306                      $this->project,
 307                      $this,
 308                      'no-limit',
 309                      array(
 310                          'status'     => $entry->status,
 311                          'translated' => 'yes',
 312                      )
 313                  );
 314                  $existing_translations[ $entry->status ] = new Translations();
 315                  foreach ( $existing_translations_list as $_entry ) {
 316                      $existing_translations[ $entry->status ]->add_entry( $_entry );
 317                  }
 318                  unset( $existing_translations_list );
 319              }
 320  
 321              $create     = false;
 322              $translated = $existing_translations[ $entry->status ]->translate_entry( $entry );
 323              if ( 'current' !== $entry->status && ! $translated ) {
 324                  // Don't create an entry if it already exists as current.
 325                  $translated = $existing_translations['current']->translate_entry( $entry );
 326              }
 327  
 328              if ( $translated ) {
 329                  // We have the same string translated, so create a new one if they don't match.
 330                  $entry->original_id      = $translated->original_id;
 331                  $translated_is_different = array_pad( $entry->translations, $locale->nplurals, null ) !== $translated->translations;
 332  
 333                  /**
 334                   * Filter whether to import over an existing translation on a translation set.
 335                   *
 336                   * @since 1.0.0
 337                   *
 338                   * @param bool $import_over Import over an existing translation.
 339                   */
 340                  $create = apply_filters( 'gp_translation_set_import_over_existing', $translated_is_different );
 341              } else {
 342                  // we don't have the string translated, let's see if the original is there
 343                  $original = GP::$original->by_project_id_and_entry( $this->project->id, $entry, '+active' );
 344                  if ( $original ) {
 345                      $entry->original_id = $original->id;
 346                      $create             = true;
 347                  }
 348              }
 349              if ( $create ) {
 350                  if ( $user ) {
 351                      $entry->user_id = $user->ID;
 352                  }
 353  
 354                  $entry->translation_set_id = $this->id;
 355  
 356                  $entry->status = apply_filters( 'gp_translation_set_import_status', $entry->status, $entry, $translated );
 357                  // Check for errors.
 358                  $translation = GP::$translation->create( $entry );
 359                  if ( is_object( $translation ) ) {
 360                      $translation->set_status( $entry->status );
 361                      $translations_added += 1;
 362                  }
 363              }
 364          }
 365  
 366          gp_clean_translation_set_cache( $this->id );
 367  
 368          /**
 369           * Fires after translations have been imported to a translation set.
 370           *
 371           * @since 1.0.0
 372           *
 373           * @param int $translation_set The ID of the translation set the import was made into.
 374           */
 375          do_action( 'gp_translations_imported', $this->id );
 376  
 377          return $translations_added;
 378      }
 379  
 380      /**
 381       * Retrieves the number of waiting translations.
 382       *
 383       * @return int Number of waiting translations.
 384       */
 385  	public function waiting_count() {
 386          if ( ! isset( $this->waiting_count ) ) {
 387              $this->update_status_breakdown();
 388          }
 389  
 390          return $this->waiting_count;
 391      }
 392  
 393      /**
 394       * Retrieves the number of untranslated originals.
 395       *
 396       * @return int Number of untranslated originals.
 397       */
 398  	public function untranslated_count() {
 399          if ( ! isset( $this->untranslated_count ) ) {
 400              $this->update_status_breakdown();
 401          }
 402  
 403          return $this->untranslated_count;
 404      }
 405  
 406      /**
 407       * Retrieves the number of fuzzy translations.
 408       *
 409       * @return int Number of fuzzy translations.
 410       */
 411  	public function fuzzy_count() {
 412          if ( ! isset( $this->fuzzy_count ) ) {
 413              $this->update_status_breakdown();
 414          }
 415  
 416          return $this->fuzzy_count;
 417      }
 418  
 419      /**
 420       * Retrieves the number of current translations.
 421       *
 422       * @return int Number of current translations.
 423       */
 424  	public function current_count() {
 425          if ( ! isset( $this->current_count ) ) {
 426              $this->update_status_breakdown();
 427          }
 428  
 429          return $this->current_count;
 430      }
 431  
 432      /**
 433       * Retrieves the number of translations with warnings.
 434       *
 435       * @return int Number of translations with warnings.
 436       */
 437  	public function warnings_count() {
 438          if ( ! isset( $this->warnings_count ) ) {
 439              $this->update_status_breakdown();
 440          }
 441  
 442          return $this->warnings_count;
 443      }
 444  
 445      /**
 446       * Retrieves the number of all originals.
 447       *
 448       * @return int Number of all originals.
 449       */
 450  	public function all_count() {
 451          if ( ! isset( $this->all_count ) ) {
 452              $this->update_status_breakdown();
 453          }
 454  
 455          return $this->all_count;
 456      }
 457  
 458      /**
 459       * Populates the count properties.
 460       */
 461  	public function update_status_breakdown() {
 462          $counts = wp_cache_get( $this->id, 'translation_set_status_breakdown' );
 463  
 464          /*
 465           * The format was changed in 2.1 and 3.0.
 466           *
 467           * In 2.1 the format was changed to an array of objects in the following sequence,
 468           * however not all may exist in the array, so for example, the array may only be 3
 469           * entries long and skip any of the values:
 470           *
 471           *     [0] = Current translations
 472           *     [1] = Fuzzy translations
 473           *     [2] = Rejected translations
 474           *     [3] = Old translations
 475           *     [4] = Translations with warnings
 476           *     [5] = All translations
 477           *
 478           * In 3.0 the untranslated object was added:
 479           *
 480           *     [0] = Current translations
 481           *     [1] = Fuzzy translations
 482           *     [2] = Rejected translations
 483           *     [3] = Old translations
 484           *     [4] = Translations with warnings
 485           *     [5] = Untranslated originals
 486           *     [6] = All translations
 487           *
 488           * Version 3.0 also introduced the cache 'version' array entry to allow for easy
 489           * detection of when the cache should be expired due to changes in the cache.
 490           *
 491           * Note: The _version key is unset after the cache is loaded so that it does not
 492           * get used in the for loops when setting the object properties.
 493           *
 494           */
 495          if ( ! is_array( $counts ) || ! array_key_exists( '_version', $counts ) || GP_CACHE_VERSION !== $counts['_version'] ) {
 496              global $wpdb;
 497              $counts = array();
 498  
 499              $status_counts = $wpdb->get_results(
 500                  $wpdb->prepare(
 501                      "SELECT
 502                          t.status AS translation_status,
 503                          COUNT(*) AS total,
 504                          COUNT( CASE WHEN o.priority = '-2' THEN o.priority END ) AS `hidden`,
 505                          COUNT( CASE WHEN o.priority <> '-2' THEN o.priority END ) AS `public`
 506                      FROM {$wpdb->gp_translations} AS t
 507                      INNER JOIN {$wpdb->gp_originals} AS o ON t.original_id = o.id
 508                      WHERE
 509                          t.translation_set_id = %d
 510                          AND o.status = '+active'
 511                      GROUP BY t.status",
 512                      $this->id
 513                  )
 514              );
 515  
 516              if ( $status_counts ) {
 517                  $counts = $status_counts;
 518              }
 519  
 520              $warnings_counts = $wpdb->get_row(
 521                  $wpdb->prepare(
 522                      "SELECT
 523                          COUNT(*) AS total,
 524                          COUNT( CASE WHEN o.priority = '-2' THEN o.priority END ) AS `hidden`,
 525                          COUNT( CASE WHEN o.priority <> '-2' THEN o.priority END ) AS `public`
 526                      FROM {$wpdb->gp_translations} AS t
 527                      INNER JOIN {$wpdb->gp_originals} AS o ON t.original_id = o.id
 528                      WHERE
 529                          t.translation_set_id = %d AND
 530                          o.status = '+active' AND
 531                          ( t.status = 'current' OR t.status = 'waiting' )
 532                          AND warnings IS NOT NULL
 533                          AND warnings != ''",
 534                      $this->id
 535                  )
 536              );
 537  
 538              if ( $warnings_counts ) {
 539                  $counts[] = (object) array(
 540                      'translation_status' => 'warnings',
 541                      'total'              => (int) $warnings_counts->total,
 542                      'hidden'             => (int) $warnings_counts->hidden,
 543                      'public'             => (int) $warnings_counts->public,
 544                  );
 545              }
 546  
 547              $untranslated_counts = $wpdb->get_row(
 548                  $wpdb->prepare(
 549                      "SELECT
 550                          COUNT(*) AS total,
 551                          COUNT( CASE WHEN o.priority = '-2' THEN o.priority END ) AS `hidden`,
 552                          COUNT( CASE WHEN o.priority <> '-2' THEN o.priority END ) AS `public`
 553                      FROM {$wpdb->gp_originals} AS o
 554                      LEFT JOIN {$wpdb->gp_translations} AS t ON o.id = t.original_id AND t.translation_set_id = %d AND t.status != 'rejected' AND t.status != 'old'
 555                      WHERE
 556                          o.project_id = %d AND
 557                          o.status = '+active' AND
 558                          t.translation_0 IS NULL",
 559                      $this->id,
 560                      $this->project_id
 561                  )
 562              );
 563  
 564              if ( $untranslated_counts ) {
 565                  $counts[] = (object) array(
 566                      'translation_status' => 'untranslated',
 567                      'total'              => (int) $untranslated_counts->total,
 568                      'public'             => (int) $untranslated_counts->public,
 569                      'hidden'             => (int) $untranslated_counts->hidden,
 570                  );
 571              }
 572  
 573              $counts['_version'] = GP_CACHE_VERSION;
 574  
 575              wp_cache_set( $this->id, $counts, 'translation_set_status_breakdown' );
 576          }
 577  
 578          if ( array_key_exists( '_version', $counts ) ) {
 579              unset( $counts['_version'] );
 580          }
 581  
 582          $all_count = GP::$original->count_by_project_id( $this->project_id, 'all' );
 583          $counts[]  = (object) array(
 584              'translation_status' => 'all',
 585              'total'              => $all_count->total,
 586              'hidden'             => $all_count->hidden,
 587              'public'             => $all_count->public,
 588          );
 589  
 590          $statuses   = GP::$translation->get_static( 'statuses' );
 591          $statuses[] = 'warnings';
 592          $statuses[] = 'untranslated';
 593          $statuses[] = 'all';
 594          foreach ( $statuses as $status ) {
 595              $this->{$status . '_count'} = 0;
 596          }
 597  
 598          $user_can_view_hidden = GP::$permission->current_user_can( 'write', 'project', $this->project_id );
 599          foreach ( $counts as $count ) {
 600              if ( in_array( $count->translation_status, $statuses, true ) ) {
 601                  $this->{$count->translation_status . '_count'} = $user_can_view_hidden ? (int) $count->total : (int) $count->public;
 602              }
 603          }
 604      }
 605  
 606      /**
 607       * Copies translations from a translation set to the current one
 608       *
 609       * This function doesn't merge then, just copies unconditionally. If a translation already exists, it will be duplicated.
 610       * When copying translations from another project, it will search to find the original first.
 611       */
 612  	public function copy_translations_from( $source_translation_set_id ) {
 613          global $wpdb;
 614          $current_date = $this->now_in_mysql_format();
 615  
 616          $source_set = GP::$translation_set->get( $source_translation_set_id );
 617          if ( $source_set->project_id != $this->project_id ) {
 618              $translations = GP::$translation->find_many_no_map( "translation_set_id = '{$source_set->id}'" );
 619              foreach ( $translations as $entry ) {
 620                  $source_original = GP::$original->get( $entry->original_id );
 621                  $original        = GP::$original->by_project_id_and_entry( $this->project_id, $source_original );
 622                  if ( $original ) {
 623                      $entry->original_id        = $original->id;
 624                      $entry->translation_set_id = $this->id;
 625                      GP::$translation->create( $entry );
 626                  }
 627              }
 628          } else {
 629              return $this->query(
 630                  "INSERT INTO $wpdb->gp_translations (
 631                      original_id,       translation_set_id, translation_0, translation_1, translation_2, user_id, status, date_added,       date_modified, warnings
 632                  )
 633                  SELECT
 634                      original_id, %s AS translation_set_id, translation_0, translation_1, translation_2, user_id, status, date_added, %s AS date_modified, warnings
 635                  FROM $wpdb->gp_translations WHERE translation_set_id = %s",
 636                  $this->id,
 637                  $current_date,
 638                  $source_translation_set_id
 639              );
 640          }
 641      }
 642  
 643  
 644  	public function percent_translated() {
 645          $original_counts = GP::$original->count_by_project_id( $this->project_id, 'all' );
 646  
 647          if ( GP::$permission->current_user_can( 'write', 'project', $this->project_id ) ) {
 648              $original_count = $original_counts->total;
 649          } else {
 650              $original_count = $original_counts->public;
 651          }
 652  
 653          return $original_count ? floor( $this->current_count() / $original_count * 100 ) : 0;
 654      }
 655  
 656      /**
 657       * Retrieves the last modified date of a translation in this translation set.
 658       *
 659       * @since 1.0.0
 660       *
 661       * @return string|false The last modified date on success, false on failure.
 662       */
 663  	public function last_modified() {
 664          return GP::$translation->last_modified( $this );
 665      }
 666  
 667      /**
 668       * Deletes a translation set and all of its translations and glossaries.
 669       *
 670       * @since 2.0.0
 671       *
 672       * @return bool
 673       */
 674  	public function delete() {
 675          GP::$translation->delete_many( array( 'translation_set_id' => $this->id ) );
 676  
 677          GP::$glossary->delete_many( array( 'translation_set_id', $this->id ) );
 678  
 679          return parent::delete();
 680      }
 681  
 682      /**
 683       * Executes after creating a translation set.
 684       *
 685       * @since 3.0.0
 686       *
 687       * @return bool
 688       */
 689  	public function after_create() {
 690          /**
 691           * Fires after creating a translation set.
 692           *
 693           * @since 3.0.0
 694           *
 695           * @param GP_Translation_Set $translation_set The translation set that was created.
 696           */
 697          do_action( 'gp_translation_set_created', $this );
 698  
 699          return true;
 700      }
 701  
 702      /**
 703       * Executes after saving a translation set.
 704       *
 705       * @since 3.0.0
 706       *
 707       * @param GP_Translation_Set $translation_set_before Translation set before the update.
 708       * @return bool
 709       */
 710  	public function after_save( $translation_set_before ) {
 711          /**
 712           * Fires after saving a translation set.
 713           *
 714           * @since 3.0.0
 715           *
 716           * @param GP_Translation_Set $translation_set        Translation set following the update.
 717           * @param GP_Translation_Set $translation_set_before Translation set before the update.
 718           */
 719          do_action( 'gp_translation_set_saved', $this, $translation_set_before );
 720  
 721          return true;
 722      }
 723  
 724      /**
 725       * Executes after deleting a translation set.
 726       *
 727       * @since 3.0.0
 728       *
 729       * @return bool
 730       */
 731  	public function after_delete() {
 732          /**
 733           * Fires after deleting a translation set.
 734           *
 735           * @since 3.0.0
 736           *
 737           * @param GP_Translation_Set $translation_set The translation set that was deleted.
 738           */
 739          do_action( 'gp_translation_set_deleted', $this );
 740  
 741          return true;
 742      }
 743  }
 744  GP::$translation_set = new GP_Translation_Set();


Generated: Thu Jul 29 01:01:59 2021 Cross-referenced by PHPXref 0.7.1