WordPress.org

Making WordPress.org

Ticket #1636: 1636.patch

File 1636.patch, 7.1 KB (added by ocean90, 5 years ago)
  • trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-plugin-directory/inc/class-plugin.php

     
    3737                $cache_purger = new Cache_Purge\Cache_Purger();
    3838                $cache_purger->register_events();
    3939
     40                $translation_sync = new Sync\Translation_Sync();
     41                $translation_sync->register_events();
     42
    4043                if ( defined( 'WP_CLI' ) && WP_CLI ) {
    4144                        $this->register_cli_commands();
    4245                }
  • trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-plugin-directory/inc/sync/class-translation-sync.php

     
     1<?php
     2
     3namespace WordPressdotorg\GlotPress\Plugin_Directory\Sync;
     4
     5use GP;
     6use GP_Locales;
     7use GP_Translation;
     8
     9class Translation_Sync {
     10        public $master_project = 'wp-plugins';
     11
     12        private $queue = array();
     13
     14        private $project_mapping = array(
     15                'dev'           => 'stable',
     16                'stable'        => 'dev',
     17                'dev-readme'    => 'stable-readme',
     18                'stable-readme' => 'dev-readme',
     19        );
     20
     21        public function register_events() {
     22                add_action( 'gp_translation_created', array( $this, 'queue_translation_for_sync' ), 5 );
     23                add_action( 'gp_translation_saved', array( $this, 'queue_translation_for_sync' ), 5 );
     24
     25                add_action( 'shutdown', array( $this, 'sync_translations' ) );
     26        }
     27
     28        /**
     29         * Adds a translation to a cache purge queue when a translation was created
     30         * or updated.
     31         *
     32         * @param \GP_Translation $translation Created/updated translation.
     33         */
     34        public function queue_translation_for_sync( $translation ) {
     35                global $wpdb;
     36
     37                if ( 'current' !== $translation->status ) {
     38                        return;
     39                }
     40
     41                $project = GP::$project->one(
     42                        "SELECT p.* FROM {$wpdb->gp_projects} AS p JOIN {$wpdb->gp_originals} AS o ON o.project_id = p.id WHERE o.id = %d",
     43                        $translation->original_id
     44                );
     45
     46                if ( ! $project ) {
     47                        return;
     48                }
     49
     50                if ( ! $this->project_is_plugin( $project->path ) ) {
     51                        return;
     52                }
     53
     54                $this->queue[ $project->path ][ $translation->id ] = $translation;
     55        }
     56
     57        /**
     58         * Syncs translations between two plugin projects.
     59         */
     60        public function sync_translations() {
     61                if ( empty( $this->queue ) ) {
     62                        return;
     63                }
     64
     65                // Avoid recursion.
     66                remove_action( 'gp_translation_created', array( $this, 'queue_translation_for_sync' ), 5 );
     67                remove_action( 'gp_translation_saved', array( $this, 'queue_translation_for_sync' ), 5 );
     68
     69                foreach ( $this->queue as $project_path => $translations ) {
     70                        $project = $this->get_dev_or_stable_project( $project_path );
     71                        if ( ! $project ) {
     72                                error_log( 'project not found' );
     73                                continue;
     74                        }
     75
     76                        foreach ( $translations as $translation ) {
     77                                $original = GP::$original->get( $translation->original_id );
     78                                if ( ! $original ) {
     79                                        error_log( 'original not found' );
     80                                        continue;
     81                                }
     82
     83                                $translation_set = GP::$translation_set->get( $translation->translation_set_id );
     84                                if ( ! $translation_set ) {
     85                                        error_log( 'set not found' );
     86                                        continue;
     87                                }
     88
     89                                $original_counterpart = GP::$original->by_project_id_and_entry(
     90                                        $project->id,
     91                                        $original,
     92                                        '+active'
     93                                );
     94
     95                                if ( ! $original_counterpart ) {
     96                                        error_log( 'original counterpart not found' );
     97                                        continue;
     98                                }
     99
     100                                $translation_set_counterpart = GP::$translation_set->by_project_id_slug_and_locale(
     101                                        $project->id,
     102                                        $translation_set->slug,
     103                                        $translation_set->locale
     104                                );
     105
     106                                if ( ! $translation_set_counterpart ) {
     107                                        error_log( 'set counterpart not found' );
     108                                        continue;
     109                                }
     110
     111                                $this->copy_translation_into_set( $translation, $translation_set_counterpart, $original_counterpart );
     112                                error_log( "copied $translation->id, $translation_set_counterpart->id, $original_counterpart->id" );
     113                        }
     114                }
     115        }
     116
     117        /**
     118         * Duplicates a translation to another translation set.
     119         *
     120         * @param \GP_Translation     $translation         The translation which should be duplicated.
     121         * @param \GP_Translation_Set $new_translation_set The new translation set.
     122         * @param \GP_Original        $new_original        The new original.
     123         * @return bool False on failure, true on success.
     124         */
     125        private function copy_translation_into_set( $translation, $new_translation_set, $new_original ) {
     126                $locale = GP_Locales::by_slug( $new_translation_set->locale );
     127                $new_translation = array();
     128
     129                for ( $i = 0; $i < $locale->nplurals; $i++ ) {
     130                        $new_translation[] = $translation->{"translation_{$i}"};
     131                }
     132
     133                // Check if the translation already exists.
     134                $existing_translations = GP::$translation->find( array(
     135                        'translation_set_id' => $new_translation_set->id,
     136                        'original_id'        => $new_original->id,
     137                        'status'             => 'current',
     138                ) );
     139
     140                foreach ( $existing_translations as $_existing_translation ) {
     141                        $existing_translation = array();
     142                        for ( $i = 0; $i < $locale->nplurals; $i++ ) {
     143                                $existing_translation[] = $_existing_translation->{"translation_{$i}"};
     144                        }
     145
     146                        if ( $existing_translation === $new_translation ) {
     147                                return true;
     148                        }
     149                }
     150
     151                $copy = new GP_Translation( $translation->fields() );
     152                $copy->original_id = $new_original->id;
     153                $copy->translation_set_id = $new_translation_set->id;
     154                $copy->status = 'current';
     155
     156                $translation = GP::$translation->create( $copy );
     157                if ( ! $translation ) {
     158                        error_log( 'translation insert failure' );
     159                        return false;
     160                }
     161
     162                $translation->set_as_current();
     163
     164                return true;
     165        }
     166
     167        /**
     168         * Retrieves the counterpart of a plugin project.
     169         *
     170         * @param string $project_path The path of a plugin project.
     171         * @return \GP_Project|null A project on success, null on failure.
     172         */
     173        private function get_dev_or_stable_project( $project_path ) {
     174                static $project_cache;
     175
     176                if ( null === $project_cache ) {
     177                        $project_cache = array();
     178                }
     179
     180                if ( isset( $project_cache[ $project_path ] ) ) {
     181                        return $project_cache[ $project_path ];
     182                }
     183
     184                $project = basename( $project_path );
     185                $counterpart = $this->project_mapping[ $project ];
     186                $new_project_path = preg_replace( "#/{$project}$#", "/$counterpart", $project_path, 1 );
     187
     188                $project = GP::$project->by_path( $new_project_path );
     189                $project_cache[ $project_path ] = $project;
     190
     191                return $project;
     192        }
     193
     194        /**
     195         * Returns whether a project path belongs to the plugins project.
     196         *
     197         * @param string $path Path of a project.
     198         *
     199         * @return bool True if it's a plugin, false if not.
     200         */
     201        private function project_is_plugin( $path ) {
     202                if ( empty( $path ) ) {
     203                        return false;
     204                }
     205
     206                $path = '/' . trim( $path, '/' ) . '/';
     207                if ( false === strpos( $path, "/{$this->master_project}/" ) ) {
     208                        return false;
     209                }
     210
     211                return true;
     212        }
     213
     214}