From 1b27ed042598ba6739763ed93d4093bd58c66648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Amieiro?= <1667814+amieiro@users.noreply.github.com> Date: Fri, 9 Aug 2024 13:03:58 +0200 Subject: [PATCH 1/8] Delete a suggestion from TM --- .../templates/style.css | 4 + .../inc/class-plugin.php | 6 +- .../inc/class-translation-memory-client.php | 75 +++--- .../inc/routes/class-translation-memory.php | 86 ++++++- .../js/translation-suggestions.js | 228 +++++++++++------- .../translation-memory-suggestions.php | 3 + 6 files changed, 287 insertions(+), 115 deletions(-) diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/templates/style.css b/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/templates/style.css index c52e9b96ea..2c6951ffca 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/templates/style.css +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/templates/style.css @@ -3223,6 +3223,10 @@ ul.sidebar-tabs { margin-left: auto; } +button.is-small.delete-suggestion { + margin-right: 0.5rem; +} + .meta.other-locales span.locale.unique { margin-right: 14px; } diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-plugin.php b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-plugin.php index dfc9d49b77..fe65136412 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-plugin.php +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-plugin.php @@ -102,6 +102,7 @@ public function register_routes() { GP::$router->prepend( "/$set/-get-other-language-suggestions", array( __NAMESPACE__ . '\Routes\Other_Languages', 'get_suggestions' ) ); GP::$router->prepend( "/$set/-get-tm-openai-suggestions", array( __NAMESPACE__ . '\Routes\Translation_Memory', 'get_openai_suggestions' ) ); GP::$router->prepend( "/$set/-get-tm-deepl-suggestions", array( __NAMESPACE__ . '\Routes\Translation_Memory', 'get_deepl_suggestions' ) ); + GP::$router->prepend( "/$set/-delete-tm-suggestion", array( __NAMESPACE__ . '\Routes\Translation_Memory', 'delete_suggestion' ), 'post' ); } /** @@ -148,11 +149,12 @@ public function pre_tmpl_load( $template, $args ) { wp_add_inline_script( 'gp-translation-suggestions', sprintf( - "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;", + "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;\nwindow.WPORG_TRANSLATION_MEMORY_API_DELETE_URL = %s;", wp_json_encode( gp_url_project( $args['project'], gp_url_join( $args['locale_slug'], $args['translation_set_slug'], '-get-tm-suggestions' ) ) ), wp_json_encode( gp_url_project( $args['project'], gp_url_join( $args['locale_slug'], $args['translation_set_slug'], '-get-tm-openai-suggestions' ) ) ), wp_json_encode( gp_url_project( $args['project'], gp_url_join( $args['locale_slug'], $args['translation_set_slug'], '-get-tm-deepl-suggestions' ) ) ), - wp_json_encode( gp_url_project( $args['project'], gp_url_join( $args['locale_slug'], $args['translation_set_slug'], '-get-other-language-suggestions' ) ) ) + wp_json_encode( gp_url_project( $args['project'], gp_url_join( $args['locale_slug'], $args['translation_set_slug'], '-get-other-language-suggestions' ) ) ), + wp_json_encode( gp_url_project( $args['project'], gp_url_join( $args['locale_slug'], $args['translation_set_slug'], '-delete-tm-suggestion' ) ) ) ) ); } diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-translation-memory-client.php b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-translation-memory-client.php index 3f0724df0c..365489944d 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-translation-memory-client.php +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-translation-memory-client.php @@ -12,7 +12,7 @@ class Translation_Memory_Client { - const API_ENDPOINT = 'https://translate.wordpress.com/api/tm/'; + const API_ENDPOINT = 'https://translate.wordpress.com/api/tm/'; const API_BULK_ENDPOINT = 'https://translate.wordpress.com/api/tm/-bulk'; /** @@ -22,7 +22,7 @@ class Translation_Memory_Client { * @return true|\WP_Error True on success, WP_Error on failure. */ public static function update( array $translations ) { - $requests = []; + $requests = array(); foreach ( $translations as $original_id => $translation_id ) { $translation = GP::$translation->get( $translation_id ); @@ -40,34 +40,36 @@ public static function update( array $translations ) { $locale .= '_' . $translation_set->slug; } - $requests[] = [ + $requests[] = array( 'source' => $original->fields(), - 'translations' => [ - [ + 'translations' => array( + array( 'singular' => $translation->translation_0, 'plural' => $translation->translation_1, 'locale' => $locale, - ], - ], - ]; + ), + ), + ); } if ( ! $requests ) { return new WP_Error( 'no_translations' ); } - $body = wp_json_encode( [ - 'token' => WPCOM_TM_TOKEN, - 'requests' => $requests, - ] ); + $body = wp_json_encode( + array( + 'token' => WPCOM_TM_TOKEN, + 'requests' => $requests, + ) + ); $request = wp_remote_post( self::API_BULK_ENDPOINT, - [ + array( 'timeout' => 10, 'user-agent' => 'WordPress.org Translate', 'body' => $body, - ] + ) ); if ( is_wp_error( $request ) ) { @@ -100,20 +102,24 @@ public static function query( string $text, string $target_locale ) { return new WP_Error( 'no_token' ); } - $url = add_query_arg( urlencode_deep( [ - 'text' => $text, - 'target' => $target_locale, - 'token' => WPCOM_TM_TOKEN, - 'ts' => time(), - ] ), self::API_ENDPOINT ); - + $url = add_query_arg( + urlencode_deep( + array( + 'text' => $text, + 'target' => $target_locale, + 'token' => WPCOM_TM_TOKEN, + 'ts' => time(), + ) + ), + self::API_ENDPOINT + ); $request = wp_remote_get( $url, - [ + array( 'timeout' => 4, 'user-agent' => 'WordPress.org Translate', - ] + ) ); if ( is_wp_error( $request ) ) { @@ -132,22 +138,35 @@ public static function query( string $text, string $target_locale ) { } if ( empty( $result['matches'] ) ) { - return []; + return array(); } - $suggestions = []; + $suggestions = array(); foreach ( $result['matches'] as $match ) { - $suggestions[] = [ + $suggestions[] = array( 'similarity_score' => $match['score'], 'source' => $match['source'], 'translation' => $match['text'], 'diff' => ( 1 === $match['score'] ) ? null : self::diff( $text, $match['source'] ), - ]; + ); } return $suggestions; } + /** + * Deletes a translation from translation memory. + * + * @param string $original_string Original string. + * @param string $translation_string Translation string. + * @param string $locale_slug Locale slug. + * @param string $set_slug Translation set slug. + */ + public static function delete( string $original_string, string $translation_string, string $locale_slug, string $set_slug ):bool { + // @todo Implement. + return true; + } + /** * Generates the differences between two sequences of strings. * @@ -156,7 +175,7 @@ public static function query( string $text, string $target_locale ) { * @return string HTML markup for the differences between the two texts. */ protected static function diff( $previous_text, $text ) { - $diff = new Text_Diff( 'auto', [ [ $text ], [ $previous_text ] ] ); + $diff = new Text_Diff( 'auto', array( array( $text ), array( $previous_text ) ) ); $renderer = new WP_Text_Diff_Renderer_inline(); return $renderer->render( $diff ); diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php index eca2166c63..55b773a14d 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php @@ -48,10 +48,13 @@ public function get_suggestions( $project_path, $locale_slug, $set_slug ) { wp_send_json_error( $suggestions->get_error_code() ); } + $project = GP::$project->by_path( $project_path ); + $translation_set = GP::$translation_set->by_project_id_slug_and_locale( $project->id, $set_slug, $locale_slug ); + $is_user_a_gte_for_locale = $this->is_user_a_gte_for_locale( wp_get_current_user(), $locale ); wp_send_json_success( gp_tmpl_get_output( 'translation-memory-suggestions', - compact( 'suggestions', 'type' ), + compact( 'suggestions', 'type', 'is_user_a_gte_for_locale' ), PLUGIN_DIR . '/templates/' ) ); @@ -170,6 +173,41 @@ public function get_deepl_suggestions( $project_path, $locale_slug, $set_slug ) ); } + /** + * Delete a suggestion from the translation memory. + * + * @param string $project_path Project path. + * @param string $locale_slug Locale slug. + * @param string $set_slug Set slug. + * + * @return void + */ + public function delete_suggestion( string $project_path, string $locale_slug, string $set_slug ): bool { + $original_id = gp_post( 'originalId' ); + $original_string = gp_post( 'originalString' ); + $translation_string = gp_post( 'translationString' ); + $nonce = gp_post( 'nonce' ); + + if ( ! wp_verify_nonce( $nonce, 'translation-memory-suggestions-' . $original_id ) ) { + wp_send_json_error( 'invalid_nonce' ); + } + + if ( empty( $original_string ) || empty( $translation_string ) ) { + wp_send_json_error( 'missing_data' ); + } + + if ( ! $this->is_user_a_gte_for_locale( wp_get_current_user(), $locale_slug ) ) { + wp_send_json_error( 'user_cannot_delete' ); + } + + $result = Translation_Memory_Client::delete( $original_string, $translation_string, $locale_slug, $set_slug ); + if ( ! $result ) { + wp_send_json_error( 'delete_failed' ); + } + + wp_send_json_success(); + } + /** * Get suggestions from OpenAI (ChatGPT). * @@ -533,5 +571,51 @@ private static function update_one_external_translation( string $translation, st } update_user_option( get_current_user_id(), 'gp_external_translations', $gp_external_translations ); } + + /** + * Determine if the user is a GTE for the given locale. + * + * @param null|WP_User $user User. + * @param string $set Locale set. + * + * @return bool + */ + private function is_user_a_gte_for_locale( $user, $locale ) { + $locale_slug = explode( '_', $locale )[0]; + $locale = GP_Locales::by_slug( $locale_slug ); + if ( ! $locale ) { + return false; + } + + $result = get_sites( + array( + 'locale' => $locale->wp_locale, + 'network_id' => WPORG_GLOBAL_NETWORK_ID, + 'path' => '/', + 'fields' => 'ids', + 'number' => '1', + ) + ); + $site_id = array_shift( $result ); + if ( ! $site_id ) { + return false; + } + + $users = get_users( + array( + 'blog_id' => $site_id, + 'role' => 'general_translation_editor', + 'count_total' => false, + ) + ); + + foreach ( $users as $gte_user ) { + if ( $gte_user->id === $user->id ) { + return true; + } + } + + return false; + } } diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js index 1a6bcfc1ad..a2a0788186 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js @@ -26,6 +26,7 @@ /** * Stores the external translations used. + * * @type {object} */ var externalSuggestion = {}; @@ -67,39 +68,47 @@ } // Store a string with a space to avoid making the same request another time. storeTheSuggestionInTheCache( type, originalId, ' ' ); - var xhr = $.ajax( { - url: apiUrl, - data: { - 'original': originalId, - 'translation': translationId, - 'nonce': nonce - }, - dataType: 'json', - cache: false, - } ); - - xhr.done( function( response ) { - $container.find( '.suggestions__loading-indicator' ).remove(); - if ( response.success ) { - $container.append( response.data ); - storeTheSuggestionInTheCache( type, originalId, response.data ); - removeNoSuggestionsMessage( $container ); - copyTranslationMemoryToSidebarTab( $container ); - } else { - $container.append( $( '', { 'text': 'Error while loading suggestions.' } ) ); + var xhr = $.ajax( + { + url: apiUrl, + data: { + 'original': originalId, + 'translation': translationId, + 'nonce': nonce + }, + dataType: 'json', + cache: false, + } + ); + + xhr.done( + function( response ) { + $container.find( '.suggestions__loading-indicator' ).remove(); + if ( response.success ) { + $container.append( response.data ); + storeTheSuggestionInTheCache( type, originalId, response.data ); + removeNoSuggestionsMessage( $container ); + copyTranslationMemoryToSidebarTab( $container ); + } else { + $container.append( $( '', { 'text': 'Error while loading suggestions.' } ) ); + } + $container.addClass( 'initialized' ); } - $container.addClass( 'initialized' ); - } ); + ); - xhr.fail( function() { - $container.find( '.suggestions__loading-indicator' ).remove(); - $container.append( $( '', { 'text': 'Error while loading suggestions.' } ) ); - $container.addClass( 'initialized' ); - } ); + xhr.fail( + function() { + $container.find( '.suggestions__loading-indicator' ).remove(); + $container.append( $( '', { 'text': 'Error while loading suggestions.' } ) ); + $container.addClass( 'initialized' ); + } + ); - xhr.always( function() { - $container.removeClass( 'fetching' ); - } ); + xhr.always( + function() { + $container.removeClass( 'fetching' ); + } + ); } /** @@ -109,12 +118,12 @@ */ function getSuggestionsForTheFirstRow() { var firstEditor = $( '#translations' ).find( '.editor' ).first(); - var row_id = firstEditor.closest( 'tr' ).attr( 'row' ); + var row_id = firstEditor.closest( 'tr' ).attr( 'row' ); if ( ! row_id ) { return; } - firstEditor.row_id = row_id; - firstEditor.original_id = $gp.editor.original_id_from_row_id( row_id ); + firstEditor.row_id = row_id; + firstEditor.original_id = $gp.editor.original_id_from_row_id( row_id ); firstEditor.translation_id = $gp.editor.translation_id_from_row_id( row_id ); maybeFetchTranslationMemorySuggestions( firstEditor ); maybeFetchOpenAISuggestions( firstEditor ); @@ -188,14 +197,14 @@ add_amount_to_others_tab = function ( sidebarTab, data, originalId ) { let elements = 0; - if ( data?.['helper-history-' + originalId] ) { + if ( data ? .['helper-history-' + originalId] ) { elements += data['helper-history-' + originalId].count; } - if ( data?.['helper-other-locales-' + originalId] ) { + if ( data ? .['helper-other-locales-' + originalId] ) { elements += data['helper-other-locales-' + originalId].count; } - var editor = $('[data-tab="' + sidebarTab + '"]').closest( '.editor' ); - var TMcontainer = editor.find( '.suggestions__translation-memory' ); + var editor = $( '[data-tab="' + sidebarTab + '"]' ).closest( '.editor' ); + var TMcontainer = editor.find( '.suggestions__translation-memory' ); var elementsInTM = 0; if ( TMcontainer.length ) { elementsInTM += TMcontainer.find( '.translation-suggestion.with-tooltip.translation' ).length; @@ -203,10 +212,10 @@ elementsInTM += TMcontainer.find( '.translation-suggestion.with-tooltip.openai' ).length; } elements += elementsInTM; - $( '#summary-translation-memory-' + originalId ).html('Translation Memory (' + elementsInTM + ')'); + $( '#summary-translation-memory-' + originalId ).html( 'Translation Memory (' + elementsInTM + ')' ); let content = 'Others (' + elements + ')'; - $('[data-tab="' + sidebarTab + '"]').html( content ); + $( '[data-tab="' + sidebarTab + '"]' ).html( content ); } /** @@ -217,16 +226,16 @@ * @return {void} */ function copyTranslationMemoryToSidebarTab( $container ){ - var editor = $container.closest( '.editor' ); - var divSidebarWithDiscussion = editor.find( '.meta.discussion' ).first(); - var divId = divSidebarWithDiscussion.attr( 'data-row-id' ); - var TMcontainer = editor.find( '.suggestions__translation-memory' ); - if ( !TMcontainer.length ) { + var editor = $container.closest( '.editor' ); + var divSidebarWithDiscussion = editor.find( '.meta.discussion' ).first(); + var divId = divSidebarWithDiscussion.attr( 'data-row-id' ); + var TMcontainer = editor.find( '.suggestions__translation-memory' ); + if ( ! TMcontainer.length ) { return; } $( '#sidebar-div-others-translation-memory-content-' + divId ).html( TMcontainer.html() ); - add_amount_to_others_tab('sidebar-tab-others-' + divId, window.translationHelpersCache?.[ divId ], divId); + add_amount_to_others_tab( 'sidebar-tab-others-' + divId, window.translationHelpersCache ? .[ divId ], divId ); } /** @@ -267,7 +276,7 @@ */ function maybeFetchTranslationMemorySuggestions( editor ) { var $container = editor.find( '.suggestions__translation-memory' ); - if ( !$container.length ) { + if ( ! $container.length ) { return; } @@ -275,15 +284,15 @@ return; } - if ( !editor.find('translation-suggestion.with-tooltip.translation').first() ) { + if ( ! editor.find( 'translation-suggestion.with-tooltip.translation' ).first() ) { return; } $container.addClass( 'fetching' ); - var originalId = editor.original_id; + var originalId = editor.original_id; var translationId = editor.translation_id; - var nonce = $container.data( 'nonce' ); + var nonce = $container.data( 'nonce' ); fetchSuggestions( $container, window.WPORG_TRANSLATION_MEMORY_API_URL, originalId, translationId, nonce, 'TM' ); } @@ -322,15 +331,15 @@ */ function maybeFetchExternalSuggestions( editor, type, getExternalSuggestions, apiUrl ) { var $container = editor.find( '.suggestions__translation-memory' ); - if ( !$container.length ) { + if ( ! $container.length ) { return; } if ( true !== getExternalSuggestions ) { return; } - var originalId = editor.original_id; + var originalId = editor.original_id; var translationId = editor.translation_id; - var nonce = $container.data( 'nonce' ); + var nonce = $container.data( 'nonce' ); fetchSuggestions( $container, apiUrl, originalId, translationId, nonce, type ); } @@ -354,9 +363,9 @@ $container.addClass( 'fetching' ); - var originalId = editor.original_id; + var originalId = editor.original_id; var translationId = editor.translation_id; - var nonce = $container.data( 'nonce' ); + var nonce = $container.data( 'nonce' ); fetchSuggestions( $container, window.WPORG_OTHER_LANGUAGES_API_URL, originalId , translationId, nonce, 'OL' ); } @@ -387,27 +396,73 @@ * @return {void} */ function removeNoSuggestionsDuplicateMessage( $container ) { - var $html = $($container); - var $paragraphs = $html.find('p'); + var $html = $( $container ); + var $paragraphs = $html.find( 'p' ); var uniqueParagraphs = []; - $paragraphs.each(function() { - var paragraphText = $(this).text().trim(); + $paragraphs.each( + function() { + var paragraphText = $( this ).text().trim(); - if (uniqueParagraphs.indexOf(paragraphText) === -1) { - uniqueParagraphs.push(paragraphText); - } else { - $(this).remove(); + if (uniqueParagraphs.indexOf( paragraphText ) === -1) { + uniqueParagraphs.push( paragraphText ); + } else { + $( this ).remove(); + } } - }); + ); } + + /** + * Removes a suggestion from the TM. + * + * @param {object} event + * + * @return {void} + */ + function deleteSuggestionFromTM( event ) { + event.preventDefault(); + event.stopImmediatePropagation(); + var editor = $gp.editor.current; + var container = editor.find( '.suggestions__translation-memory' ); + if ( ! container.length ) { + return; + } + var row = $( this ).closest( '.translation-suggestion' ); + var deleteButton = row.find( '.delete-suggestion' ); + var originalString = editor.find( '.original-raw' ).text(); + var translationString = row.find( '.translation-suggestion__translation' ).text(); + var originalId = editor.original_id; + var nonce = container.data( 'nonce' ); + deleteButton.prop( 'disabled', true ); + $.ajax( + { + type: 'POST', + url: window.WPORG_TRANSLATION_MEMORY_API_DELETE_URL, + data: { + 'originalId' : originalId, + 'originalString': originalString, + 'translationString': translationString, + 'nonce': nonce + }, + dataType: 'json', + cache: false, + success: function(result) { + if ( true === result.success ) { + row.remove(); + } + } + } + ); + } + function copySuggestion( event ) { if ( 'A' === event.target.tagName ) { return; } - var $el = $( this ).closest( '.translation-suggestion' ); - var $translation = $el.find( '.translation-suggestion__translation-raw'); + var $el = $( this ).closest( '.translation-suggestion' ); + var $translation = $el.find( '.translation-suggestion__translation-raw' ); if ( ! $translation.length ) { return; } @@ -460,11 +515,11 @@ maybeFetchOpenAISuggestions( $gp.editor.current ); maybeFetchDeeplSuggestions( $gp.editor.current ); maybeFetchOtherLanguageSuggestions( $gp.editor.current ); - var nextEditor = $gp.editor.current.nextAll('tr.editor' ).first(); + var nextEditor = $gp.editor.current.nextAll( 'tr.editor' ).first(); if ( nextEditor.length ) { - var row_id = nextEditor.closest( 'tr' ).attr( 'row' ); - nextEditor.row_id = row_id; - nextEditor.original_id = $gp.editor.original_id_from_row_id( row_id ); + var row_id = nextEditor.closest( 'tr' ).attr( 'row' ); + nextEditor.row_id = row_id; + nextEditor.original_id = $gp.editor.original_id_from_row_id( row_id ); nextEditor.translation_id = $gp.editor.translation_id_from_row_id( row_id ); maybeFetchTranslationMemorySuggestions( nextEditor ); maybeFetchOpenAISuggestions( nextEditor ); @@ -479,11 +534,14 @@ original(); $( $gp.editor.table ) + .on( 'click', '.translation-suggestion .delete-suggestion', deleteSuggestionFromTM ) .on( 'click', '.translation-suggestion', copySuggestion ) .on( 'click', '.translation-suggestion', addSuggestion ); - $( document ).ready( function() { - getSuggestionsForTheFirstRow(); - }); + $( document ).ready( + function() { + getSuggestionsForTheFirstRow(); + } + ); }; })( $gp.editor.install_hooks ); @@ -499,21 +557,23 @@ return; } externalSuggestion.suggestion_source = $row.data( 'suggestion-source' ) == 'translation' ? 'tm' : $row.data( 'suggestion-source' ); - externalSuggestion.translation = $row.find( '.translation-suggestion__translation' ).text(); + externalSuggestion.translation = $row.find( '.translation-suggestion__translation' ).text(); } - //Prefilter ajax requests to add external translations used to the request. - $.ajaxPrefilter( function ( options ) { - const isSuggestionUsed = Object.keys( externalSuggestion ).length > 0 ? true : false; + // Prefilter ajax requests to add external translations used to the request. + $.ajaxPrefilter( + function ( options ) { + const isSuggestionUsed = Object.keys( externalSuggestion ).length > 0 ? true : false; - if ( ! externalSuggestion || ! isSuggestionUsed ) { - return; - } - if ( 'POST' === options.type && $gp_editor_options.url === options.url ) { - options.data += '&externalTranslationSource=' + encodeURIComponent( externalSuggestion.suggestion_source ); - options.data += '&externalTranslationUsed=' + encodeURIComponent( externalSuggestion.translation ); - externalSuggestion = {}; + if ( ! externalSuggestion || ! isSuggestionUsed ) { + return; + } + if ( 'POST' === options.type && $gp_editor_options.url === options.url ) { + options.data += '&externalTranslationSource=' + encodeURIComponent( externalSuggestion.suggestion_source ); + options.data += '&externalTranslationUsed=' + encodeURIComponent( externalSuggestion.translation ); + externalSuggestion = {}; + } } - }); + ); })( jQuery ); diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/templates/translation-memory-suggestions.php b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/templates/translation-memory-suggestions.php index 05efc2b193..6c87934c3d 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/templates/translation-memory-suggestions.php +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/templates/translation-memory-suggestions.php @@ -25,6 +25,9 @@ echo ''; + if ( $is_user_a_gte_for_locale && 1 == $suggestion['similarity_score'] ) { + echo ''; + } echo ''; echo ''; echo ''; From 75c653b81b6e61f34a00dc3dd6bc67a51f9a5890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Amieiro?= <1667814+amieiro@users.noreply.github.com> Date: Mon, 12 Aug 2024 09:08:29 +0200 Subject: [PATCH 2/8] Hide both rows (main place and sideber) with the incorrect translation --- .../js/translation-suggestions.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js index a2a0788186..58dc924f7d 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js @@ -428,12 +428,15 @@ if ( ! container.length ) { return; } - var row = $( this ).closest( '.translation-suggestion' ); + var row = $( this ).closest( '.translation-suggestion' ); + var rows = editor.find( '.translation-suggestion' ); + var deleteButton = row.find( '.delete-suggestion' ); var originalString = editor.find( '.original-raw' ).text(); var translationString = row.find( '.translation-suggestion__translation' ).text(); var originalId = editor.original_id; var nonce = container.data( 'nonce' ); + deleteButton.prop( 'disabled', true ); $.ajax( { @@ -449,7 +452,14 @@ cache: false, success: function(result) { if ( true === result.success ) { - row.remove(); + rows.filter( + function () { + var translationRaw = $( this ).find( '.translation-suggestion__translation-raw' ).text().trim(); + var score = $( this ).find( '.translation-suggestion__score' ).text().trim(); + + return translationRaw === translationString && score === "100%"; + } + ).hide(); } } } From af6e3bbcaf08c17901e97ba4f00680f1652c17ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Amieiro?= <1667814+amieiro@users.noreply.github.com> Date: Mon, 12 Aug 2024 16:13:30 +0200 Subject: [PATCH 3/8] Disable both Delete buttons --- .../js/translation-suggestions.js | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js index 58dc924f7d..0154bc3985 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js @@ -429,15 +429,22 @@ return; } var row = $( this ).closest( '.translation-suggestion' ); - var rows = editor.find( '.translation-suggestion' ); + var rows = editor.find( '.translation-suggestion.with-tooltip.translation' ); - var deleteButton = row.find( '.delete-suggestion' ); var originalString = editor.find( '.original-raw' ).text(); var translationString = row.find( '.translation-suggestion__translation' ).text(); var originalId = editor.original_id; var nonce = container.data( 'nonce' ); - deleteButton.prop( 'disabled', true ); + var filteredRows = rows.filter( + function() { + var translationRaw = $( this ).find( '.translation-suggestion__translation-raw' ).text().trim(); + var score = $( this ).find( '.translation-suggestion__score' ).text().trim(); + return translationRaw === translationString && score === "100%"; + } + ); + + filteredRows.find( '.delete-suggestion' ).prop( 'disabled', true ); $.ajax( { type: 'POST', @@ -452,17 +459,16 @@ cache: false, success: function(result) { if ( true === result.success ) { - rows.filter( - function () { - var translationRaw = $( this ).find( '.translation-suggestion__translation-raw' ).text().trim(); - var score = $( this ).find( '.translation-suggestion__score' ).text().trim(); - - return translationRaw === translationString && score === "100%"; + filteredRows.each( + function() { + $( this ).remove(); } - ).hide(); + ); } + } - } + }, + 100 ); } From a269763d1e07d5803a8332511a5f131ebe6660ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Amieiro?= <1667814+amieiro@users.noreply.github.com> Date: Tue, 20 Aug 2024 18:58:56 +0200 Subject: [PATCH 4/8] Add a visual confirmation (JS) for the delete --- .../js/translation-suggestions.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js index 0154bc3985..15f94cde2c 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js @@ -423,6 +423,9 @@ function deleteSuggestionFromTM( event ) { event.preventDefault(); event.stopImmediatePropagation(); + if ( ! confirm( 'Are you sure you want to delete this translation from the Translation Memory?' )) { + return; + } var editor = $gp.editor.current; var container = editor.find( '.suggestions__translation-memory' ); if ( ! container.length ) { From be68387b16d967106529d6873cf7caa586bf9963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Amieiro?= <1667814+amieiro@users.noreply.github.com> Date: Thu, 22 Aug 2024 19:46:39 +0200 Subject: [PATCH 5/8] Add changes in the signatures of the methods to support the plurals and the context --- .../templates/style.css | 2 +- .../inc/class-translation-memory-client.php | 69 ++++++++++++++----- .../inc/routes/class-translation-memory.php | 28 ++++---- .../js/translation-suggestions.js | 28 +++++--- .../translation-memory-suggestions.php | 2 +- 5 files changed, 87 insertions(+), 42 deletions(-) diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/templates/style.css b/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/templates/style.css index 2c6951ffca..c1d6490048 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/templates/style.css +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/templates/style.css @@ -3352,4 +3352,4 @@ ul.other-locales li { max-width: 100%; float: none; } -} \ No newline at end of file +} diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-translation-memory-client.php b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-translation-memory-client.php index 365489944d..c08a2048f6 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-translation-memory-client.php +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-translation-memory-client.php @@ -3,6 +3,7 @@ namespace WordPressdotorg\GlotPress\TranslationSuggestions; use GP; +use GP_Locale; use Text_Diff; use WP_Error; use WP_Http; @@ -93,11 +94,12 @@ public static function update( array $translations ) { /** * Queries translation memory for a string. * - * @param string $text Text to search translations for. + * @param string $text Singular text to search translations for. + * @param string $text_plural Plural text to search translations for. * @param string $target_locale Locale to search in. * @return array|\WP_Error List of suggestions on success, WP_Error on failure. */ - public static function query( string $text, string $target_locale ) { + public static function query( string $text, string $text_plural, string $target_locale ) { if ( ! defined( 'WPCOM_TM_TOKEN' ) ) { return new WP_Error( 'no_token' ); } @@ -105,10 +107,11 @@ public static function query( string $text, string $target_locale ) { $url = add_query_arg( urlencode_deep( array( - 'text' => $text, - 'target' => $target_locale, - 'token' => WPCOM_TM_TOKEN, - 'ts' => time(), + 'text' => $text, + 'text_plural' => $text_plural, + 'target' => $target_locale, + 'token' => WPCOM_TM_TOKEN, + 'ts' => time(), ) ), self::API_ENDPOINT @@ -144,10 +147,13 @@ public static function query( string $text, string $target_locale ) { $suggestions = array(); foreach ( $result['matches'] as $match ) { $suggestions[] = array( - 'similarity_score' => $match['score'], - 'source' => $match['source'], - 'translation' => $match['text'], - 'diff' => ( 1 === $match['score'] ) ? null : self::diff( $text, $match['source'] ), + 'similarity_score' => $match['score'], + 'source' => $match['source'], + 'source_plural' => $match['source_plural'], + 'source_context' => $match['source_context'], + 'translation' => $match['text'], + 'translation_plural' => $match['text_plural'], + 'diff' => ( 1 === $match['score'] ) ? null : self::diff( $text, $match['source'] ), ); } @@ -157,13 +163,44 @@ public static function query( string $text, string $target_locale ) { /** * Deletes a translation from translation memory. * - * @param string $original_string Original string. - * @param string $translation_string Translation string. - * @param string $locale_slug Locale slug. - * @param string $set_slug Translation set slug. + * @param array $source Array with the original string (singular and plural) and the context. + * @param array $translation Array with the translation (singular and plural). + * @param string $locale_slug Locale slug. + * @param string $set_slug Translation set slug. + * + * @return bool */ - public static function delete( string $original_string, string $translation_string, string $locale_slug, string $set_slug ):bool { - // @todo Implement. + public static function delete( array $source, array $translation, string $locale_slug, string $set_slug ):bool { + $locale = $locale_slug; + if ( 'default' !== $set_slug ) { + $locale .= '_' . $set_slug; + } + $body = wp_json_encode( + array( + 'token' => WPCOM_TM_TOKEN, + 'source' => $source, + 'translation' => array( + 'singular' => $translation['translation'], + 'plural' => $translation['translation_plural'], + 'locale' => $locale, + ), + ) + ); + $request = wp_remote_post( + self::API_BULK_ENDPOINT, + array( + 'method' => 'DELETE', + 'timeout' => 10, + 'user-agent' => 'WordPress.org Translate', + 'body' => $body, + ) + ); + if ( is_wp_error( $request ) ) { + return false; + } + if ( WP_Http::OK !== wp_remote_retrieve_response_code( $request ) ) { + return false; + } return true; } diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php index 55b773a14d..37cbb9ffc9 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php @@ -5,7 +5,10 @@ use GP; use GP_Locales; use GP_Route; +use GP_Translation; use WordPressdotorg\GlotPress\TranslationSuggestions\Translation_Memory_Client; +use WP_User; +use function cli\err; use const WordPressdotorg\GlotPress\TranslationSuggestions\PLUGIN_DIR; class Translation_Memory extends GP_Route { @@ -42,14 +45,12 @@ public function get_suggestions( $project_path, $locale_slug, $set_slug ) { $locale .= '_' . $set_slug; } - $suggestions = Translation_Memory_Client::query( $original->singular, $locale ); + $suggestions = Translation_Memory_Client::query( $original->singular, $original->plural, $locale ); if ( is_wp_error( $suggestions ) ) { wp_send_json_error( $suggestions->get_error_code() ); } - $project = GP::$project->by_path( $project_path ); - $translation_set = GP::$translation_set->by_project_id_slug_and_locale( $project->id, $set_slug, $locale_slug ); $is_user_a_gte_for_locale = $this->is_user_a_gte_for_locale( wp_get_current_user(), $locale ); wp_send_json_success( gp_tmpl_get_output( @@ -174,7 +175,7 @@ public function get_deepl_suggestions( $project_path, $locale_slug, $set_slug ) } /** - * Delete a suggestion from the translation memory. + * Deletes a suggestion from the translation memory. * * @param string $project_path Project path. * @param string $locale_slug Locale slug. @@ -183,16 +184,15 @@ public function get_deepl_suggestions( $project_path, $locale_slug, $set_slug ) * @return void */ public function delete_suggestion( string $project_path, string $locale_slug, string $set_slug ): bool { - $original_id = gp_post( 'originalId' ); - $original_string = gp_post( 'originalString' ); - $translation_string = gp_post( 'translationString' ); - $nonce = gp_post( 'nonce' ); - + $source = gp_post( 'source' ); + $translation = gp_post( 'translation' ); + $original_id = gp_post( 'originalId' ); + $nonce = gp_post( 'nonce' ); if ( ! wp_verify_nonce( $nonce, 'translation-memory-suggestions-' . $original_id ) ) { wp_send_json_error( 'invalid_nonce' ); } - if ( empty( $original_string ) || empty( $translation_string ) ) { + if ( empty( $source ) || empty( $translation ) ) { wp_send_json_error( 'missing_data' ); } @@ -200,7 +200,7 @@ public function delete_suggestion( string $project_path, string $locale_slug, st wp_send_json_error( 'user_cannot_delete' ); } - $result = Translation_Memory_Client::delete( $original_string, $translation_string, $locale_slug, $set_slug ); + $result = Translation_Memory_Client::delete( $source, $translation, $locale_slug, $set_slug ); if ( ! $result ) { wp_send_json_error( 'delete_failed' ); } @@ -575,12 +575,12 @@ private static function update_one_external_translation( string $translation, st /** * Determine if the user is a GTE for the given locale. * - * @param null|WP_User $user User. - * @param string $set Locale set. + * @param WP_User $user User. + * @param string $locale Locale set. * * @return bool */ - private function is_user_a_gte_for_locale( $user, $locale ) { + private function is_user_a_gte_for_locale( WP_User $user, string $locale ): bool { $locale_slug = explode( '_', $locale )[0]; $locale = GP_Locales::by_slug( $locale_slug ); if ( ! $locale ) { diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js index 15f94cde2c..36be7cb9d8 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js @@ -431,19 +431,27 @@ if ( ! container.length ) { return; } - var row = $( this ).closest( '.translation-suggestion' ); - var rows = editor.find( '.translation-suggestion.with-tooltip.translation' ); - - var originalString = editor.find( '.original-raw' ).text(); - var translationString = row.find( '.translation-suggestion__translation' ).text(); - var originalId = editor.original_id; - var nonce = container.data( 'nonce' ); + var row = $( this ).closest( '.translation-suggestion' ); + var deleteButton = event.target; + var rows = editor.find( '.translation-suggestion.with-tooltip.translation' ); + + var source = { + 'source': deleteButton.dataset.sourceSingular, + 'source_plural': deleteButton.dataset.sourcePlural, + 'source_context': deleteButton.dataset.sourceContext, + }; + var translation = { + 'translation': deleteButton.dataset.translation, + 'translation_plural': deleteButton.dataset.translationPlural, + }; + var originalId = editor.original_id; + var nonce = container.data( 'nonce' ); var filteredRows = rows.filter( function() { var translationRaw = $( this ).find( '.translation-suggestion__translation-raw' ).text().trim(); var score = $( this ).find( '.translation-suggestion__score' ).text().trim(); - return translationRaw === translationString && score === "100%"; + return translationRaw === deleteButton.dataset.translation && score === "100%"; } ); @@ -453,9 +461,9 @@ type: 'POST', url: window.WPORG_TRANSLATION_MEMORY_API_DELETE_URL, data: { + 'source': source, + 'translation': translation, 'originalId' : originalId, - 'originalString': originalString, - 'translationString': translationString, 'nonce': nonce }, dataType: 'json', diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/templates/translation-memory-suggestions.php b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/templates/translation-memory-suggestions.php index 6c87934c3d..1da974a673 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/templates/translation-memory-suggestions.php +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/templates/translation-memory-suggestions.php @@ -26,7 +26,7 @@ echo ''; if ( $is_user_a_gte_for_locale && 1 == $suggestion['similarity_score'] ) { - echo ''; + echo ''; } echo ''; echo ''; From 9e65a5f5f9729eaee5fb810ae9e4f1fb398b9bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Amieiro?= <1667814+amieiro@users.noreply.github.com> Date: Fri, 23 Aug 2024 10:41:40 +0200 Subject: [PATCH 6/8] Remove an unused variable and some linting from code outside of this PR --- .../js/translation-suggestions.js | 253 ++++++++---------- 1 file changed, 115 insertions(+), 138 deletions(-) diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js index 36be7cb9d8..a6ec3963c0 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/js/translation-suggestions.js @@ -26,7 +26,6 @@ /** * Stores the external translations used. - * * @type {object} */ var externalSuggestion = {}; @@ -68,47 +67,39 @@ } // Store a string with a space to avoid making the same request another time. storeTheSuggestionInTheCache( type, originalId, ' ' ); - var xhr = $.ajax( - { - url: apiUrl, - data: { - 'original': originalId, - 'translation': translationId, - 'nonce': nonce - }, - dataType: 'json', - cache: false, - } - ); - - xhr.done( - function( response ) { - $container.find( '.suggestions__loading-indicator' ).remove(); - if ( response.success ) { - $container.append( response.data ); - storeTheSuggestionInTheCache( type, originalId, response.data ); - removeNoSuggestionsMessage( $container ); - copyTranslationMemoryToSidebarTab( $container ); - } else { - $container.append( $( '', { 'text': 'Error while loading suggestions.' } ) ); - } - $container.addClass( 'initialized' ); - } - ); + var xhr = $.ajax( { + url: apiUrl, + data: { + 'original': originalId, + 'translation': translationId, + 'nonce': nonce + }, + dataType: 'json', + cache: false, + } ); - xhr.fail( - function() { - $container.find( '.suggestions__loading-indicator' ).remove(); + xhr.done( function( response ) { + $container.find( '.suggestions__loading-indicator' ).remove(); + if ( response.success ) { + $container.append( response.data ); + storeTheSuggestionInTheCache( type, originalId, response.data ); + removeNoSuggestionsMessage( $container ); + copyTranslationMemoryToSidebarTab( $container ); + } else { $container.append( $( '', { 'text': 'Error while loading suggestions.' } ) ); - $container.addClass( 'initialized' ); } - ); + $container.addClass( 'initialized' ); + } ); - xhr.always( - function() { - $container.removeClass( 'fetching' ); - } - ); + xhr.fail( function() { + $container.find( '.suggestions__loading-indicator' ).remove(); + $container.append( $( '', { 'text': 'Error while loading suggestions.' } ) ); + $container.addClass( 'initialized' ); + } ); + + xhr.always( function() { + $container.removeClass( 'fetching' ); + } ); } /** @@ -118,12 +109,12 @@ */ function getSuggestionsForTheFirstRow() { var firstEditor = $( '#translations' ).find( '.editor' ).first(); - var row_id = firstEditor.closest( 'tr' ).attr( 'row' ); + var row_id = firstEditor.closest( 'tr' ).attr( 'row' ); if ( ! row_id ) { return; } - firstEditor.row_id = row_id; - firstEditor.original_id = $gp.editor.original_id_from_row_id( row_id ); + firstEditor.row_id = row_id; + firstEditor.original_id = $gp.editor.original_id_from_row_id( row_id ); firstEditor.translation_id = $gp.editor.translation_id_from_row_id( row_id ); maybeFetchTranslationMemorySuggestions( firstEditor ); maybeFetchOpenAISuggestions( firstEditor ); @@ -197,14 +188,14 @@ add_amount_to_others_tab = function ( sidebarTab, data, originalId ) { let elements = 0; - if ( data ? .['helper-history-' + originalId] ) { + if ( data?.['helper-history-' + originalId] ) { elements += data['helper-history-' + originalId].count; } - if ( data ? .['helper-other-locales-' + originalId] ) { + if ( data?.['helper-other-locales-' + originalId] ) { elements += data['helper-other-locales-' + originalId].count; } - var editor = $( '[data-tab="' + sidebarTab + '"]' ).closest( '.editor' ); - var TMcontainer = editor.find( '.suggestions__translation-memory' ); + var editor = $('[data-tab="' + sidebarTab + '"]').closest( '.editor' ); + var TMcontainer = editor.find( '.suggestions__translation-memory' ); var elementsInTM = 0; if ( TMcontainer.length ) { elementsInTM += TMcontainer.find( '.translation-suggestion.with-tooltip.translation' ).length; @@ -212,10 +203,10 @@ elementsInTM += TMcontainer.find( '.translation-suggestion.with-tooltip.openai' ).length; } elements += elementsInTM; - $( '#summary-translation-memory-' + originalId ).html( 'Translation Memory (' + elementsInTM + ')' ); + $( '#summary-translation-memory-' + originalId ).html('Translation Memory (' + elementsInTM + ')'); let content = 'Others (' + elements + ')'; - $( '[data-tab="' + sidebarTab + '"]' ).html( content ); + $('[data-tab="' + sidebarTab + '"]').html( content ); } /** @@ -226,16 +217,16 @@ * @return {void} */ function copyTranslationMemoryToSidebarTab( $container ){ - var editor = $container.closest( '.editor' ); - var divSidebarWithDiscussion = editor.find( '.meta.discussion' ).first(); - var divId = divSidebarWithDiscussion.attr( 'data-row-id' ); - var TMcontainer = editor.find( '.suggestions__translation-memory' ); - if ( ! TMcontainer.length ) { + var editor = $container.closest( '.editor' ); + var divSidebarWithDiscussion = editor.find( '.meta.discussion' ).first(); + var divId = divSidebarWithDiscussion.attr( 'data-row-id' ); + var TMcontainer = editor.find( '.suggestions__translation-memory' ); + if ( !TMcontainer.length ) { return; } $( '#sidebar-div-others-translation-memory-content-' + divId ).html( TMcontainer.html() ); - add_amount_to_others_tab( 'sidebar-tab-others-' + divId, window.translationHelpersCache ? .[ divId ], divId ); + add_amount_to_others_tab('sidebar-tab-others-' + divId, window.translationHelpersCache?.[ divId ], divId); } /** @@ -276,7 +267,7 @@ */ function maybeFetchTranslationMemorySuggestions( editor ) { var $container = editor.find( '.suggestions__translation-memory' ); - if ( ! $container.length ) { + if ( !$container.length ) { return; } @@ -284,15 +275,15 @@ return; } - if ( ! editor.find( 'translation-suggestion.with-tooltip.translation' ).first() ) { + if ( !editor.find('translation-suggestion.with-tooltip.translation').first() ) { return; } $container.addClass( 'fetching' ); - var originalId = editor.original_id; + var originalId = editor.original_id; var translationId = editor.translation_id; - var nonce = $container.data( 'nonce' ); + var nonce = $container.data( 'nonce' ); fetchSuggestions( $container, window.WPORG_TRANSLATION_MEMORY_API_URL, originalId, translationId, nonce, 'TM' ); } @@ -331,15 +322,15 @@ */ function maybeFetchExternalSuggestions( editor, type, getExternalSuggestions, apiUrl ) { var $container = editor.find( '.suggestions__translation-memory' ); - if ( ! $container.length ) { + if ( !$container.length ) { return; } if ( true !== getExternalSuggestions ) { return; } - var originalId = editor.original_id; + var originalId = editor.original_id; var translationId = editor.translation_id; - var nonce = $container.data( 'nonce' ); + var nonce = $container.data( 'nonce' ); fetchSuggestions( $container, apiUrl, originalId, translationId, nonce, type ); } @@ -363,9 +354,9 @@ $container.addClass( 'fetching' ); - var originalId = editor.original_id; + var originalId = editor.original_id; var translationId = editor.translation_id; - var nonce = $container.data( 'nonce' ); + var nonce = $container.data( 'nonce' ); fetchSuggestions( $container, window.WPORG_OTHER_LANGUAGES_API_URL, originalId , translationId, nonce, 'OL' ); } @@ -396,21 +387,19 @@ * @return {void} */ function removeNoSuggestionsDuplicateMessage( $container ) { - var $html = $( $container ); - var $paragraphs = $html.find( 'p' ); + var $html = $($container); + var $paragraphs = $html.find('p'); var uniqueParagraphs = []; - $paragraphs.each( - function() { - var paragraphText = $( this ).text().trim(); + $paragraphs.each(function() { + var paragraphText = $(this).text().trim(); - if (uniqueParagraphs.indexOf( paragraphText ) === -1) { - uniqueParagraphs.push( paragraphText ); - } else { - $( this ).remove(); - } + if (uniqueParagraphs.indexOf(paragraphText) === -1) { + uniqueParagraphs.push(paragraphText); + } else { + $(this).remove(); } - ); + }); } /** @@ -423,19 +412,17 @@ function deleteSuggestionFromTM( event ) { event.preventDefault(); event.stopImmediatePropagation(); - if ( ! confirm( 'Are you sure you want to delete this translation from the Translation Memory?' )) { + if ( ! confirm( 'Are you sure you want to delete this translation from the Translation Memory?' ) ) { return; } - var editor = $gp.editor.current; + var editor = $gp.editor.current; var container = editor.find( '.suggestions__translation-memory' ); if ( ! container.length ) { return; } - var row = $( this ).closest( '.translation-suggestion' ); - var deleteButton = event.target; - var rows = editor.find( '.translation-suggestion.with-tooltip.translation' ); - var source = { + var deleteButton = event.target; + var source = { 'source': deleteButton.dataset.sourceSingular, 'source_plural': deleteButton.dataset.sourcePlural, 'source_context': deleteButton.dataset.sourceContext, @@ -444,43 +431,37 @@ 'translation': deleteButton.dataset.translation, 'translation_plural': deleteButton.dataset.translationPlural, }; - var originalId = editor.original_id; - var nonce = container.data( 'nonce' ); - - var filteredRows = rows.filter( - function() { - var translationRaw = $( this ).find( '.translation-suggestion__translation-raw' ).text().trim(); - var score = $( this ).find( '.translation-suggestion__score' ).text().trim(); - return translationRaw === deleteButton.dataset.translation && score === "100%"; - } - ); + var originalId = editor.original_id; + var nonce = container.data( 'nonce' ); - filteredRows.find( '.delete-suggestion' ).prop( 'disabled', true ); - $.ajax( - { - type: 'POST', - url: window.WPORG_TRANSLATION_MEMORY_API_DELETE_URL, - data: { - 'source': source, - 'translation': translation, - 'originalId' : originalId, - 'nonce': nonce - }, - dataType: 'json', - cache: false, - success: function(result) { - if ( true === result.success ) { - filteredRows.each( - function() { - $( this ).remove(); - } - ); - } + var rows = editor.find( '.translation-suggestion.with-tooltip.translation' ); + var filteredRows = rows.filter( function() { + var translationRaw = $( this ).find( '.translation-suggestion__translation-raw' ).text().trim(); + var score = $( this ).find( '.translation-suggestion__score' ).text().trim(); + return translationRaw === deleteButton.dataset.translation && score === "100%"; + }); - } + filteredRows.find( '.delete-suggestion' ).prop( 'disabled', true ); + $.ajax( { + type: 'POST', + url: window.WPORG_TRANSLATION_MEMORY_API_DELETE_URL, + data: { + 'source': source, + 'translation': translation, + 'originalId' : originalId, + 'nonce': nonce }, - 100 - ); + dataType: 'json', + cache: false, + success: function( result ) { + if( true === result.success ) { + filteredRows.each( function() { + $( this ).remove(); + }); + } + + } + }, 100 ); } function copySuggestion( event ) { @@ -488,8 +469,8 @@ return; } - var $el = $( this ).closest( '.translation-suggestion' ); - var $translation = $el.find( '.translation-suggestion__translation-raw' ); + var $el = $( this ).closest( '.translation-suggestion' ); + var $translation = $el.find( '.translation-suggestion__translation-raw'); if ( ! $translation.length ) { return; } @@ -542,11 +523,11 @@ maybeFetchOpenAISuggestions( $gp.editor.current ); maybeFetchDeeplSuggestions( $gp.editor.current ); maybeFetchOtherLanguageSuggestions( $gp.editor.current ); - var nextEditor = $gp.editor.current.nextAll( 'tr.editor' ).first(); + var nextEditor = $gp.editor.current.nextAll('tr.editor' ).first(); if ( nextEditor.length ) { - var row_id = nextEditor.closest( 'tr' ).attr( 'row' ); - nextEditor.row_id = row_id; - nextEditor.original_id = $gp.editor.original_id_from_row_id( row_id ); + var row_id = nextEditor.closest( 'tr' ).attr( 'row' ); + nextEditor.row_id = row_id; + nextEditor.original_id = $gp.editor.original_id_from_row_id( row_id ); nextEditor.translation_id = $gp.editor.translation_id_from_row_id( row_id ); maybeFetchTranslationMemorySuggestions( nextEditor ); maybeFetchOpenAISuggestions( nextEditor ); @@ -564,11 +545,9 @@ .on( 'click', '.translation-suggestion .delete-suggestion', deleteSuggestionFromTM ) .on( 'click', '.translation-suggestion', copySuggestion ) .on( 'click', '.translation-suggestion', addSuggestion ); - $( document ).ready( - function() { - getSuggestionsForTheFirstRow(); - } - ); + $( document ).ready( function() { + getSuggestionsForTheFirstRow(); + }); }; })( $gp.editor.install_hooks ); @@ -584,23 +563,21 @@ return; } externalSuggestion.suggestion_source = $row.data( 'suggestion-source' ) == 'translation' ? 'tm' : $row.data( 'suggestion-source' ); - externalSuggestion.translation = $row.find( '.translation-suggestion__translation' ).text(); + externalSuggestion.translation = $row.find( '.translation-suggestion__translation' ).text(); } - // Prefilter ajax requests to add external translations used to the request. - $.ajaxPrefilter( - function ( options ) { - const isSuggestionUsed = Object.keys( externalSuggestion ).length > 0 ? true : false; + //Prefilter ajax requests to add external translations used to the request. + $.ajaxPrefilter( function ( options ) { + const isSuggestionUsed = Object.keys( externalSuggestion ).length > 0 ? true : false; - if ( ! externalSuggestion || ! isSuggestionUsed ) { - return; - } - if ( 'POST' === options.type && $gp_editor_options.url === options.url ) { - options.data += '&externalTranslationSource=' + encodeURIComponent( externalSuggestion.suggestion_source ); - options.data += '&externalTranslationUsed=' + encodeURIComponent( externalSuggestion.translation ); - externalSuggestion = {}; - } + if ( ! externalSuggestion || ! isSuggestionUsed ) { + return; + } + if ( 'POST' === options.type && $gp_editor_options.url === options.url ) { + options.data += '&externalTranslationSource=' + encodeURIComponent( externalSuggestion.suggestion_source ); + options.data += '&externalTranslationUsed=' + encodeURIComponent( externalSuggestion.translation ); + externalSuggestion = {}; } - ); + }); })( jQuery ); From d05998024379c536cf77537627630edcdea5d867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Amieiro?= <1667814+amieiro@users.noreply.github.com> Date: Fri, 23 Aug 2024 11:37:50 +0200 Subject: [PATCH 7/8] Add the plural in a Translation_Memory_Client::query call --- .../inc/routes/class-translation-memory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php index 37cbb9ffc9..117bbe416e 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php @@ -378,7 +378,7 @@ private function is_TM_translation_100_accurate( $project_path, $locale, $set_sl return false; } - $suggestions = Translation_Memory_Client::query( $original->singular, $locale ); + $suggestions = Translation_Memory_Client::query( $original->singular, $original->plural, $locale ); if ( is_wp_error( $suggestions ) ) { return false; } From fdc3dc6f00a0c615e76330ccfdcf51601f949aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Amieiro?= <1667814+amieiro@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:00:33 +0100 Subject: [PATCH 8/8] Lint --- .../templates/style.css | 2 +- .../inc/class-translation-memory-client.php | 86 +++++++++---------- .../inc/routes/class-translation-memory.php | 2 - .../translation-memory-suggestions.php | 6 +- 4 files changed, 44 insertions(+), 52 deletions(-) diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/templates/style.css b/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/templates/style.css index c1d6490048..2c6951ffca 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/templates/style.css +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-customizations/templates/style.css @@ -3352,4 +3352,4 @@ ul.other-locales li { max-width: 100%; float: none; } -} +} \ No newline at end of file diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-translation-memory-client.php b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-translation-memory-client.php index c08a2048f6..63bc01f6b8 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-translation-memory-client.php +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/class-translation-memory-client.php @@ -13,7 +13,7 @@ class Translation_Memory_Client { - const API_ENDPOINT = 'https://translate.wordpress.com/api/tm/'; + const API_ENDPOINT = 'https://translate.wordpress.com/api/tm/'; const API_BULK_ENDPOINT = 'https://translate.wordpress.com/api/tm/-bulk'; /** @@ -23,7 +23,7 @@ class Translation_Memory_Client { * @return true|\WP_Error True on success, WP_Error on failure. */ public static function update( array $translations ) { - $requests = array(); + $requests = []; foreach ( $translations as $original_id => $translation_id ) { $translation = GP::$translation->get( $translation_id ); @@ -41,36 +41,34 @@ public static function update( array $translations ) { $locale .= '_' . $translation_set->slug; } - $requests[] = array( + $requests[] = [ 'source' => $original->fields(), - 'translations' => array( - array( + 'translations' => [ + [ 'singular' => $translation->translation_0, 'plural' => $translation->translation_1, 'locale' => $locale, - ), - ), - ); + ], + ], + ]; } if ( ! $requests ) { return new WP_Error( 'no_translations' ); } - $body = wp_json_encode( - array( - 'token' => WPCOM_TM_TOKEN, - 'requests' => $requests, - ) - ); + $body = wp_json_encode( [ + 'token' => WPCOM_TM_TOKEN, + 'requests' => $requests, + ] ); $request = wp_remote_post( self::API_BULK_ENDPOINT, - array( + [ 'timeout' => 10, 'user-agent' => 'WordPress.org Translate', 'body' => $body, - ) + ] ); if ( is_wp_error( $request ) ) { @@ -94,35 +92,31 @@ public static function update( array $translations ) { /** * Queries translation memory for a string. * - * @param string $text Singular text to search translations for. - * @param string $text_plural Plural text to search translations for. - * @param string $target_locale Locale to search in. - * @return array|\WP_Error List of suggestions on success, WP_Error on failure. + * @param string $text Singular text to search translations for. + * @param null|string $text_plural Plural text to search translations for. + * @param string $target_locale Locale to search in. + * + * @return array|\WP_Error List of suggestions on success, WP_Error on failure. */ - public static function query( string $text, string $text_plural, string $target_locale ) { + public static function query( string $text, $text_plural, string $target_locale ) { if ( ! defined( 'WPCOM_TM_TOKEN' ) ) { return new WP_Error( 'no_token' ); } - $url = add_query_arg( - urlencode_deep( - array( - 'text' => $text, - 'text_plural' => $text_plural, - 'target' => $target_locale, - 'token' => WPCOM_TM_TOKEN, - 'ts' => time(), - ) - ), - self::API_ENDPOINT - ); + $url = add_query_arg( urlencode_deep( [ + 'text' => $text, + 'text_plural' => $text_plural, + 'target' => $target_locale, + 'token' => WPCOM_TM_TOKEN, + 'ts' => time(), + ] ), self::API_ENDPOINT ); $request = wp_remote_get( $url, - array( + [ 'timeout' => 4, 'user-agent' => 'WordPress.org Translate', - ) + ] ); if ( is_wp_error( $request ) ) { @@ -141,20 +135,20 @@ public static function query( string $text, string $text_plural, string $target_ } if ( empty( $result['matches'] ) ) { - return array(); + return []; } - $suggestions = array(); + $suggestions = []; foreach ( $result['matches'] as $match ) { - $suggestions[] = array( + $suggestions[] = [ 'similarity_score' => $match['score'], 'source' => $match['source'], - 'source_plural' => $match['source_plural'], + 'source_plural' => $match['source_plural'], 'source_context' => $match['source_context'], 'translation' => $match['text'], 'translation_plural' => $match['text_plural'], 'diff' => ( 1 === $match['score'] ) ? null : self::diff( $text, $match['source'] ), - ); + ]; } return $suggestions; @@ -175,21 +169,21 @@ public static function delete( array $source, array $translation, string $locale if ( 'default' !== $set_slug ) { $locale .= '_' . $set_slug; } - $body = wp_json_encode( + $body = wp_json_encode( array( - 'token' => WPCOM_TM_TOKEN, - 'source' => $source, + 'token' => WPCOM_TM_TOKEN, + 'source' => $source, 'translation' => array( 'singular' => $translation['translation'], 'plural' => $translation['translation_plural'], 'locale' => $locale, - ), + ) ) ); $request = wp_remote_post( self::API_BULK_ENDPOINT, array( - 'method' => 'DELETE', + 'method' => 'DELETE', 'timeout' => 10, 'user-agent' => 'WordPress.org Translate', 'body' => $body, @@ -212,7 +206,7 @@ public static function delete( array $source, array $translation, string $locale * @return string HTML markup for the differences between the two texts. */ protected static function diff( $previous_text, $text ) { - $diff = new Text_Diff( 'auto', array( array( $text ), array( $previous_text ) ) ); + $diff = new Text_Diff( 'auto', [ [ $text ], [ $previous_text ] ] ); $renderer = new WP_Text_Diff_Renderer_inline(); return $renderer->render( $diff ); diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php index 117bbe416e..7837ebbccc 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/inc/routes/class-translation-memory.php @@ -5,10 +5,8 @@ use GP; use GP_Locales; use GP_Route; -use GP_Translation; use WordPressdotorg\GlotPress\TranslationSuggestions\Translation_Memory_Client; use WP_User; -use function cli\err; use const WordPressdotorg\GlotPress\TranslationSuggestions\PLUGIN_DIR; class Translation_Memory extends GP_Route { diff --git a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/templates/translation-memory-suggestions.php b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/templates/translation-memory-suggestions.php index 1da974a673..f75f7681ea 100644 --- a/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/templates/translation-memory-suggestions.php +++ b/wordpress.org/public_html/wp-content/plugins/wporg-gp-translation-suggestions/templates/translation-memory-suggestions.php @@ -25,9 +25,9 @@ echo ''; - if ( $is_user_a_gte_for_locale && 1 == $suggestion['similarity_score'] ) { - echo ''; - } + if ( $is_user_a_gte_for_locale && 1 == $suggestion['similarity_score'] ) { + echo ''; + } echo ''; echo ''; echo '';