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

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

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