PluginProbe
Translate and Go multilingual – Automatic AI translation – wpLingua / 2.16.6
Translate and Go multilingual – Automatic AI translation – wpLingua v2.16.6
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 1.1.1 All 111 releases
wplingua / inc / translation.php

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

666 lines 15.0 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 for all languages from cache or wp_query
138 *
139 * @return array
140 */
141 function wplng_get_translations() {
142
143 $translations = get_option( 'wplng_cached_translations' );
144
145 if ( empty( $translations )
146 || ! is_array( $translations )
147 ) {
148 $translations = wplng_get_translations_from_query();
149 }
150
151 return $translations;
152 }
153
154
155 /**
156 * Get all saved translations from a wp_query for all languages
157 *
158 * @return array
159 */
160 function wplng_get_translations_from_query() {
161
162 $translations = array();
163
164 $args = array(
165 'post_type' => 'wplng_translation',
166 'posts_per_page' => -1,
167 'no_found_rows' => true,
168 'update_post_term_cache' => false,
169 'update_post_meta_cache' => false,
170 'cache_results' => false,
171 'fields' => 'ids', // Retrieve only post IDs for better performance
172 'meta_query' => array(
173 array(
174 'key' => 'wplng_translation_original_language_id',
175 'value' => wplng_get_language_website_id(),
176 'compare' => '=',
177 ),
178 ),
179 );
180
181 $post_ids = get_posts( $args );
182
183 if ( empty( $post_ids ) ) {
184 return array();
185 }
186
187 foreach ( $post_ids as $id ) {
188
189 $meta = get_post_meta( $id );
190
191 // Ensure 'wplng_translation_original' exists and is a valid string
192 if ( empty( $meta['wplng_translation_original'][0] )
193 || ! is_string( $meta['wplng_translation_original'][0] )
194 || trim( $meta['wplng_translation_original'][0] ) === ''
195 ) {
196 continue;
197 }
198
199 $source = wplng_text_esc( trim( $meta['wplng_translation_original'][0] ) );
200
201 $translation = array(
202 'source' => $source,
203 'post_id' => $id,
204 'review' => array(),
205 'translations' => array(),
206 );
207
208 // Ensure 'wplng_translation_translations' exists
209 if ( empty( $meta['wplng_translation_translations'][0] ) ) {
210 continue;
211 }
212
213 $translations_meta = json_decode( $meta['wplng_translation_translations'][0], true );
214
215 // Ensure JSON decoding was successful
216 if ( ! is_array( $translations_meta ) ) {
217 continue;
218 }
219
220 foreach ( $translations_meta as $translation_meta ) {
221 // Validate each translation entry
222 if ( empty( $translation_meta['language_id'] )
223 || ! wplng_is_valid_language_id( $translation_meta['language_id'] )
224 || (
225 isset( $translation_meta['translation'] )
226 && $translation_meta['translation'] === '[WPLNG_EMPTY]'
227 )
228 ) {
229 continue;
230 }
231
232 $language_id = sanitize_key( $translation_meta['language_id'] );
233
234 if ( isset( $translation_meta['translation'] )
235 && is_string( $translation_meta['translation'] )
236 ) {
237 $translated_text = wplng_text_esc( $translation_meta['translation'] );
238
239 $translation['translations'][ $language_id ] = $translated_text;
240 }
241
242 if ( isset( $translation_meta['status'] )
243 && is_int( $translation_meta['status'] )
244 ) {
245 $translation['review'][] = $language_id;
246 }
247 }
248
249 // Skip entries with no valid translations
250 if ( empty( $translation['translations'] ) ) {
251 continue;
252 }
253
254 $array_index = (string) mb_substr( $source, 0, 1 ) . (string) strlen( $source );
255
256 $translations[ $array_index ][] = $translation;
257 }
258
259 // Cache translations as a persistent option
260 update_option( 'wplng_cached_translations', $translations, false );
261
262 return $translations;
263 }
264
265
266 /**
267 * Save a translation
268 *
269 * @param string $language_id
270 * @param string $original
271 * @param array $translation
272 * @return int|false Post ID or false on failure
273 */
274 function wplng_save_translation_new( $language_id, $original, $translation ) {
275
276 $translation = str_replace( '\\', '', $translation );
277
278 /**
279 * Make the title
280 */
281
282 $tite_max_length = 100;
283 $title = mb_substr( $original, 0, $tite_max_length );
284 $title = wplng_text_esc_displayed( $title );
285 $title = wp_encode_emoji( $title );
286 if ( strlen( $original ) > $tite_max_length ) {
287 $title .= __( '...', 'wplingua' );
288 }
289
290 /**
291 * Create the post and get this ID
292 */
293
294 $new_post_id = wp_insert_post(
295 array(
296 'post_title' => esc_html( $title ),
297 'post_type' => 'wplng_translation',
298 'post_status' => 'publish',
299 'post_name' => sanitize_title(
300 'wplingua-translation-' . md5( $title ) . '-' . $title
301 ),
302 )
303 );
304
305 if ( is_wp_error( $new_post_id ) || empty( $new_post_id ) ) {
306 return false;
307 }
308
309 /**
310 * Make $translation_meta
311 */
312
313 $languages_target = wplng_get_languages_target_ids();
314 $translation_meta = array();
315
316 foreach ( $languages_target as $target_language ) {
317
318 if ( $target_language === $language_id ) {
319 $translation_meta[] = array(
320 'language_id' => $target_language,
321 'translation' => esc_html( $translation ),
322 'status' => 'generated',
323 );
324 } else {
325 $translation_meta[] = array(
326 'language_id' => $target_language,
327 'translation' => '[WPLNG_EMPTY]',
328 'status' => 'ungenerated',
329 );
330 }
331 }
332
333 /**
334 * Get the URL where the translation was discovered
335 */
336
337 $discovery_url = wplng_get_url_original();
338 $discovery_url = wp_make_link_relative( $discovery_url );
339 $discovery_url = remove_query_arg(
340 array( 'wplng-mode', 'wplng-load', 'nocache' ),
341 $discovery_url
342 );
343
344 /**
345 * Save meta: Discovered URL
346 */
347
348 $meta_return = add_post_meta(
349 $new_post_id,
350 'wplng_translation_discovery_url',
351 $discovery_url
352 );
353
354 if ( false === $meta_return ) {
355 wp_delete_post( $new_post_id, true );
356 return false;
357 }
358
359 /**
360 * Save meta: original language ID
361 */
362
363 $meta_return = add_post_meta(
364 $new_post_id,
365 'wplng_translation_original_language_id',
366 wplng_get_language_website_id()
367 );
368
369 if ( false === $meta_return ) {
370 wp_delete_post( $new_post_id, true );
371 return false;
372 }
373
374 /**
375 * Save meta: original text MD5
376 */
377
378 $meta_return = add_post_meta(
379 $new_post_id,
380 'wplng_translation_md5',
381 md5( $original )
382 );
383
384 if ( false === $meta_return ) {
385 wp_delete_post( $new_post_id, true );
386 return false;
387 }
388
389 /**
390 * Save meta: original text
391 */
392
393 $meta_return = add_post_meta(
394 $new_post_id,
395 'wplng_translation_original',
396 $original
397 );
398
399 if ( false === $meta_return ) {
400
401 // Try to save it with encoded emoji
402 $original = wp_encode_emoji( $original );
403
404 $meta_return = add_post_meta(
405 $new_post_id,
406 'wplng_translation_original',
407 $original
408 );
409
410 if ( false === $meta_return ) {
411 wp_delete_post( $new_post_id, true );
412 return false;
413 }
414 }
415
416 /**
417 * Save meta: Translation array as JSON
418 */
419
420 $meta_return = add_post_meta(
421 $new_post_id,
422 'wplng_translation_translations',
423 wp_json_encode(
424 $translation_meta,
425 JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
426 )
427 );
428
429 if ( false === $meta_return ) {
430
431 // Try to save it with encoded emoji
432 foreach ( $translation_meta as $key => $translation ) {
433
434 if ( empty( $translation['translation'] )
435 || '[WPLNG_EMPTY]' === $translation['translation']
436 ) {
437 continue;
438 }
439
440 $translation_meta[ $key ]['translation'] = wp_encode_emoji( $translation['translation'] );
441 }
442
443 $meta_return = add_post_meta(
444 $new_post_id,
445 'wplng_translation_translations',
446 wp_json_encode(
447 $translation_meta,
448 JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
449 )
450 );
451
452 if ( false === $meta_return ) {
453 wp_delete_post( $new_post_id, true );
454 return false;
455 }
456 }
457
458 return $new_post_id;
459 }
460
461
462 /**
463 * Update a translation
464 *
465 * @param object $post
466 * @param string $language_id
467 * @param array $translation
468 * @return int|false Post ID, false on failure
469 */
470 function wplng_update_translation( $post, $language_id, $translation ) {
471
472 $translation = str_replace( '\\', '', $translation );
473 $meta = get_post_meta( $post->ID );
474 $languages_target = wplng_get_languages_target_ids();
475 $website_language = wplng_get_language_website_id();
476
477 $translation_meta = ( empty( $meta['wplng_translation_translations'][0] ) )
478 ? array() :
479 json_decode( $meta['wplng_translation_translations'][0], true );
480
481 $original_language_id_meta = ( empty( $meta['wplng_translation_original_language_id'][0] ) )
482 ? wplng_get_language_website_id()
483 : $meta['wplng_translation_original_language_id'][0];
484
485 // If translation found is not valid
486 if ( empty( $translation_meta )
487 || $website_language !== $original_language_id_meta
488 ) {
489
490 /**
491 * $original_language_id_meta must be the same as in option page
492 */
493
494 $meta_return = update_post_meta(
495 $post->ID,
496 'wplng_translation_original_language_id',
497 $website_language
498 );
499
500 if ( false === $meta_return ) {
501 return false;
502 }
503
504 /**
505 * Make $translation_meta
506 */
507
508 $translation_meta = array();
509 foreach ( $languages_target as $key => $target_language ) {
510
511 if ( $target_language === $language_id && $translation !== '[WPLNG_EMPTY]' ) {
512 $translation_meta[] = array(
513 'language_id' => $target_language,
514 'translation' => esc_html( $translation ),
515 'status' => 'generated',
516 );
517 } else {
518 $translation_meta[] = array(
519 'language_id' => $target_language,
520 'translation' => '[WPLNG_EMPTY]',
521 'status' => 'ungenerated',
522 );
523 }
524 }
525 } else { // Translation is valid
526
527 // Set or update new translation
528 $translation_already_in = false;
529
530 foreach ( $translation_meta as $key => $translation_e ) {
531 if ( $translation_e['language_id'] === $language_id ) {
532 $translation_already_in = true;
533 $translation_meta[ $key ] = array(
534 'language_id' => $language_id,
535 'translation' => esc_html( $translation ),
536 'status' => 'generated',
537 );
538 break;
539 }
540 }
541
542 if ( ! $translation_already_in ) {
543 $translation_meta[] = array(
544 'language_id' => $language_id,
545 'translation' => esc_html( $translation ),
546 'status' => 'generated',
547 );
548 }
549 }
550
551 /**
552 * Update the translations post meta
553 */
554
555 $meta_return = update_post_meta(
556 $post->ID,
557 'wplng_translation_translations',
558 wp_json_encode(
559 $translation_meta,
560 JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
561 )
562 );
563
564 if ( false === $meta_return ) {
565
566 // Try to save it with encoded emoji
567 foreach ( $translation_meta as $key => $translation ) {
568
569 if ( empty( $translation['translation'] )
570 || '[WPLNG_EMPTY]' === $translation['translation']
571 ) {
572 continue;
573 }
574
575 $translation_meta[ $key ]['translation'] = wp_encode_emoji( $translation['translation'] );
576 }
577
578 $meta_return = update_post_meta(
579 $post->ID,
580 'wplng_translation_translations',
581 wp_json_encode(
582 $translation_meta,
583 JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
584 )
585 );
586
587 if ( false === $meta_return ) {
588 return false;
589 }
590 }
591
592 return $post->ID;
593 }
594
595
596 /**
597 * Save a list of translations
598 *
599 * @param array $translations
600 * @param string $language_target_id
601 * @return array $translations with post IDs
602 */
603 function wplng_save_translations( $translations, $language_target_id ) {
604
605 if ( empty( $translations ) || ! is_array( $translations ) ) {
606 return array();
607 }
608
609 foreach ( $translations as $key => $translation ) {
610
611 if (
612 ! isset( $translation['source'] ) // Original text
613 || ! isset( $translation['translation'] ) // Translater text
614 ) {
615 continue;
616 }
617
618 $translations[ $key ]['post_id'] = wplng_save_translation(
619 $language_target_id,
620 $translation['source'],
621 $translation['translation'],
622 false
623 );
624 }
625
626 wplng_clear_translations_cache();
627
628 return $translations;
629 }
630
631
632 /**
633 * Save translation
634 *
635 * @param string $target_language_id
636 * @param string $original
637 * @param array $translation
638 * @return array $translation with post ID
639 */
640 function wplng_save_translation( $target_language_id, $original, $translation, $clear_cache = true ) {
641
642 $saved_translation = wplng_get_translation_saved_from_original( $original );
643
644 if ( empty( $saved_translation ) ) {
645 // Create new translation post
646 $result = wplng_save_translation_new(
647 $target_language_id,
648 $original,
649 $translation
650 );
651 } else {
652 // Update the translation post
653 $result = wplng_update_translation(
654 $saved_translation,
655 $target_language_id,
656 $translation
657 );
658 }
659
660 if ( $clear_cache ) {
661 wplng_clear_translations_cache();
662 }
663
664 return $result;
665 }
666