find( 'body text' ) as $element ) { if ( in_array( $element->parent->tag, $edit_link_excluded ) || in_array( $element->parent->tag, $node_text_excluded ) ) { continue; } $text = $element->innertext; if ( empty( trim( $text ) ) ) { continue; } // Manage non breaking space $text = str_replace( array( ' ', html_entity_decode( ' ' ) ), array( ' ', ' ' ), $text ); /** * Get spaces before and after text */ $temp = array(); $spaces_before = ''; $spaces_after = ''; preg_match( '/^(\s*).*/', $text, $temp ); if ( ! empty( $temp[1] ) ) { $spaces_before = $temp[1]; } preg_match( '/.*(\s*)$/U', $text, $temp ); if ( ! empty( $temp[1] ) ) { $spaces_after = $temp[1]; } $text = wplng_text_esc( $text ); $translated = ''; if ( wplng_text_is_translatable( $text ) ) { foreach ( $args['translations'] as $translation ) { if ( $text === $translation['source'] ) { $translated = $translation['translation']; break; } } if ( '' === $translated ) { $innertext = 'innertext = $innertext; } else { $element->innertext = esc_html( $spaces_before . $translated . $spaces_after ); } } } /** * Create the html of message bar */ $number_of_texts = (int) $args['count_texts']; $numer_of_translated_texts = count( $args['translations'] ); // Calculate percentage $percentage = 0; if ( $number_of_texts > 0 ) { $percentage = (int) ( ( $numer_of_translated_texts / $number_of_texts ) * 100 ); } if ( $percentage < 1 ) { $percentage = 1; } // Make the HTML $html = '
'; $html .= '
'; $html .= ' '; $html .= ''; $html .= esc_html__( 'Translation in progress', 'wplingua' ); $html .= ''; $html .= ''; $html .= esc_html__( 'In progress: Translation and saving of new texts', 'wplingua' ); $html .= ''; $html .= ' - '; $html .= ''; $html .= esc_html( $percentage ); $html .= ''; $html .= ' %'; $html .= '
'; // End #wplng-translation-in-progress $html .= '
'; $html .= ' $max_chars_per_chunk ) { $text = function_exists( 'mb_substr' ) ? mb_substr( $text, 0, $max_chars_per_chunk, 'UTF-8' ) : substr( $text, 0, $max_chars_per_chunk ); $len = $max_chars_per_chunk; } // If adding this text would exceed either limit, flush current chunk. if ( count( $current_chunk ) >= $max_items_per_chunk || ( $current_chars + $len ) > $max_chars_per_chunk ) { if ( ! empty( $current_chunk ) ) { $texts_unknow_by_chunk[] = array( 'percentage' => (int) ( ( $numer_of_translated_texts / $number_of_texts ) * 100 ), 'texts' => $current_chunk, ); $current_chunk = array(); $current_chars = 0; } } $current_chunk[] = wplng_encryption_encrypt( $text ); $current_chars += $len; ++$numer_of_translated_texts; } // Push last chunk if any if ( ! empty( $current_chunk ) ) { $texts_unknow_by_chunk[] = array( 'percentage' => 99, 'texts' => $current_chunk, ); } /** * Make the reload URL */ $url_reload_query_arg = array( 'wplng-load' => 'translated', 'nocache' => (string) time() . (string) rand( 100, 999 ), ); if ( $args['mode'] !== 'vanilla' ) { $url_reload_query_arg['wplng-mode'] = $args['mode']; } $url_reload = add_query_arg( $url_reload_query_arg, $args['url_current'] ); // Ensure the reload URL is safe for JS: decode entities then use esc_url_raw (programmatic URL) $url_reload_for_js = html_entity_decode( $url_reload, ENT_QUOTES | ENT_HTML5, 'UTF-8' ); $url_reload_for_js = esc_url_raw( $url_reload_for_js ); /** * JS Script - Load in progress - Data */ $load_in_progress_data_js = array( 'urlAjax' => esc_url_raw( admin_url( 'admin-ajax.php' ) ), 'urlReload' => $url_reload_for_js, 'language' => esc_attr( $args['language_target'] ), 'chunks' => $texts_unknow_by_chunk, 'nonce' => wp_create_nonce( 'wplng_load_in_progress' ), ); $html .= ''; /** * JS Script - Load in progress - File */ $script_url = plugins_url() . '/wplingua/assets/js/load-in-progress.js'; $script_url .= '?ver=' . WPLNG_PLUGIN_VERSION; $html .= 'find( 'body' ) as $body ) { $body->innertext = $body->innertext . $html; } return $dom; } /** * AJAX handler for "load in progress" translations. * * Validates the current user capability and incoming POST data, requests * translations for the provided texts and returns a JSON response. On error * a JSON error response is sent and execution ends. * * Expected POST parameters: * - wplng_language (string) : target language id * - wplng_texts (array) : list of texts to translate * * Permissions: current user must have 'edit_posts'. * * @return void Sends JSON success or error and exits. */ function wplng_ajax_load_in_progress() { /** * Check authorizations */ if ( ! current_user_can( 'edit_posts' ) ) { wp_send_json_error( array( 'error_load_in_progress' => true, 'error_message' => 'Unauthorized user', ) ); return; } // Verify nonce sent from client if ( empty( $_POST['wplng_nonce'] ) || ! wp_verify_nonce( wp_unslash( $_POST['wplng_nonce'] ), 'wplng_load_in_progress' ) ) { wp_send_json_error( array( 'error_load_in_progress' => true, 'error_message' => 'Invalid nonce', ) ); return; } if ( ! wplng_api_feature_is_allow( 'detection' ) ) { wp_send_json_error( array( 'error_load_in_progress' => true, 'error_message' => 'Error detecting text', ) ); return; } /** * Check target language */ // Check if language is defined if ( empty( $_POST['wplng_language'] ) ) { wp_send_json_error( array( 'error_load_in_progress' => true, 'error_message' => 'Empty language', ) ); return; } $language_target = sanitize_text_field( wp_unslash( $_POST['wplng_language'] ) ); // Check if is a valid language ID if ( ! wplng_is_valid_language_id( $language_target ) ) { wp_send_json_error( array( 'error_load_in_progress' => true, 'error_message' => 'Invalid language', ) ); return; } // Check if languagd is allow if ( ! in_array( $language_target, wplng_get_languages_target_ids() ) ) { wp_send_json_error( array( 'error_load_in_progress' => true, 'error_message' => 'Unauthorized website language - ' . esc_attr( $language_target ), ) ); return; } /** * Check texts to translate */ if ( empty( $_POST['wplng_texts'] ) || ! is_array( $_POST['wplng_texts'] ) ) { wp_send_json_error( array( 'error_load_in_progress' => true, 'error_message' => 'Invalid texts data', ) ); return; } $texts_original_encrypted = wp_unslash( $_POST['wplng_texts'] ); $texts_original = array(); foreach ( $texts_original_encrypted as $text_encrypted ) { $text_decrypted = wplng_encryption_decrypt( $text_encrypted ); if ( $text_decrypted === '' ) { wp_send_json_error( array( 'error_load_in_progress' => true, 'error_message' => 'Texts decryption failed', ) ); return; } $texts_original[] = $text_decrypted; } /** * Setup $args and get translations */ $args = array( 'language_target' => $language_target ); wplng_args_setup( $args ); wplng_args_update_from_texts( $args, $texts_original ); /** * Basic translation check */ if ( empty( $args['translations'] ) ) { wp_send_json_error( array( 'error_load_in_progress' => true, 'error_message' => 'No translation returned', ) ); return; } /** * Setup translation array for AJAX response */ $translation_response = array(); foreach ( $args['translations'] as $translation ) { if ( ! isset( $translation['source'] ) || ! isset( $translation['translation'] ) ) { continue; } $translation_response[] = array( 'source' => $translation['source'], 'translation' => $translation['translation'], ); } wp_send_json_success( $translation_response ); }