PluginProbe
Translate and Go multilingual – Automatic AI translation – wpLingua / 2.14.3
Translate and Go multilingual – Automatic AI translation – wpLingua v2.14.3
2.16.7 2.16.6 2.16.5 2.16.4 2.16.3 2.16.2 2.16.1 2.16.0 2.15.2 2.15.1 2.15.0 2.14.3 2.14.2 2.14.1 2.14.0 2.13.1 2.13.0 2.12.3 2.12.2 2.12.1 trunk 1.0.3 1.0.4 1.0.5 1.1.0 All 112 releases
wplingua / inc / dom / load-progress.php

load-progress.php in Translate and Go multilingual – Automatic AI translation – wpLingua 2.14.3, at inc/dom/load-progress.php

452 lines 11.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // If this file is called directly, abort.
4 if ( ! defined( 'WPINC' ) ) {
5 die;
6 }
7
8
9 /**
10 * Modify dom for the "in progress" load mode
11 *
12 * @param object $dom
13 * @param array $args
14 * @return object
15 */
16 function wplng_dom_load_progress( $dom, $args ) {
17
18 wplng_args_setup( $args );
19
20 if ( $args['load'] !== 'progress'
21 || ! current_user_can( 'edit_posts' )
22 ) {
23 return $dom;
24 }
25
26 /**
27 * Add effect on unknow texts and translate know texts
28 */
29
30 $edit_link_excluded = wplng_data_excluded_editor_link();
31 $node_text_excluded = wplng_data_excluded_node_text();
32
33 foreach ( $dom->find( 'body text' ) as $element ) {
34
35 if ( in_array( $element->parent->tag, $edit_link_excluded )
36 || in_array( $element->parent->tag, $node_text_excluded )
37 ) {
38 continue;
39 }
40
41 $text = $element->innertext;
42
43 if ( empty( trim( $text ) ) ) {
44 continue;
45 }
46
47 // Manage non breaking space
48 $text = str_replace(
49 array( '&nbsp;', html_entity_decode( '&nbsp;' ) ),
50 array( ' ', ' ' ),
51 $text
52 );
53
54 /**
55 * Get spaces before and after text
56 */
57
58 $temp = array();
59 $spaces_before = '';
60 $spaces_after = '';
61
62 preg_match( '/^(\s*).*/', $text, $temp );
63 if ( ! empty( $temp[1] ) ) {
64 $spaces_before = $temp[1];
65 }
66
67 preg_match( '/.*(\s*)$/U', $text, $temp );
68 if ( ! empty( $temp[1] ) ) {
69 $spaces_after = $temp[1];
70 }
71
72 $text = wplng_text_esc( $text );
73 $translated = '';
74
75 if ( wplng_text_is_translatable( $text ) ) {
76
77 foreach ( $args['translations'] as $translation ) {
78 if ( $text === $translation['source'] ) {
79 $translated = $translation['translation'];
80 break;
81 }
82 }
83
84 if ( '' === $translated ) {
85
86 $innertext = '<span';
87 $innertext .= ' class="wplng-in-progress-text"';
88 $innertext .= ' title="' . esc_attr__( 'Translation in progress', 'wplingua' ) . '"';
89 $innertext .= '>';
90 $innertext .= esc_html( $spaces_before . $text . $spaces_after );
91 $innertext .= '</span>';
92
93 $element->innertext = $innertext;
94
95 } else {
96 $element->innertext = esc_html( $spaces_before . $translated . $spaces_after );
97 }
98 }
99 }
100
101 /**
102 * Create the html of message bar
103 */
104
105 $number_of_texts = (int) $args['count_texts'];
106 $numer_of_translated_texts = count( $args['translations'] );
107
108 // Calculate percentage
109
110 $percentage = 0;
111 if ( $number_of_texts > 0 ) {
112 $percentage = (int) ( ( $numer_of_translated_texts / $number_of_texts ) * 100 );
113 }
114
115 if ( $percentage < 1 ) {
116 $percentage = 1;
117 }
118
119 // Make the HTML
120
121 $html = '<div id="wplng-in-progress-container">';
122
123 $html .= '<div id="wplng-in-progress-message">';
124 $html .= '<span class="dashicons dashicons-update wplng-spin"></span> ';
125
126 $html .= '<span class="wplng-in-progress-text-mobile">';
127 $html .= esc_html__( 'Translation in progress', 'wplingua' );
128 $html .= '</span>';
129
130 $html .= '<span class="wplng-in-progress-text-desktop">';
131 $html .= esc_html__( 'In progress: Translation and saving of new texts', 'wplingua' );
132 $html .= '</span>';
133
134 $html .= ' - ';
135 $html .= '<span id="wplng-in-progress-percent">';
136 $html .= esc_html( $percentage );
137 $html .= '</span>';
138 $html .= ' %';
139 $html .= '</div>'; // End #wplng-translation-in-progress
140
141 $html .= '<div id="wplng-progress-bar">';
142 $html .= '<div';
143 $html .= ' id="wplng-progress-bar-value"';
144 $html .= ' style="width: ' . esc_attr( $percentage ) . '%"';
145 $html .= '>';
146 $html .= '</div>'; // End #wplng-progress-bar-value
147 $html .= '</div>'; // End #wplng-progress-bar
148
149 $html .= '<div id="wplng-in-progress-error" style="display: none;">';
150 $html .= '<span class="dashicons dashicons-info-outline"></span> ';
151
152 $html .= '<span class="wplng-in-progress-text-mobile">';
153 $html .= esc_html__( 'Error during translation.', 'wplingua' );
154 $html .= '</span>';
155
156 $html .= '<span class="wplng-in-progress-text-desktop">';
157 $html .= esc_html__( 'Error during translation. Check the browser console for more information.', 'wplingua' );
158 $html .= '</span>';
159
160 $html .= '<span';
161 $html .= ' id="wplng-in-progress-error-close"';
162 $html .= ' class="dashicons dashicons-no-alt"';
163 $html .= ' title="' . esc_attr__( 'Close', 'wplingua' ) . '"';
164 $html .= '></span>';
165
166 $html .= '</div>'; // End wplng-in-progress-error
167
168 $html .= '</div>'; // End #wplng-in-progress-container
169
170 /**
171 * Prepare the texts chunks
172 */
173
174 $texts_unknow_by_chunk = array();
175 $current_chunk = array();
176 $current_chars = 0;
177 $max_items_per_chunk = (int) ( WPLNG_MAX_TRANSLATIONS_STR / 2 );
178 $max_chars_per_chunk = (int) ( WPLNG_MAX_TRANSLATIONS_CHAR / 2 );
179
180 foreach ( $args['texts_unknow'] as $text_unknow ) {
181
182 $text = (string) $text_unknow;
183 $len = function_exists( 'mb_strlen' ) ? mb_strlen( $text, 'UTF-8' ) : strlen( $text );
184
185 // If a single item is longer than allowed, truncate it to fit the limit.
186 if ( $len > $max_chars_per_chunk ) {
187 $text = function_exists( 'mb_substr' ) ? mb_substr( $text, 0, $max_chars_per_chunk, 'UTF-8' ) : substr( $text, 0, $max_chars_per_chunk );
188 $len = $max_chars_per_chunk;
189 }
190
191 // If adding this text would exceed either limit, flush current chunk.
192 if ( count( $current_chunk ) >= $max_items_per_chunk || ( $current_chars + $len ) > $max_chars_per_chunk ) {
193 if ( ! empty( $current_chunk ) ) {
194 $texts_unknow_by_chunk[] = array(
195 'percentage' => (int) ( ( $numer_of_translated_texts / $number_of_texts ) * 100 ),
196 'texts' => $current_chunk,
197 );
198 $current_chunk = array();
199 $current_chars = 0;
200 }
201 }
202
203 $current_chunk[] = wplng_encryption_encrypt( $text );
204 $current_chars += $len;
205 ++$numer_of_translated_texts;
206 }
207
208 // Push last chunk if any
209 if ( ! empty( $current_chunk ) ) {
210 $texts_unknow_by_chunk[] = array(
211 'percentage' => 99,
212 'texts' => $current_chunk,
213 );
214 }
215
216 /**
217 * Make the reload URL
218 */
219
220 $url_reload_query_arg = array(
221 'wplng-load' => 'translated',
222 'nocache' => (string) time() . (string) rand( 100, 999 ),
223 );
224
225 if ( $args['mode'] !== 'vanilla' ) {
226 $url_reload_query_arg['wplng-mode'] = $args['mode'];
227 }
228
229 $url_reload = add_query_arg(
230 $url_reload_query_arg,
231 $args['url_current']
232 );
233
234 // Ensure the reload URL is safe for JS: decode entities then use esc_url_raw (programmatic URL)
235 $url_reload_for_js = html_entity_decode( $url_reload, ENT_QUOTES | ENT_HTML5, 'UTF-8' );
236 $url_reload_for_js = esc_url_raw( $url_reload_for_js );
237
238 /**
239 * JS Script - Load in progress - Data
240 */
241
242 $load_in_progress_data_js = array(
243 'urlAjax' => esc_url_raw( admin_url( 'admin-ajax.php' ) ),
244 'urlReload' => $url_reload_for_js,
245 'language' => esc_attr( $args['language_target'] ),
246 'chunks' => $texts_unknow_by_chunk,
247 'nonce' => wp_create_nonce( 'wplng_load_in_progress' ),
248 );
249
250 $html .= '<script id="wplingua-js-load-in-progress-data">';
251 $html .= 'let wplngLoadInProgressData = ' . wp_json_encode( $load_in_progress_data_js ) . ';';
252 $html .= '</script>';
253
254 /**
255 * JS Script - Load in progress - File
256 */
257
258 $script_url = plugins_url() . '/wplingua/assets/js/load-in-progress.js';
259 $script_url .= '?ver=' . WPLNG_PLUGIN_VERSION;
260
261 $html .= '<script';
262 $html .= ' type="text/javascript"';
263 $html .= ' src="' . esc_url( $script_url ) . '"';
264 $html .= ' id="wplingua-js-load-in-progress-script"';
265 $html .= '>';
266 $html .= '</script>';
267
268 /**
269 * Place the HTML in the end of body
270 */
271
272 foreach ( $dom->find( 'body' ) as $body ) {
273 $body->innertext = $body->innertext . $html;
274 }
275
276 return $dom;
277 }
278
279
280 /**
281 * AJAX handler for "load in progress" translations.
282 *
283 * Validates the current user capability and incoming POST data, requests
284 * translations for the provided texts and returns a JSON response. On error
285 * a JSON error response is sent and execution ends.
286 *
287 * Expected POST parameters:
288 * - wplng_language (string) : target language id
289 * - wplng_texts (array) : list of texts to translate
290 *
291 * Permissions: current user must have 'edit_posts'.
292 *
293 * @return void Sends JSON success or error and exits.
294 */
295 function wplng_ajax_load_in_progress() {
296
297 /**
298 * Check authorizations
299 */
300
301 if ( ! current_user_can( 'edit_posts' ) ) {
302 wp_send_json_error(
303 array(
304 'error_load_in_progress' => true,
305 'error_message' => 'Unauthorized user',
306 )
307 );
308 return;
309 }
310
311 // Verify nonce sent from client
312 if ( empty( $_POST['wplng_nonce'] )
313 || ! wp_verify_nonce( wp_unslash( $_POST['wplng_nonce'] ), 'wplng_load_in_progress' )
314 ) {
315 wp_send_json_error(
316 array(
317 'error_load_in_progress' => true,
318 'error_message' => 'Invalid nonce',
319 )
320 );
321 return;
322 }
323
324 if ( ! wplng_api_feature_is_allow( 'detection' ) ) {
325 wp_send_json_error(
326 array(
327 'error_load_in_progress' => true,
328 'error_message' => 'Error detecting text',
329 )
330 );
331 return;
332 }
333
334 /**
335 * Check target language
336 */
337
338 // Check if language is defined
339
340 if ( empty( $_POST['wplng_language'] ) ) {
341 wp_send_json_error(
342 array(
343 'error_load_in_progress' => true,
344 'error_message' => 'Empty language',
345 )
346 );
347 return;
348 }
349
350 $language_target = sanitize_text_field( wp_unslash( $_POST['wplng_language'] ) );
351
352 // Check if is a valid language ID
353
354 if ( ! wplng_is_valid_language_id( $language_target ) ) {
355 wp_send_json_error(
356 array(
357 'error_load_in_progress' => true,
358 'error_message' => 'Invalid language',
359 )
360 );
361 return;
362 }
363
364 // Check if languagd is allow
365
366 if ( ! in_array( $language_target, wplng_get_languages_target_ids() ) ) {
367 wp_send_json_error(
368 array(
369 'error_load_in_progress' => true,
370 'error_message' => 'Unauthorized website language - ' . esc_attr( $language_target ),
371 )
372 );
373 return;
374 }
375
376 /**
377 * Check texts to translate
378 */
379
380 if ( empty( $_POST['wplng_texts'] )
381 || ! is_array( $_POST['wplng_texts'] )
382 ) {
383 wp_send_json_error(
384 array(
385 'error_load_in_progress' => true,
386 'error_message' => 'Invalid texts data',
387 )
388 );
389 return;
390 }
391
392 $texts_original_encrypted = wp_unslash( $_POST['wplng_texts'] );
393 $texts_original = array();
394
395 foreach ( $texts_original_encrypted as $text_encrypted ) {
396 $text_decrypted = wplng_encryption_decrypt( $text_encrypted );
397
398 if ( $text_decrypted === '' ) {
399 wp_send_json_error(
400 array(
401 'error_load_in_progress' => true,
402 'error_message' => 'Texts decryption failed',
403 )
404 );
405 return;
406 }
407
408 $texts_original[] = $text_decrypted;
409 }
410
411 /**
412 * Setup $args and get translations
413 */
414
415 $args = array( 'language_target' => $language_target );
416 wplng_args_setup( $args );
417 wplng_args_update_from_texts( $args, $texts_original );
418
419 /**
420 * Basic translation check
421 */
422
423 if ( empty( $args['translations'] ) ) {
424 wp_send_json_error(
425 array(
426 'error_load_in_progress' => true,
427 'error_message' => 'No translation returned',
428 )
429 );
430 return;
431 }
432
433 /**
434 * Setup translation array for AJAX response
435 */
436
437 $translation_response = array();
438
439 foreach ( $args['translations'] as $translation ) {
440 if ( ! isset( $translation['source'] ) || ! isset( $translation['translation'] ) ) {
441 continue;
442 }
443
444 $translation_response[] = array(
445 'source' => $translation['source'],
446 'translation' => $translation['translation'],
447 );
448 }
449
450 wp_send_json_success( $translation_response );
451 }
452