Making WordPress.org

Changeset 12527


Ignore:
Timestamp:
04/05/2023 07:33:49 PM (3 years ago)
Author:
amieiro
Message:

Traslate: Make all the requests async in the Translation Memory

See https://github.com/WordPress/wordpress.org/pull/137

Location:
sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-plugin.php

    r12510 r12527  
    1818     * @var array
    1919     */
    20     private $queue = [];
     20    private $queue = array();
    2121
    2222    /**
     
    3636     */
    3737    private function __construct() {
    38         add_action( 'plugins_loaded', [ $this, 'plugins_loaded' ] );
     38        add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ) );
    3939    }
    4040
     
    4343     */
    4444    public function plugins_loaded() {
    45         add_action( 'template_redirect', [ $this, 'register_routes' ], 5 );
    46         add_action( 'gp_pre_tmpl_load', [ $this, 'pre_tmpl_load' ], 10, 2 );
    47         add_action( 'wporg_translate_suggestions', [ $this, 'extend_translation_suggestions' ] );
     45        add_action( 'template_redirect', array( $this, 'register_routes' ), 5 );
     46        add_action( 'gp_pre_tmpl_load', array( $this, 'pre_tmpl_load' ), 10, 2 );
     47        add_action( 'wporg_translate_suggestions', array( $this, 'extend_translation_suggestions' ) );
    4848
    4949        if ( 'cli' !== PHP_SAPI ) {
    50             add_action( 'gp_translation_created', [ $this, 'translation_updated' ], 3 );
    51             add_action( 'gp_translation_saved', [ $this, 'translation_updated' ], 3 );
     50            add_action( 'gp_translation_created', array( $this, 'translation_updated' ), 3 );
     51            add_action( 'gp_translation_saved', array( $this, 'translation_updated' ), 3 );
    5252
    5353            // DB Writes are delayed until shutdown to bulk-update the stats during imports.
    54             add_action( 'shutdown', [ $this, 'schedule_tm_update' ], 3 );
     54            add_action( 'shutdown', array( $this, 'schedule_tm_update' ), 3 );
    5555        }
    5656
    57         add_action( self::TM_UPDATE_EVENT, [ Translation_Memory_Client::class, 'update' ] );
     57        add_action( self::TM_UPDATE_EVENT, array( Translation_Memory_Client::class, 'update' ) );
    5858    }
    5959
     
    7676     */
    7777    public function schedule_tm_update() {
    78         remove_action( 'gp_translation_created', [ $this, 'translation_updated' ], 3 );
    79         remove_action( 'gp_translation_saved', [ $this, 'translation_updated' ], 3 );
     78        remove_action( 'gp_translation_created', array( $this, 'translation_updated' ), 3 );
     79        remove_action( 'gp_translation_saved', array( $this, 'translation_updated' ), 3 );
    8080
    8181        if ( ! $this->queue ) {
     
    8383        }
    8484
    85         wp_schedule_single_event( time() + 60, self::TM_UPDATE_EVENT, [ 'translations' => $this->queue ] );
     85        wp_schedule_single_event( time() + 60, self::TM_UPDATE_EVENT, array( 'translations' => $this->queue ) );
    8686    }
    8787
     
    9090     */
    9191    public function register_routes() {
    92         $dir = '([^_/][^/]*)';
    93         $path = '(.+?)';
     92        $dir      = '([^_/][^/]*)';
     93        $path     = '(.+?)';
    9494        $projects = 'projects';
    95         $project = $projects . '/' . $path;
    96         $locale = '(' . implode( '|', wp_list_pluck( GP_Locales::locales(), 'slug' ) ) . ')';
    97         $set = "$project/$locale/$dir";
     95        $project  = $projects . '/' . $path;
     96        $locale   = '(' . implode( '|', wp_list_pluck( GP_Locales::locales(), 'slug' ) ) . ')';
     97        $set      = "$project/$locale/$dir";
    9898
    99         GP::$router->prepend( "/$set/-get-tm-suggestions", [ __NAMESPACE__ . '\Routes\Translation_Memory', 'get_suggestions' ] );
    100         GP::$router->prepend( "/$set/-get-other-language-suggestions", [ __NAMESPACE__ . '\Routes\Other_Languages', 'get_suggestions' ] );
    101         GP::$router->prepend( "/-save-external-suggestions", [ __NAMESPACE__ . '\Routes\Translation_Memory', 'update_external_translations' ], 'post' );
     99        GP::$router->prepend( "/$set/-get-tm-suggestions", array( __NAMESPACE__ . '\Routes\Translation_Memory', 'get_suggestions' ) );
     100        GP::$router->prepend( "/$set/-get-other-language-suggestions", array( __NAMESPACE__ . '\Routes\Other_Languages', 'get_suggestions' ) );
     101        GP::$router->prepend( "/$set/-get-tm-openai-suggestions", array( __NAMESPACE__ . '\Routes\Translation_Memory', 'get_openai_suggestions' ) );
     102        GP::$router->prepend( "/$set/-get-tm-deepl-suggestions", array( __NAMESPACE__ . '\Routes\Translation_Memory', 'get_deepl_suggestions' ) );
     103        GP::$router->prepend( '/-save-external-suggestions', array( __NAMESPACE__ . '\Routes\Translation_Memory', 'update_external_translations' ), 'post' );
    102104    }
    103105
     
    113115            'gp-translation-suggestions',
    114116            plugins_url( 'css/translation-suggestions.css', PLUGIN_FILE ),
    115             [],
     117            array(),
    116118            '20220401'
    117119        );
     
    121123            'gp-translation-suggestions',
    122124            plugins_url( './js/translation-suggestions.js', PLUGIN_FILE ),
    123             [ 'gp-editor' ],
     125            array( 'gp-editor' ),
    124126            '20190510'
     127        );
     128
     129        $gp_default_sort         = get_user_option( 'gp_default_sort' );
     130        $get_openai_translations = ! empty( trim( gp_array_get( $gp_default_sort, 'openai_api_key' ) ) );
     131        $get_deepl_translations  = ! empty( trim( gp_array_get( $gp_default_sort, 'deepl_api_key' ) ) );
     132
     133        wp_localize_script(
     134            'gp-translation-suggestions',
     135            'gpTranslationSuggestions',
     136            array(
     137                'nonce'                     => wp_create_nonce( 'gp-translation-suggestions' ),
     138                'get_external_translations' => array(
     139                    'get_openai_translations' => $get_openai_translations,
     140                    'get_deepl_translations'  => $get_deepl_translations,
     141                ),
     142            )
    125143        );
    126144
     
    130148            'gp-translation-suggestions',
    131149            sprintf(
    132                 "window.WPORG_TRANSLATION_MEMORY_API_URL = %s;\nwindow.WPORG_OTHER_LANGUAGES_API_URL = %s;",
     150                "window.WPORG_TRANSLATION_MEMORY_API_URL = %s;\nwindow.WPORG_TRANSLATION_MEMORY_OPENAI_API_URL = %s;\nwindow.WPORG_TRANSLATION_MEMORY_DEEPL_API_URL = %s;\nwindow.WPORG_OTHER_LANGUAGES_API_URL = %s;",
    133151                wp_json_encode( gp_url_project( $args['project'], gp_url_join( $args['locale_slug'], $args['translation_set_slug'], '-get-tm-suggestions' ) ) ),
     152                wp_json_encode( gp_url_project( $args['project'], gp_url_join( $args['locale_slug'], $args['translation_set_slug'], '-get-tm-openai-suggestions' ) ) ),
     153                wp_json_encode( gp_url_project( $args['project'], gp_url_join( $args['locale_slug'], $args['translation_set_slug'], '-get-tm-deepl-suggestions' ) ) ),
    134154                wp_json_encode( gp_url_project( $args['project'], gp_url_join( $args['locale_slug'], $args['translation_set_slug'], '-get-other-language-suggestions' ) ) )
    135155            )
     
    147167            return;
    148168        }
    149 
    150169
    151170        // Prevent querying the TM for long strings which usually time out
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php

    r12513 r12527  
    1212
    1313    public function get_suggestions( $project_path, $locale_slug, $set_slug ) {
     14        $type                                  = 'Translation';
    1415        $original_id                           = gp_get( 'original' );
    1516        $translation_id                        = gp_get( 'translation', 0 );
     
    3940        }
    4041
    41         $suggestions                     = Translation_Memory_Client::query( $original->singular, $locale );
     42        $suggestions = Translation_Memory_Client::query( $original->singular, $locale );
     43
     44        if ( is_wp_error( $suggestions ) ) {
     45            wp_send_json_error( $suggestions->get_error_code() );
     46        }
     47
     48        wp_send_json_success(
     49            gp_tmpl_get_output(
     50                'translation-memory-suggestions',
     51                compact( 'suggestions', 'type' ),
     52                PLUGIN_DIR . '/templates/'
     53            )
     54        );
     55    }
     56
     57    public function get_openai_suggestions( $project_path, $locale_slug, $set_slug ) {
     58        $type                                  = 'OpenAI';
     59        $original_id                           = gp_get( 'original' );
     60        $translation_id                        = gp_get( 'translation', 0 );
     61        $nonce                                 = gp_get( 'nonce' );
     62        $gp_default_sort                       = get_user_option( 'gp_default_sort' );
     63        $external_services_exclude_some_status = gp_array_get( $gp_default_sort, 'external_services_exclude_some_status', 0 );
     64        $translation                           = null;
     65        $suggestions                           = array();
     66
     67        if ( ! wp_verify_nonce( $nonce, 'translation-memory-suggestions-' . $original_id ) ) {
     68            wp_send_json_error( 'invalid_nonce' );
     69        }
     70
     71        if ( empty( $original_id ) ) {
     72            wp_send_json_error( 'no_original' );
     73        }
     74
     75        $original = GP::$original->get( $original_id );
     76        if ( ! $original ) {
     77            wp_send_json_error( 'invalid_original' );
     78        }
     79
    4280        $current_set_slug                = 'default';
    4381        $locale_glossary_translation_set = GP::$translation_set->by_project_id_slug_and_locale( 0, $current_set_slug, $locale_slug );
     
    4987            }
    5088            if ( ! $translation || ( 'current' != $translation->status && 'rejected' != $translation->status && 'old' != $translation->status ) ) {
    51                 $openai_suggestions = $this->get_openai_suggestion( $original->singular, $locale_slug, $locale_glossary );
    52                 $deepl_suggestions  = $this->get_deepl_suggestion( $original->singular, $locale_slug, $set_slug );
     89                $suggestions = $this->get_openai_suggestion( $original->singular, $locale_slug, $locale_glossary );
    5390            }
    5491        } else {
    55             $openai_suggestions = $this->get_openai_suggestion( $original->singular, $locale_slug, $locale_glossary );
    56             $deepl_suggestions  = $this->get_deepl_suggestion( $original->singular, $locale_slug, $set_slug );
    57         }
    58 
    59         if ( is_wp_error( $suggestions ) ) {
    60             wp_send_json_error( $suggestions->get_error_code() );
    61         }
    62 
    63         wp_send_json_success( gp_tmpl_get_output( 'translation-memory-suggestions', compact( 'suggestions', 'openai_suggestions', 'deepl_suggestions' ), PLUGIN_DIR . '/templates/' ) );
     92            $suggestions = $this->get_openai_suggestion( $original->singular, $locale_slug, $locale_glossary );
     93        }
     94
     95        wp_send_json_success(
     96            gp_tmpl_get_output(
     97                'translation-memory-suggestions',
     98                compact( 'suggestions', 'type' ),
     99                PLUGIN_DIR . '/templates/'
     100            )
     101        );
     102    }
     103
     104    public function get_deepl_suggestions( $project_path, $locale_slug, $set_slug ) {
     105        $type                                  = 'DeepL';
     106        $original_id                           = gp_get( 'original' );
     107        $translation_id                        = gp_get( 'translation', 0 );
     108        $nonce                                 = gp_get( 'nonce' );
     109        $gp_default_sort                       = get_user_option( 'gp_default_sort' );
     110        $external_services_exclude_some_status = gp_array_get( $gp_default_sort, 'external_services_exclude_some_status', 0 );
     111        $translation                           = null;
     112        $suggestions                           = array();
     113
     114        if ( ! wp_verify_nonce( $nonce, 'translation-memory-suggestions-' . $original_id ) ) {
     115            wp_send_json_error( 'invalid_nonce' );
     116        }
     117
     118        if ( empty( $original_id ) ) {
     119            wp_send_json_error( 'no_original' );
     120        }
     121
     122        $original = GP::$original->get( $original_id );
     123        if ( ! $original ) {
     124            wp_send_json_error( 'invalid_original' );
     125        }
     126
     127        $locale = $locale_slug;
     128        if ( 'default' !== $set_slug ) {
     129            $locale .= '_' . $set_slug;
     130        }
     131
     132        if ( $external_services_exclude_some_status ) {
     133            if ( $translation_id > 0 ) {
     134                $translation = GP::$translation->get( $translation_id );
     135            }
     136            if ( ! $translation || ( 'current' != $translation->status && 'rejected' != $translation->status && 'old' != $translation->status ) ) {
     137                $suggestions = $this->get_deepl_suggestion( $original->singular, $locale_slug, $set_slug );
     138            }
     139        } else {
     140            $suggestions = $this->get_deepl_suggestion( $original->singular, $locale_slug, $set_slug );
     141        }
     142
     143        wp_send_json_success(
     144            gp_tmpl_get_output(
     145                'translation-memory-suggestions',
     146                compact( 'suggestions', 'type' ),
     147                PLUGIN_DIR . '/templates/'
     148            )
     149        );
    64150    }
    65151
     
    378464     */
    379465    private function update_one_external_translation( string $translation, string $suggestion, string $external_translations_used, string $external_same_translations_used ) {
    380         $sameTranslationUsed      = $translation == $suggestion;
     466        $is_the_same_translation  = $translation == $suggestion;
    381467        $gp_external_translations = get_user_option( 'gp_external_translations' );
    382468        $translations_used        = gp_array_get( $gp_external_translations, $external_translations_used, 0 );
     
    387473        $translations_used++;
    388474        $gp_external_translations[ $external_translations_used ] = $translations_used;
    389         if ( $sameTranslationUsed ) {
     475        if ( $is_the_same_translation ) {
    390476            if ( ! is_int( $same_translations_used ) || $same_translations_used < 0 ) {
    391477                $same_translations_used = 0;
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js

    r12510 r12527  
    3030        xhr.always( function() {
    3131            $container.removeClass( 'fetching' );
     32            removeNoSuggestionsMessage( $container );
    3233        } );
    3334    }
     
    5253    }
    5354
     55    /**
     56     * Gets the suggestions from the OpenAI API.
     57     *
     58     * @return {void}
     59     **/
     60    function maybeFetchOpenAISuggestions() {
     61        maybeFetchExternalSuggestions( gpTranslationSuggestions.get_external_translations.get_openai_translations, window.WPORG_TRANSLATION_MEMORY_OPENAI_API_URL );
     62    }
     63
     64    /**
     65     * Gets the suggestions from the DeepL API.
     66     *
     67     * @return {void}
     68     **/
     69    function maybeFetchDeeplSuggestions() {
     70        maybeFetchExternalSuggestions( gpTranslationSuggestions.get_external_translations.get_deepl_translations, window.WPORG_TRANSLATION_MEMORY_DEEPL_API_URL );
     71    }
     72
     73    /**
     74     * Gets the suggestions from an external service.
     75     *
     76     * @param getExternalSuggestions
     77     * @param apiUrl
     78     */
     79    function maybeFetchExternalSuggestions( getExternalSuggestions, apiUrl ) {
     80        var $container = $gp.editor.current.find( '.suggestions__translation-memory' );
     81        if ( !$container.length ) {
     82            return;
     83        }
     84        if ( true !== getExternalSuggestions ) {
     85            return;
     86        }
     87
     88        var originalId = $gp.editor.current.original_id;
     89        var translationId = $gp.editor.current.translation_id;
     90        var nonce = $container.data( 'nonce' );
     91
     92        fetchSuggestions( $container, apiUrl, originalId, translationId, nonce );
     93    }
     94
    5495    function maybeFetchOtherLanguageSuggestions() {
    5596        var $container = $gp.editor.current.find( '.suggestions__other-languages' );
     
    71112    }
    72113
     114    /**
     115     * Removes the "No suggestions" message if there are suggestions.
     116     *
     117     * This is needed because the suggestions are loaded asynchronously.
     118     *
     119     * @param $container
     120     */
     121    function removeNoSuggestionsMessage( $container ) {
     122        var hasSuggestions = $container.find( '.translation-suggestion' ).length > 0;
     123        if ( hasSuggestions ) {
     124            $container.find( '.no-suggestions' ).hide();
     125        } else {
     126            $container = removeNoSuggestionsDuplicateMessage( $container );
     127        }
     128    }
     129
     130    /**
     131     * Removes duplicate "No suggestions" messages.
     132     *
     133     * @param $container
     134     * @returns {*|jQuery}
     135     */
     136    function removeNoSuggestionsDuplicateMessage( $container ) {
     137        var $html = $($container);
     138        var $paragraphs = $html.find('p');
     139        var uniqueParagraphs = [];
     140
     141        $paragraphs.each(function() {
     142            var paragraphText = $(this).text().trim();
     143
     144            if (uniqueParagraphs.indexOf(paragraphText) === -1) {
     145                uniqueParagraphs.push(paragraphText);
     146            } else {
     147                $(this).remove();
     148            }
     149        });
     150
     151        return $html.prop('outerHTML');
     152    }
    73153    function copySuggestion( event ) {
    74154        if ( 'A' === event.target.tagName ) {
     
    97177        return function() {
    98178            original.apply( $gp.editor, arguments );
    99 
    100179            maybeFetchTranslationMemorySuggestions();
     180            maybeFetchOpenAISuggestions();
     181            maybeFetchDeeplSuggestions();
    101182            maybeFetchOtherLanguageSuggestions();
    102183        }
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/templates/translation-memory-suggestions.php

    r12510 r12527  
    11<?php
    2 if ( empty( $suggestions ) && empty( $openai_suggestions ) && empty( $deepl_suggestions ) ) {
     2if ( empty( $suggestions ) ) {
    33    echo '<p class="no-suggestions">No suggestions.</p>';
    44} else {
     
    66    foreach ( $suggestions as $suggestion ) {
    77        echo '<li>';
    8         echo '<div class="translation-suggestion with-tooltip" tabindex="0" role="button" aria-pressed="false" aria-label="Copy translation">';
    9             echo '<span class="translation-suggestion__score">' . number_format( 100 * $suggestion['similarity_score'] ) . '%</span>';
    10 
     8        echo '<div class="translation-suggestion with-tooltip ' . esc_html( strtolower( $type ) ) . '" tabindex="0" role="button" aria-pressed="false" aria-label="Copy translation">';
     9            echo '<span class="' . esc_html( strtolower( $type ) ) . '-suggestion__score">';
     10        if ( 'Translation' == $type ) {
     11            echo number_format( 100 * $suggestion['similarity_score'] ) . '%';
     12        } else {
     13            echo esc_html( $type );
     14        }
     15            echo '</span>';
    1116            echo '<span class="translation-suggestion__translation">';
    1217                echo esc_translation( $suggestion['translation'] );
    1318
    14                 if ( $suggestion['diff'] ) {
    15                     echo '<span class="translation-suggestion__original-diff">' . wp_kses_post( $suggestion['diff'] ) . '</span>';
    16                 }
    17             echo '</span>';
    18 
    19             echo '<span aria-hidden="true" class="translation-suggestion__translation-raw">' . esc_translation( $suggestion['translation'] ) . '</span>';
    20 
    21             echo '<button type="button" class="button is-small copy-suggestion">Copy</button>';
    22         echo '</div>';
    23         echo '</li>';
    24     }
    25     foreach ( $openai_suggestions as $suggestion ) {
    26         echo '<li>';
    27         echo '<div class="translation-suggestion with-tooltip openai" tabindex="0" role="button" aria-pressed="false" aria-label="Copy translation">';
    28             echo '<span class="openai-suggestion__score">OpenAI</span>';
    29 
    30             echo '<span class="translation-suggestion__translation">';
    31                 echo esc_translation( $suggestion['translation'] );
    32 
    33                 if ( $suggestion['diff'] ) {
    34                     echo '<span class="translation-suggestion__original-diff">' . wp_kses_post( $suggestion['diff'] ) . '</span>';
    35                 }
    36             echo '</span>';
    37 
    38             echo '<span aria-hidden="true" class="translation-suggestion__translation-raw">' . esc_translation( $suggestion['translation'] ) . '</span>';
    39 
    40             echo '<button type="button" class="button is-small copy-suggestion">Copy</button>';
    41         echo '</div>';
    42         echo '</li>';
    43     }
    44     foreach ( $deepl_suggestions as $suggestion ) {
    45         echo '<li>';
    46         echo '<div class="translation-suggestion with-tooltip deepl" tabindex="0" role="button" aria-pressed="false" aria-label="Copy translation">';
    47             echo '<span class="deepl-suggestion__score">DeepL</span>';
    48 
    49             echo '<span class="translation-suggestion__translation">';
    50                 echo esc_translation( $suggestion['translation'] );
    51 
    52                 if ( $suggestion['diff'] ) {
    53                     echo '<span class="translation-suggestion__original-diff">' . wp_kses_post( $suggestion['diff'] ) . '</span>';
    54                 }
     19        if ( $suggestion['diff'] ) {
     20            echo '<span class="translation-suggestion__original-diff">' . wp_kses_post( $suggestion['diff'] ) . '</span>';
     21        }
    5522            echo '</span>';
    5623
Note: See TracChangeset for help on using the changeset viewer.