$text ) { $translated = self::translate_single($text, $target_locale,$provider ); if ( is_wp_error( $translated ) ) { return $translated; } $translated_matrix[ $index ] =$translated; } return $translated_matrix; default: return new WP_Error( 'unmapped_provider', __( 'Selected batch routing engine lacks an active payload class handler.', 'af-translate' ) ); } } /** * ------------------------------------------------------------------ * COMMON CORE UTILITIES & HELPERS * ------------------------------------------------------------------ */ /** * Execute remote HTTP POST requests with standardized error handling and JSON decoding. */ private static function execute_api_post( $endpoint, $headers,$body, $timeout = 25,$json_encode = true ) { $response = wp_remote_post($endpoint, array( 'timeout' => $timeout, 'headers' => $headers, 'body' => $json_encode ? wp_json_encode( $body ) :$body, )); if ( is_wp_error( $response ) ) { return $response; } $code = wp_remote_retrieve_response_code($response ); $decoded = json_decode( wp_remote_retrieve_body($response ), true ); if ( $code < 200 || $code >= 300 ) {$msg = __( 'Remote API endpoint communication disruption.', 'af-translate' ); if ( isset( $decoded['error']['message'] ) ) { $msg =$decoded['error']['message']; } elseif ( isset( $decoded['message'] ) ) { $msg =$decoded['message']; } return new WP_Error( 'remote_api_error', $msg ); } return $decoded; } /** * Centralized prompt builder to handle string replacements and filters. */ private static function build_llm_prompt( $text, $target_locale,$settings, $provider,$append_instruction = '') { if ( 'openai' === $provider ) {$prompt = self::get_openai_system_prompt( $target_locale,$settings ); } else { $prompt_key = $provider . '_custom_prompt';$default_prompt = 'Translate this WordPress string to {target_language}. Keep code/HTML placeholders identical. CRITICAL: Return ONLY the absolute raw translation text. Do NOT include any conversational text, introductory remarks, explanations, or Markdown formatting.'; $prompt = ! empty( $settings[ $prompt_key ] ) ?$settings[ $prompt_key ] :$default_prompt; $prompt = str_replace( '{target_language}', $target_locale,$prompt ); } if ( ! empty( $append_instruction ) ) { $prompt .= ' ' .$append_instruction; } return apply_filters( 'af_translate_llm_system_prompt', $prompt, $text,$target_locale ); } /** * Safely extract the active API key. */ private static function get_api_key( $settings,$provider ) { if ( 'openai' === $provider ) { return ! empty( $settings['openai_key'] ) ? trim( $settings['openai_key'] ) : get_option( 'af_translate_api_key', '' ); } $key_field =$provider . '_key'; return isset( $settings[$key_field ] ) ? trim( $settings[$key_field ] ) : ''; } private static function call_gemini( $text, $target_locale, $settings ) { $api_key = self::get_api_key( $settings, 'gemini' ); if ( empty( $api_key ) ) { return new WP_Error( 'missing_key', __( 'Gemini API key is empty.', 'af-translate' ) ); } $model = ! empty( $settings['gemini_model'] ) ? trim( $settings['gemini_model'] ) : 'gemini-3.1-flash-lite'; $prompt = self::build_llm_prompt( $text, $target_locale, $settings, 'gemini' ); $endpoint = 'https://generativelanguage.googleapis.com/v1beta/models/' . sanitize_text_field( $model ) . ':generateContent?key=' . $api_key; $payload = apply_filters( 'af_translate_llm_request_body', array( 'contents' => array( array( 'parts' => array( array( 'text' => $text ) ) ) ), 'systemInstruction' => array( 'parts' => array( array( 'text' => $prompt ) ) ), // Fixed: Removed extra outer array layout 'generationConfig' => array( 'temperature' => isset( $settings['pro_temperature'] ) ? (float) $settings['pro_temperature'] : 0.1 ) ), 'gemini' ); $body = self::execute_api_post( $endpoint, array( 'Content-Type' => 'application/json' ), $payload, 25 ); if ( is_wp_error( $body ) ) { return $body; } if ( isset( $body['candidates'][0]['content']['parts'][0]['text'] ) ) { return self::clean_model_response( $body['candidates'][0]['content']['parts'][0]['text'] ); } return new WP_Error( 'api_error', __( 'Gemini execution loop failed.', 'af-translate' ) ); } private static function call_gemini_batch( $strings_array, $target_locale, $settings ) { $api_key = self::get_api_key( $settings, 'gemini' ); if ( empty( $api_key ) ) { return new WP_Error( 'missing_key', __( 'Gemini API key is empty.', 'af-translate' ) ); } $model = ! empty( $settings['gemini_model'] ) ? trim( $settings['gemini_model'] ) : 'gemini-3.1-flash-lite'; $append = 'CRITICAL REQUIREMENT: Input will arrive as an explicitly indexed JSON object array layout matrix. You must return absolute translation output ONLY as a matching structural JSON object using the identical key assignments. Do not include markdown code wrapping blocks.'; $prompt = self::build_llm_prompt( implode( ' ', $strings_array ), $target_locale, $settings, 'gemini', $append ); $endpoint = 'https://generativelanguage.googleapis.com/v1beta/models/' . sanitize_text_field( $model ) . ':generateContent?key=' . $api_key; $payload = apply_filters( 'af_translate_llm_request_body', array( 'contents' => array( array( 'parts' => array( array( 'text' => wp_json_encode( $strings_array ) ) ) ) ), 'systemInstruction' => array( 'parts' => array( array( 'text' => $prompt ) ) ), // Fixed: Removed extra outer array layout 'generationConfig' => array( 'temperature' => isset( $settings['pro_temperature'] ) ? (float) $settings['pro_temperature'] : 0.1, 'responseMimeType' => 'application/json' ) ), 'gemini' ); $body = self::execute_api_post( $endpoint, array( 'Content-Type' => 'application/json' ), $payload, 45 ); if ( is_wp_error( $body ) ) { return $body; } if ( isset( $body['candidates'][0]['content']['parts'][0]['text'] ) ) { $json_str = trim( $body['candidates'][0]['content']['parts'][0]['text'] ); $json_str = preg_replace( '/^```json\s*/i', '', $json_str );$json_str = preg_replace( '/\s*```$/', '', $json_str ); $decoded = json_decode( trim( $json_str ), true ); if ( is_array( $decoded ) ) { return $decoded; } } return new WP_Error( 'gemini_batch_alignment_failed', __( 'Could not securely synchronize translated Gemini dataset matrix structural syntax layout.', 'af-translate' ) ); } private static function call_openai_single( $source_text, $target_locale,$settings ) { $api_key = self::get_api_key($settings, 'openai' ); if ( empty( $api_key ) ) { return new WP_Error( 'missing_key', __( 'OpenAI API key is empty.', 'af-translate' ) ); } $model = ! empty( $settings['openai_model'] ) ? $settings['openai_model'] : get_option( 'af_translate_ai_model', 'gpt-4o-mini' );$prompt = self::build_llm_prompt( $source_text,$target_locale, $settings, 'openai' );$endpoint = ! empty( $settings['openai_custom_endpoint'] ) ? esc_url_raw( $settings['openai_custom_endpoint'] ) : 'https://api.openai.com/v1/chat/completions'; $payload = apply_filters( 'af_translate_llm_request_body', array( 'model' => $model, 'temperature' => isset( $settings['pro_temperature'] ) ? (float)$settings['pro_temperature'] : 0.2, 'messages' => array( array( 'role' => 'system', 'content' => $prompt ), array( 'role' => 'user', 'content' => $source_text ) ) ), 'openai' ); $headers = array( 'Authorization' => 'Bearer ' .$api_key, 'Content-Type' => 'application/json' ); $body = self::execute_api_post($endpoint, $headers,$payload, 45 ); if ( is_wp_error( $body ) ) { return $body; } if ( isset( $body['choices'][0]['message']['content'] ) ) { return self::clean_model_response( $body['choices'][0]['message']['content'] ); } return new WP_Error( 'api_malformed_response', __( 'OpenAI core node returned an unreadable response layout.', 'af-translate' ) ); } private static function call_openai_batch( $strings_array, $target_locale,$settings ) { $api_key = self::get_api_key($settings, 'openai' ); if ( empty( $api_key ) ) { return new WP_Error( 'missing_key', __( 'OpenAI API key is empty.', 'af-translate' ) ); } $model = ! empty( $settings['openai_model'] ) ? $settings['openai_model'] : get_option( 'af_translate_ai_model', 'gpt-4o-mini' );$append = 'Crucial Instruction: Input will arrive as a serialized JSON object map. You must respond ONLY with a valid JSON object matching the exact key definitions. Do not include markdown wraps or ```json indicators.'; $prompt = self::build_llm_prompt( implode( ' ', $strings_array ), $target_locale, $settings, 'openai', $append ); $endpoint = ! empty( $settings['openai_custom_endpoint'] ) ? esc_url_raw( $settings['openai_custom_endpoint'] ) : '[https://api.openai.com/v1/chat/completions](https://api.openai.com/v1/chat/completions)'; $payload = apply_filters( 'af_translate_llm_request_body', array( 'model' => $model, 'temperature' => isset( $settings['pro_temperature'] ) ? (float) $settings['pro_temperature'] : 0.2, 'response_format' => array( 'type' => 'json_object' ), 'messages' => array( array( 'role' => 'system', 'content' => $prompt ), array( 'role' => 'user', 'content' => wp_json_encode( $strings_array ) ) ) ), 'openai' ); $headers = array( 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json' ); $body = self::execute_api_post( $endpoint, $headers, $payload, 45 ); if ( is_wp_error( $body ) ) { return $body; } if ( isset( $body['choices'][0]['message']['content'] ) ) { $decoded = json_decode( $body['choices'][0]['message']['content'], true ); if ( is_array( $decoded ) ) { return $decoded; } } return new WP_Error( 'batch_alignment_failed', __( 'Could not securely synchronize translated OpenAI dataset matrix trees.', 'af-translate' ) ); } private static function get_openai_system_prompt( $target_locale, $settings ) { if ( ! empty( $settings['openai_custom_prompt'] ) ) { return str_replace( '{target_language}', $target_locale, $settings['openai_custom_prompt'] ); } return "You are a professional localization engine processing complex core WordPress gettext catalogs. " . "Translate the provided text content accurately into the target language code context: '{$target_locale}'. " . "CRITICAL: You must preserve all raw formatting parameters, HTML entities, and structural printf string layout placeholders exactly as they appear in the source string. " . "CRITICAL: Return ONLY the absolute raw translation text. Do NOT include any conversational text, introductory remarks, explanations, or Markdown formatting."; } private static function call_anthropic( $text, $target_locale, $settings ) { $api_key = self::get_api_key( $settings, 'anthropic' ); if ( empty( $api_key ) ) { return new WP_Error( 'missing_key', __( 'Anthropic API key is empty.', 'af-translate' ) ); } $model = ! empty( $settings['anthropic_model'] ) ? trim( $settings['anthropic_model'] ) : 'claude-3-5-sonnet-latest'; $prompt = self::build_llm_prompt( $text, $target_locale, $settings, 'anthropic' ); $payload = apply_filters( 'af_translate_llm_request_body', array( 'model' => sanitize_text_field( $model ), 'max_tokens' => 2000, 'temperature' => isset( $settings['pro_temperature'] ) ? (float) $settings['pro_temperature'] : 0.1, 'system' => $prompt, 'messages' => array( array( 'role' => 'user', 'content' => array( array( 'type' => 'text', 'text' => $text ) ) ) ), ), 'anthropic' ); $headers = array( 'x-api-key' => $api_key, 'anthropic-version' => '2023-06-01', 'content-type' => 'application/json' ); $body = self::execute_api_post( '[https://api.anthropic.com/v1/messages](https://api.anthropic.com/v1/messages)', $headers, $payload, 25 ); if ( is_wp_error( $body ) ) { return $body; } if ( isset( $body['content'][0]['text'] ) ) { return self::clean_model_response( $body['content'][0]['text'] ); } return new WP_Error( 'api_error', __( 'Anthropic payload execution failed.', 'af-translate' ) ); } private static function call_grok( $text, $target_locale, $settings ) { $api_key = self::get_api_key( $settings, 'grok' ); if ( empty( $api_key ) ) { return new WP_Error( 'missing_key', __( 'Grok API key is empty.', 'af-translate' ) ); } $model = ! empty( $settings['grok_model'] ) ? trim( $settings['grok_model'] ) : 'grok-4'; $prompt = self::build_llm_prompt( $text, $target_locale, $settings, 'grok' ); $payload = apply_filters( 'af_translate_llm_request_body', array( 'model' => sanitize_text_field( $model ), 'temperature' => isset( $settings['pro_temperature'] ) ? (float) $settings['pro_temperature'] : 0.2, 'messages' => array( array( 'role' => 'system', 'content' => $prompt ), array( 'role' => 'user', 'content' => $text ), ), ), 'grok' ); $headers = array( 'Authorization' => 'Bearer ' . $api_key, 'Content-Type' => 'application/json' ); $body = self::execute_api_post( '[https://api.x.ai/v1/chat/completions](https://api.x.ai/v1/chat/completions)', $headers, $payload, 25 ); if ( is_wp_error( $body ) ) { return $body; } if ( isset( $body['choices'][0]['message']['content'] ) ) { return self::clean_model_response( $body['choices'][0]['message']['content'] ); } return new WP_Error( 'api_error', __( 'Grok response validation failed.', 'af-translate' ) ); } /** * ------------------------------------------------------------------ * NEURAL MACHINE TRANSLATION (NMT) ENGINES * ------------------------------------------------------------------ */ private static function call_deepl( $text, $target_locale, $settings ) { $api_key = self::get_api_key( $settings, 'deepl' ); if ( empty( $api_key ) ) { return new WP_Error( 'missing_key', __( 'DeepL API key is empty.', 'af-translate' ) ); } $target_lang = strtolower( substr( $target_locale, 0, 2 ) ); $endpoint = ( 'fx' === substr( strtolower( $api_key ), -2 ) ) ? '[https://api-free.deepl.com/v2/translate](https://api-free.deepl.com/v2/translate)' : '[https://api.deepl.com/v2/translate](https://api.deepl.com/v2/translate)'; $payload = apply_filters( 'af_translate_nmt_request_body', array( 'text' => array( $text ), 'target_lang' => strtoupper( $target_lang ) ), 'deepl', $target_lang, $text ); $headers = array( 'Authorization' => 'DeepL-Auth-Key ' . $api_key, 'Content-Type' => 'application/json' ); $body = self::execute_api_post( $endpoint, $headers, $payload, 15 ); if ( is_wp_error( $body ) ) { return $body; } if ( isset( $body['translations'][0]['text'] ) ) { return $body['translations'][0]['text']; } return new WP_Error( 'api_error', __( 'DeepL compilation failed.', 'af-translate' ) ); } private static function call_google( $text, $target_locale, $settings ) { $api_key = self::get_api_key( $settings, 'google' ); if ( empty( $api_key ) ) { return new WP_Error( 'missing_key', __( 'Google Translate API key is empty.', 'af-translate' ) ); } $target_lang = strtolower( substr( $target_locale, 0, 2 ) ); $url = '[https://translation.googleapis.com/language/translate/v2?key=](https://translation.googleapis.com/language/translate/v2?key=)' . $api_key; $payload = apply_filters( 'af_translate_nmt_request_body', array( 'q' => $text, 'target' => $target_lang, 'format' => 'text' ), 'google', $target_lang, $text ); $body = self::execute_api_post( $url, array(), $payload, 15, false ); if ( is_wp_error( $body ) ) { return $body; } if ( isset( $body['data']['translations'][0]['translatedText'] ) ) { return html_entity_decode( $body['data']['translations'][0]['translatedText'], ENT_QUOTES, 'UTF-8' ); } return new WP_Error( 'api_error', __( 'Google Translate request failed.', 'af-translate' ) ); } private static function call_lecto( $text, $target_locale, $settings ) { $api_key = self::get_api_key( $settings, 'lecto' ); if ( empty( $api_key ) ) { return new WP_Error( 'missing_key', __( 'Lecto AI API key is empty.', 'af-translate' ) ); } $target_lang = strtolower( substr( $target_locale, 0, 2 ) ); $payload = apply_filters( 'af_translate_nmt_request_body', array( 'texts' => array( $text ), 'to' => array( $target_lang ) ), 'lecto', $target_lang, $text ); $headers = array( 'X-API-Key' => $api_key, 'Content-Type' => 'application/json' ); $body = self::execute_api_post( '[https://api.lecto.ai/v1/translate/text](https://api.lecto.ai/v1/translate/text)', $headers, $payload, 15 ); if ( is_wp_error( $body ) ) { return $body; } if ( isset( $body['translations'][0]['to'][0]['translated'][0] ) ) { return $body['translations'][0]['to'][0]['translated'][0]; } return new WP_Error( 'api_error', __( 'Lecto AI execution payload failed.', 'af-translate' ) ); } private static function call_microsoft( $text, $target_locale, $settings ) { $api_key = self::get_api_key( $settings, 'microsoft' ); if ( empty( $api_key ) ) { return new WP_Error( 'missing_key', __( 'Microsoft Translator API key is empty.', 'af-translate' ) ); } $region = isset( $settings['microsoft_region'] ) ? trim( $settings['microsoft_region'] ) : 'global'; $target_lang = strtolower( substr( $target_locale, 0, 2 ) ); $url = '[https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=](https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to=)' . $target_lang; $payload = apply_filters( 'af_translate_nmt_request_body', array( array( 'Text' => $text ) ), 'microsoft', $target_lang, $text ); $headers = array( 'Ocp-Apim-Subscription-Key' => $api_key, 'Ocp-Apim-Subscription-Region' => $region, 'Content-Type' => 'application/json' ); $body = self::execute_api_post( $url, $headers, $payload, 15 ); if ( is_wp_error( $body ) ) { return $body; } if ( isset( $body[0]['translations'][0]['text'] ) ) { return $body[0]['translations'][0]['text']; } return new WP_Error( 'api_error', __( 'Microsoft Translator verification failed.', 'af-translate' ) ); } /** * ------------------------------------------------------------------ * RESOLVERS & SANDBOX SYSTEM * ------------------------------------------------------------------ */ private static function resolve_active_provider( $settings, $explicit_provider = '' ) { if ( ! empty( $explicit_provider ) ) { return sanitize_key( $explicit_provider ); } if ( ! empty( $settings['active_provider'] ) ) { $active = sanitize_key( $settings['active_provider'] ); if ( ! empty( $settings[ $active . '_key' ] ) && 'sandbox-test-key' !== $settings[ $active . '_key' ] ) { return $active; } } foreach ( array( 'gemini', 'openai', 'anthropic', 'grok', 'deepl', 'microsoft', 'google', 'lecto' ) as $provider ) { if ( ! empty( $settings[ $provider . '_key' ] ) && 'sandbox-test-key' !== $settings[ $provider . '_key' ] ) { return $provider; } } return 'gemini'; } private static function is_sandbox_mode( $settings, $provider ) { if ( 'openai' === $provider && 'sandbox-test-key' === get_option( 'af_translate_api_key', '' ) ) { return true; } $api_key = isset( $settings[ $provider . '_key' ] ) ? trim( $settings[ $provider . '_key' ] ) : ''; return ( empty( $api_key ) || 'sandbox-test-key' === $api_key ); } private static function simulate_single_sandbox( $text, $locale ) { usleep( 600000 ); return "[Sandbox - Language Target: " . strtoupper( esc_html( $locale ) ) . "]: " . $text; } private static function simulate_batch_sandbox( $strings_array, $locale ) { usleep( 1200000 ); $mocked_catalog = array(); foreach ( $strings_array as $index => $text ) { $mocked_catalog[ $index ] = "[Bulk Sandbox - " . strtoupper( esc_html( $locale ) ) . "]: " . $text; } return $mocked_catalog; } }