PluginProbe
Translate and Go multilingual – Automatic AI translation – wpLingua / 2.10.0
Translate and Go multilingual – Automatic AI translation – wpLingua v2.10.0
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.10.0, at inc/translation.php

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