PluginProbe
Translate and Go multilingual – Automatic AI translation – wpLingua / 2.14.2
Translate and Go multilingual – Automatic AI translation – wpLingua v2.14.2
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 / translation.php

translation.php in Translate and Go multilingual – Automatic AI translation – wpLingua 2.14.2, at inc/translation.php

647 lines 14.7 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 * Get the translated text from translations array
11 *
12 * @param string $text
13 * @param array $translations
14 * @return string
15 */
16 function wplng_get_translated_text_from_translations( $text, $translations ) {
17
18 if ( empty( trim( $text ) ) ) {
19 return $text;
20 }
21
22 // Manage non breaking space
23 $text = str_replace(
24 array( '&nbsp;', html_entity_decode( '&nbsp;' ) ),
25 array( ' ', ' ' ),
26 $text
27 );
28
29 /**
30 * Get spaces before and after text
31 */
32 $temp = array();
33 $spaces_before = '';
34 $spaces_after = '';
35
36 preg_match( '/^(\s*).*/', $text, $temp );
37 if ( ! empty( $temp[1] ) ) {
38 $spaces_before = $temp[1];
39 }
40
41 preg_match( '/(\s+)$/', $text, $temp );
42 if ( ! empty( $temp[1] ) ) {
43 $spaces_after = $temp[1];
44 }
45
46 $text = wplng_text_esc( $text );
47 $translated = $text;
48
49 foreach ( $translations as $translation ) {
50 if ( $text === $translation['source'] ) {
51 $translated = $translation['translation'];
52 break;
53 }
54 }
55
56 return $spaces_before . $translated . $spaces_after;
57 }
58
59
60 /**
61 * Get the count of published 'wplng_translation' posts.
62 *
63 * This function retrieves the number of posts of type 'wplng_translation'
64 * that are currently published on the site.
65 *
66 * @return int The number of published 'wplng_translation' posts.
67 */
68 function wplng_get_translation_count() {
69
70 global $wplng_translation_count;
71
72 if ( null !== $wplng_translation_count ) {
73 return $wplng_translation_count;
74 }
75
76 $count_posts = wp_count_posts( 'wplng_translation' );
77 $wplng_translation_count = (int) ( $count_posts->publish ?? 0 );
78
79 return $wplng_translation_count;
80 }
81
82
83 /**
84 * Get translation data from original text
85 *
86 * @param string $original
87 * @return array Translation data
88 */
89 function wplng_get_translation_saved_from_original( $original ) {
90
91 if ( empty( $original ) ) {
92 return false;
93 }
94
95 $args = array(
96 'post_type' => 'wplng_translation',
97 'posts_per_page' => -1,
98 'fields' => 'ids',
99 'meta_query' => array(
100 'relation' => 'AND',
101 array(
102 'key' => 'wplng_translation_md5',
103 'value' => md5( $original ),
104 'compare' => '=',
105 ),
106 array(
107 'key' => 'wplng_translation_original_language_id',
108 'value' => wplng_get_language_website_id(),
109 'compare' => '=',
110 ),
111 ),
112 );
113
114 $posts = get_posts( $args );
115
116 if ( empty( $posts ) ) {
117 return false;
118 }
119
120 foreach ( $posts as $post_id ) {
121
122 $meta = get_post_meta( $post_id );
123
124 if ( isset( $meta['wplng_translation_original'][0] )
125 && is_string( $meta['wplng_translation_original'][0] )
126 && $meta['wplng_translation_original'][0] === $original
127 ) {
128 return get_post( $post_id );
129 }
130 }
131
132 return false;
133 }
134
135
136 /**
137 * Get all saved translations from a wp_query for all languages
138 *
139 * @return array
140 */
141 function wplng_get_translations_from_query() {
142
143 $translations = array();
144
145 $args = array(
146 'post_type' => 'wplng_translation',
147 'posts_per_page' => -1,
148 'no_found_rows' => true,
149 'update_post_term_cache' => false,
150 'update_post_meta_cache' => false,
151 'cache_results' => false,
152 'fields' => 'ids', // Retrieve only post IDs for better performance
153 'meta_query' => array(
154 array(
155 'key' => 'wplng_translation_original_language_id',
156 'value' => wplng_get_language_website_id(),
157 'compare' => '=',
158 ),
159 ),
160 );
161
162 $post_ids = get_posts( $args );
163
164 if ( empty( $post_ids ) ) {
165 return array();
166 }
167
168 foreach ( $post_ids as $id ) {
169
170 $meta = get_post_meta( $id );
171
172 // Ensure 'wplng_translation_original' exists and is a valid string
173 if ( empty( $meta['wplng_translation_original'][0] )
174 || ! is_string( $meta['wplng_translation_original'][0] )
175 || trim( $meta['wplng_translation_original'][0] ) === ''
176 ) {
177 continue;
178 }
179
180 $source = wplng_text_esc( trim( $meta['wplng_translation_original'][0] ) );
181
182 $translation = array(
183 'source' => $source,
184 'post_id' => $id,
185 'review' => array(),
186 'translations' => array(),
187 );
188
189 // Ensure 'wplng_translation_translations' exists
190 if ( empty( $meta['wplng_translation_translations'][0] ) ) {
191 continue;
192 }
193
194 $translations_meta = json_decode( $meta['wplng_translation_translations'][0], true );
195
196 // Ensure JSON decoding was successful
197 if ( ! is_array( $translations_meta ) ) {
198 continue;
199 }
200
201 foreach ( $translations_meta as $translation_meta ) {
202 // Validate each translation entry
203 if ( empty( $translation_meta['language_id'] )
204 || ! wplng_is_valid_language_id( $translation_meta['language_id'] )
205 || (
206 isset( $translation_meta['translation'] )
207 && $translation_meta['translation'] === '[WPLNG_EMPTY]'
208 )
209 ) {
210 continue;
211 }
212
213 $language_id = sanitize_key( $translation_meta['language_id'] );
214
215 if ( isset( $translation_meta['translation'] )
216 && is_string( $translation_meta['translation'] )
217 ) {
218 $translated_text = wplng_text_esc( $translation_meta['translation'] );
219
220 $translation['translations'][ $language_id ] = $translated_text;
221 }
222
223 if ( isset( $translation_meta['status'] )
224 && is_int( $translation_meta['status'] )
225 ) {
226 $translation['review'][] = $language_id;
227 }
228 }
229
230 // Skip entries with no valid translations
231 if ( empty( $translation['translations'] ) ) {
232 continue;
233 }
234
235 $array_index = (string) mb_substr( $source, 0, 1 ) . (string) strlen( $source );
236
237 $translations[ $array_index ][] = $translation;
238 }
239
240 // Cache translations as a persistent option
241 update_option( 'wplng_cached_translations', $translations, false );
242
243 return $translations;
244 }
245
246
247 /**
248 * Save a translation
249 *
250 * @param string $language_id
251 * @param string $original
252 * @param array $translation
253 * @return int|false Post ID or false on failure
254 */
255 function wplng_save_translation_new( $language_id, $original, $translation ) {
256
257 $translation = str_replace( '\\', '', $translation );
258
259 /**
260 * Make the title
261 */
262
263 $tite_max_length = 100;
264 $title = mb_substr( $original, 0, $tite_max_length );
265 $title = wplng_text_esc_displayed( $title );
266 $title = wp_encode_emoji( $title );
267 if ( strlen( $original ) > $tite_max_length ) {
268 $title .= __( '...', 'wplingua' );
269 }
270
271 /**
272 * Create the post and get this ID
273 */
274
275 $new_post_id = wp_insert_post(
276 array(
277 'post_title' => esc_html( $title ),
278 'post_type' => 'wplng_translation',
279 'post_status' => 'publish',
280 'post_name' => sanitize_title(
281 'wplingua-translation-' . md5( $title ) . '-' . $title
282 ),
283 )
284 );
285
286 if ( is_wp_error( $new_post_id ) || empty( $new_post_id ) ) {
287 return false;
288 }
289
290 /**
291 * Make $translation_meta
292 */
293
294 $languages_target = wplng_get_languages_target_ids();
295 $translation_meta = array();
296
297 foreach ( $languages_target as $target_language ) {
298
299 if ( $target_language === $language_id ) {
300 $translation_meta[] = array(
301 'language_id' => $target_language,
302 'translation' => esc_html( $translation ),
303 'status' => 'generated',
304 );
305 } else {
306 $translation_meta[] = array(
307 'language_id' => $target_language,
308 'translation' => '[WPLNG_EMPTY]',
309 'status' => 'ungenerated',
310 );
311 }
312 }
313
314 /**
315 * Get the URL where the translation was discovered
316 */
317
318 $discovery_url = wplng_get_url_original();
319 $discovery_url = wp_make_link_relative( $discovery_url );
320 $discovery_url = remove_query_arg(
321 array( 'wplng-mode', 'wplng-load', 'nocache' ),
322 $discovery_url
323 );
324
325 /**
326 * Save meta: Discovered URL
327 */
328
329 $meta_return = add_post_meta(
330 $new_post_id,
331 'wplng_translation_discovery_url',
332 $discovery_url
333 );
334
335 if ( false === $meta_return ) {
336 wp_delete_post( $new_post_id, true );
337 return false;
338 }
339
340 /**
341 * Save meta: original language ID
342 */
343
344 $meta_return = add_post_meta(
345 $new_post_id,
346 'wplng_translation_original_language_id',
347 wplng_get_language_website_id()
348 );
349
350 if ( false === $meta_return ) {
351 wp_delete_post( $new_post_id, true );
352 return false;
353 }
354
355 /**
356 * Save meta: original text MD5
357 */
358
359 $meta_return = add_post_meta(
360 $new_post_id,
361 'wplng_translation_md5',
362 md5( $original )
363 );
364
365 if ( false === $meta_return ) {
366 wp_delete_post( $new_post_id, true );
367 return false;
368 }
369
370 /**
371 * Save meta: original text
372 */
373
374 $meta_return = add_post_meta(
375 $new_post_id,
376 'wplng_translation_original',
377 $original
378 );
379
380 if ( false === $meta_return ) {
381
382 // Try to save it with encoded emoji
383 $original = wp_encode_emoji( $original );
384
385 $meta_return = add_post_meta(
386 $new_post_id,
387 'wplng_translation_original',
388 $original
389 );
390
391 if ( false === $meta_return ) {
392 wp_delete_post( $new_post_id, true );
393 return false;
394 }
395 }
396
397 /**
398 * Save meta: Translation array as JSON
399 */
400
401 $meta_return = add_post_meta(
402 $new_post_id,
403 'wplng_translation_translations',
404 wp_json_encode(
405 $translation_meta,
406 JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
407 )
408 );
409
410 if ( false === $meta_return ) {
411
412 // Try to save it with encoded emoji
413 foreach ( $translation_meta as $key => $translation ) {
414
415 if ( empty( $translation['translation'] )
416 || '[WPLNG_EMPTY]' === $translation['translation']
417 ) {
418 continue;
419 }
420
421 $translation_meta[ $key ]['translation'] = wp_encode_emoji( $translation['translation'] );
422 }
423
424 $meta_return = add_post_meta(
425 $new_post_id,
426 'wplng_translation_translations',
427 wp_json_encode(
428 $translation_meta,
429 JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
430 )
431 );
432
433 if ( false === $meta_return ) {
434 wp_delete_post( $new_post_id, true );
435 return false;
436 }
437 }
438
439 return $new_post_id;
440 }
441
442
443 /**
444 * Update a translation
445 *
446 * @param object $post
447 * @param string $language_id
448 * @param array $translation
449 * @return int|false Post ID, false on failure
450 */
451 function wplng_update_translation( $post, $language_id, $translation ) {
452
453 $translation = str_replace( '\\', '', $translation );
454 $meta = get_post_meta( $post->ID );
455 $languages_target = wplng_get_languages_target_ids();
456 $website_language = wplng_get_language_website_id();
457
458 $translation_meta = ( empty( $meta['wplng_translation_translations'][0] ) )
459 ? array() :
460 json_decode( $meta['wplng_translation_translations'][0], true );
461
462 $original_language_id_meta = ( empty( $meta['wplng_translation_original_language_id'][0] ) )
463 ? wplng_get_language_website_id()
464 : $meta['wplng_translation_original_language_id'][0];
465
466 // If translation found is not valid
467 if ( empty( $translation_meta )
468 || $website_language !== $original_language_id_meta
469 ) {
470
471 /**
472 * $original_language_id_meta must be the same as in option page
473 */
474
475 $meta_return = update_post_meta(
476 $post->ID,
477 'wplng_translation_original_language_id',
478 $website_language
479 );
480
481 if ( false === $meta_return ) {
482 return false;
483 }
484
485 /**
486 * Make $translation_meta
487 */
488
489 $translation_meta = array();
490 foreach ( $languages_target as $key => $target_language ) {
491
492 if ( $target_language === $language_id && $translation !== '[WPLNG_EMPTY]' ) {
493 $translation_meta[] = array(
494 'language_id' => $target_language,
495 'translation' => esc_html( $translation ),
496 'status' => 'generated',
497 );
498 } else {
499 $translation_meta[] = array(
500 'language_id' => $target_language,
501 'translation' => '[WPLNG_EMPTY]',
502 'status' => 'ungenerated',
503 );
504 }
505 }
506 } else { // Translation is valid
507
508 // Set or update new translation
509 $translation_already_in = false;
510
511 foreach ( $translation_meta as $key => $translation_e ) {
512 if ( $translation_e['language_id'] === $language_id ) {
513 $translation_already_in = true;
514 $translation_meta[ $key ] = array(
515 'language_id' => $language_id,
516 'translation' => esc_html( $translation ),
517 'status' => 'generated',
518 );
519 break;
520 }
521 }
522
523 if ( ! $translation_already_in ) {
524 $translation_meta[] = array(
525 'language_id' => $language_id,
526 'translation' => esc_html( $translation ),
527 'status' => 'generated',
528 );
529 }
530 }
531
532 /**
533 * Update the translations post meta
534 */
535
536 $meta_return = update_post_meta(
537 $post->ID,
538 'wplng_translation_translations',
539 wp_json_encode(
540 $translation_meta,
541 JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
542 )
543 );
544
545 if ( false === $meta_return ) {
546
547 // Try to save it with encoded emoji
548 foreach ( $translation_meta as $key => $translation ) {
549
550 if ( empty( $translation['translation'] )
551 || '[WPLNG_EMPTY]' === $translation['translation']
552 ) {
553 continue;
554 }
555
556 $translation_meta[ $key ]['translation'] = wp_encode_emoji( $translation['translation'] );
557 }
558
559 $meta_return = update_post_meta(
560 $post->ID,
561 'wplng_translation_translations',
562 wp_json_encode(
563 $translation_meta,
564 JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
565 )
566 );
567
568 if ( false === $meta_return ) {
569 return false;
570 }
571 }
572
573 return $post->ID;
574 }
575
576
577 /**
578 * Save a list of translations
579 *
580 * @param array $translations
581 * @param string $language_target_id
582 * @return array $translations with post IDs
583 */
584 function wplng_save_translations( $translations, $language_target_id ) {
585
586 if ( empty( $translations ) || ! is_array( $translations ) ) {
587 return array();
588 }
589
590 foreach ( $translations as $key => $translation ) {
591
592 if (
593 ! isset( $translation['source'] ) // Original text
594 || ! isset( $translation['translation'] ) // Translater text
595 ) {
596 continue;
597 }
598
599 $translations[ $key ]['post_id'] = wplng_save_translation(
600 $language_target_id,
601 $translation['source'],
602 $translation['translation'],
603 false
604 );
605 }
606
607 wplng_clear_translations_cache();
608
609 return $translations;
610 }
611
612
613 /**
614 * Save translation
615 *
616 * @param string $target_language_id
617 * @param string $original
618 * @param array $translation
619 * @return array $translation with post ID
620 */
621 function wplng_save_translation( $target_language_id, $original, $translation, $clear_cache = true ) {
622
623 $saved_translation = wplng_get_translation_saved_from_original( $original );
624
625 if ( empty( $saved_translation ) ) {
626 // Create new translation post
627 $result = wplng_save_translation_new(
628 $target_language_id,
629 $original,
630 $translation
631 );
632 } else {
633 // Update the translation post
634 $result = wplng_update_translation(
635 $saved_translation,
636 $target_language_id,
637 $translation
638 );
639 }
640
641 if ( $clear_cache ) {
642 wplng_clear_translations_cache();
643 }
644
645 return $result;
646 }
647