publish ?? 0 ); return $wplng_translation_count; } /** * Get translation data from original text * * @param string $original * @return array Translation data */ function wplng_get_translation_saved_from_original( $original ) { if ( empty( $original ) ) { return false; } $args = array( 'post_type' => 'wplng_translation', 'posts_per_page' => -1, 'meta_query' => array( array( 'key' => 'wplng_translation_md5', 'value' => md5( $original ), 'compare' => '=', ), ), 'fields' => 'ids', 'meta_query' => array( array( 'key' => 'wplng_translation_original_language_id', 'value' => wplng_get_language_website_id(), 'compare' => '=', ), ), ); $posts = get_posts( $args ); if ( empty( $posts ) ) { return false; } foreach ( $posts as $post_id ) { $meta = get_post_meta( $post_id ); if ( isset( $meta['wplng_translation_original'][0] ) && is_string( $meta['wplng_translation_original'][0] ) && $meta['wplng_translation_original'][0] === $original ) { return get_post( $post_id ); } } return false; } /** * Get all saved translations from a wp_query for all languages * * @return array */ function wplng_get_translations_from_query() { $translations = array(); $args = array( 'post_type' => 'wplng_translation', 'posts_per_page' => -1, 'no_found_rows' => true, 'update_post_term_cache' => false, 'update_post_meta_cache' => false, 'cache_results' => false, 'fields' => 'ids', // Retrieve only post IDs for better performance 'meta_query' => array( array( 'key' => 'wplng_translation_original_language_id', 'value' => wplng_get_language_website_id(), 'compare' => '=', ), ), ); $post_ids = get_posts( $args ); if ( empty( $post_ids ) ) { return array(); } foreach ( $post_ids as $id ) { $meta = get_post_meta( $id ); // Ensure 'wplng_translation_original' exists and is a valid string if ( empty( $meta['wplng_translation_original'][0] ) || ! is_string( $meta['wplng_translation_original'][0] ) || trim( $meta['wplng_translation_original'][0] ) === '' ) { continue; } $source = wplng_text_esc( trim( $meta['wplng_translation_original'][0] ) ); $translation = array( 'source' => $source, 'post_id' => $id, 'review' => array(), 'translations' => array(), ); // Ensure 'wplng_translation_translations' exists if ( empty( $meta['wplng_translation_translations'][0] ) ) { continue; } $translations_meta = json_decode( $meta['wplng_translation_translations'][0], true ); // Ensure JSON decoding was successful if ( ! is_array( $translations_meta ) ) { continue; } foreach ( $translations_meta as $translation_meta ) { // Validate each translation entry if ( empty( $translation_meta['language_id'] ) || ! wplng_is_valid_language_id( $translation_meta['language_id'] ) || ( isset( $translation_meta['translation'] ) && $translation_meta['translation'] === '[WPLNG_EMPTY]' ) ) { continue; } $language_id = sanitize_key( $translation_meta['language_id'] ); if ( isset( $translation_meta['translation'] ) && is_string( $translation_meta['translation'] ) ) { $translated_text = wplng_text_esc( $translation_meta['translation'] ); $translation['translations'][ $language_id ] = $translated_text; } if ( isset( $translation_meta['status'] ) && is_int( $translation_meta['status'] ) ) { $translation['review'][] = $language_id; } } // Skip entries with no valid translations if ( empty( $translation['translations'] ) ) { continue; } $array_index = (string) mb_substr( $source, 0, 1 ) . (string) strlen( $source ); $translations[ $array_index ][] = $translation; } // Cache translations for better performance set_transient( 'wplng_cached_translations', $translations, MONTH_IN_SECONDS ); return $translations; } /** * Save a translation * * @param string $language_id * @param string $original * @param array $translation * @return int|false Post ID or false on failure */ function wplng_save_translation_new( $language_id, $original, $translation ) { $translation = str_replace( '\\', '', $translation ); /** * Make the title */ $tite_max_length = 100; $title = mb_substr( $original, 0, $tite_max_length ); $title = wplng_text_esc_displayed( $title ); $title = wp_encode_emoji( $title ); if ( strlen( $original ) > $tite_max_length ) { $title .= __( '...', 'wplingua' ); } /** * Create the post and get this ID */ $new_post_id = wp_insert_post( array( 'post_title' => esc_html( $title ), 'post_type' => 'wplng_translation', 'post_status' => 'publish', 'post_name' => sanitize_title( 'wplingua-translation-' . md5( $title ) . '-' . $title ), ) ); if ( is_wp_error( $new_post_id ) || empty( $new_post_id ) ) { return false; } /** * Make $translation_meta */ $languages_target = wplng_get_languages_target_ids(); $translation_meta = array(); foreach ( $languages_target as $target_language ) { if ( $target_language === $language_id ) { $translation_meta[] = array( 'language_id' => $target_language, 'translation' => esc_html( $translation ), 'status' => 'generated', ); } else { $translation_meta[] = array( 'language_id' => $target_language, 'translation' => '[WPLNG_EMPTY]', 'status' => 'ungenerated', ); } } /** * Get the URL where the translation was discovered */ $discovery_url = wplng_get_url_original(); $discovery_url = wp_make_link_relative( $discovery_url ); $discovery_url = remove_query_arg( array( 'wplng-mode', 'wplng-load', 'nocache' ), $discovery_url ); /** * Save meta: Discovered URL */ $meta_return = add_post_meta( $new_post_id, 'wplng_translation_discovery_url', $discovery_url ); if ( false === $meta_return ) { wp_delete_post( $new_post_id, true ); return false; } /** * Save meta: original language ID */ $meta_return = add_post_meta( $new_post_id, 'wplng_translation_original_language_id', wplng_get_language_website_id() ); if ( false === $meta_return ) { wp_delete_post( $new_post_id, true ); return false; } /** * Save meta: original text MD5 */ $meta_return = add_post_meta( $new_post_id, 'wplng_translation_md5', md5( $original ) ); if ( false === $meta_return ) { wp_delete_post( $new_post_id, true ); return false; } /** * Save meta: original text */ $meta_return = add_post_meta( $new_post_id, 'wplng_translation_original', $original ); if ( false === $meta_return ) { // Try to save it with encoded emoji $original = wp_encode_emoji( $original ); $meta_return = add_post_meta( $new_post_id, 'wplng_translation_original', $original ); if ( false === $meta_return ) { wp_delete_post( $new_post_id, true ); return false; } } /** * Save meta: Translation array as JSON */ $meta_return = add_post_meta( $new_post_id, 'wplng_translation_translations', wp_json_encode( $translation_meta, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ) ); if ( false === $meta_return ) { // Try to save it with encoded emoji foreach ( $translation_meta as $key => $translation ) { if ( empty( $translation['translation'] ) || '[WPLNG_EMPTY]' === $translation['translation'] ) { continue; } $translation_meta[ $key ]['translation'] = wp_encode_emoji( $translation['translation'] ); } $meta_return = add_post_meta( $new_post_id, 'wplng_translation_translations', wp_json_encode( $translation_meta, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ) ); if ( false === $meta_return ) { wp_delete_post( $new_post_id, true ); return false; } } return $new_post_id; } /** * Update a translation * * @param object $post * @param string $language_id * @param array $translation * @return int|false Post ID, false on failure */ function wplng_update_translation( $post, $language_id, $translation ) { $translation = str_replace( '\\', '', $translation ); $meta = get_post_meta( $post->ID ); $languages_target = wplng_get_languages_target_ids(); $website_language = wplng_get_language_website_id(); $translation_meta = ( empty( $meta['wplng_translation_translations'][0] ) ) ? array() : json_decode( $meta['wplng_translation_translations'][0], true ); $original_language_id_meta = ( empty( $meta['wplng_translation_original_language_id'][0] ) ) ? wplng_get_language_website_id() : $meta['wplng_translation_original_language_id'][0]; // If translation found is not valid if ( empty( $translation_meta ) || $website_language !== $original_language_id_meta ) { /** * $original_language_id_meta must be the same as in option page */ $meta_return = update_post_meta( $post->ID, 'wplng_translation_original_language_id', $website_language ); if ( false === $meta_return ) { return false; } /** * Make $translation_meta */ $translation_meta = array(); foreach ( $languages_target as $key => $target_language ) { if ( $target_language === $language_id && $translation !== '[WPLNG_EMPTY]' ) { $translation_meta[] = array( 'language_id' => $target_language, 'translation' => '[WPLNG_EMPTY]', 'status' => 'ungenerated', ); } else { $translation_meta[] = array( 'language_id' => $target_language, 'translation' => esc_html( $translation ), 'status' => 'generated', ); } } } else { // Translation is valid // Set or update new translation $translation_already_in = false; foreach ( $translation_meta as $key => $translation_e ) { if ( $translation_e['language_id'] === $language_id ) { $translation_already_in = true; $translation_meta[ $key ] = array( 'language_id' => $language_id, 'translation' => esc_html( $translation ), 'status' => 'generated', ); break; } } if ( ! $translation_already_in ) { $translation_meta[] = array( 'language_id' => $language_id, 'translation' => esc_html( $translation ), 'status' => 'generated', ); } } /** * Update the translations post meta */ $meta_return = update_post_meta( $post->ID, 'wplng_translation_translations', wp_json_encode( $translation_meta, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ) ); if ( false === $meta_return ) { // Try to save it with encoded emoji foreach ( $translation_meta as $key => $translation ) { if ( empty( $translation['translation'] ) || '[WPLNG_EMPTY]' === $translation['translation'] ) { continue; } $translation_meta[ $key ]['translation'] = wp_encode_emoji( $translation['translation'] ); } $meta_return = update_post_meta( $post->ID, 'wplng_translation_translations', wp_json_encode( $translation_meta, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ) ); if ( false === $meta_return ) { return false; } } return $post->ID; } /** * Save a list of translations * * @param array $translations * @param string $language_target_id * @return array $translations with post IDs */ function wplng_save_translations( $translations, $language_target_id ) { if ( empty( $translations ) || ! is_array( $translations ) ) { return array(); } foreach ( $translations as $key => $translation ) { if ( ! isset( $translation['source'] ) // Original text || ! isset( $translation['translation'] ) // Translater text ) { continue; } $translations[ $key ]['post_id'] = wplng_save_translation( $language_target_id, $translation['source'], $translation['translation'], false ); } wplng_clear_translations_cache(); return $translations; } /** * Save translation * * @param string $target_language_id * @param string $original * @param array $translation * @return array $translation with post ID */ function wplng_save_translation( $target_language_id, $original, $translation, $clear_cache = true ) { $saved_translation = wplng_get_translation_saved_from_original( $original ); if ( empty( $saved_translation ) ) { // Create new translation post return wplng_save_translation_new( $target_language_id, $original, $translation ); } else { // Update the translation post return wplng_update_translation( $saved_translation, $target_language_id, $translation ); } if ( $clear_cache ) { wplng_clear_translations_cache(); } }