get_active_languages(); $default_lang = $sitepress->get_default_language(); $string_domains = []; $string_domains_grouped = []; if ($wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}icl_strings'")) { $string_domains = $wpdb->get_col("SELECT DISTINCT context FROM {$wpdb->prefix}icl_strings ORDER BY context ASC"); $string_domains_grouped = [ 'Theme' => [], 'Plugins' => [], 'Blocks' => [], 'Settings / Admin' => [], 'Other' => [] ]; $theme_slugs = [get_stylesheet(), get_template()]; $plugin_slugs = []; foreach (get_option('active_plugins', []) as $plugin) { $plugin_slugs[] = dirname($plugin); } foreach ($string_domains as $domain) { if (strpos($domain, 'admin_texts_') === 0) { $string_domains_grouped['Settings / Admin'][] = $domain; } elseif (strpos($domain, 'gutenberg_') === 0 || strpos($domain, 'block') !== false) { $string_domains_grouped['Blocks'][] = $domain; } elseif (in_array($domain, $theme_slugs)) { $string_domains_grouped['Theme'][] = $domain; } elseif (in_array($domain, $plugin_slugs) || strpos($domain, 'plugin-') === 0) { $string_domains_grouped['Plugins'][] = $domain; } else { $string_domains_grouped['Other'][] = $domain; } } } ?>
get_param('domain'); $target_lang = $request->get_param('target_lang'); if (empty($domain) || empty($target_lang)) { return new \WP_REST_Response(['success' => false, 'message' => 'Missing domain or target_lang parameters'], 400); } // phpcs:ignore WordPress.DB.DirectDatabaseQuery $results = $wpdb->get_results($wpdb->prepare(" SELECT s.id, s.name, s.value FROM {$wpdb->prefix}icl_strings s LEFT JOIN {$wpdb->prefix}icl_string_translations st ON s.id = st.string_id AND st.language = %s WHERE s.context = %s AND s.language != %s AND (st.id IS NULL OR st.status != 10) ORDER BY s.id DESC LIMIT 500 ", $target_lang, $domain, $target_lang)); $items = []; foreach ($results as $r) { $items[] = [ 'id' => $r->id, 'name' => esc_html(mb_strimwidth($r->name, 0, 80, '...')), 'value' => esc_html(mb_strimwidth($r->value, 0, 150, '...')) ]; } return new \WP_REST_Response(['success' => true, 'items' => $items], 200); } public function handle_wpml_strings_translate(\WP_REST_Request $request) { global $wpdb; $string_id = (int)$request->get_param('string_id'); $target_lang = $request->get_param('target_lang'); if (!$string_id || empty($target_lang) || !function_exists('icl_add_string_translation')) { return new \WP_REST_Response(['success' => false, 'message' => 'Invalid request or ST not installed'], 400); } $string_value = $wpdb->get_var($wpdb->prepare("SELECT value FROM {$wpdb->prefix}icl_strings WHERE id = %d", $string_id)); if (empty($string_value)) { return new \WP_REST_Response(['success' => false, 'message' => 'String empty or not found'], 400); } $prompt = "You are an expert translator. Translate the following UI/text string into the language represented by the ISO code '{$target_lang}'.\n"; $prompt .= "IMPORTANT RULES:\n"; $prompt .= "1. Respond ONLY with the translated text. Do NOT include any explanations, quotes, or JSON.\n"; $prompt .= "2. Preserve any placeholders like %s, %d, {name}, HTML tags exactly.\n\n"; $prompt .= "TEXT TO TRANSLATE:\n" . $string_value; $model = get_option('aiutoma_wpml_model', ''); if ($model === 'google_free' && method_exists($this, 'google_translate_free')) { $source_lang = $wpdb->get_var($wpdb->prepare("SELECT language FROM {$wpdb->prefix}icl_strings WHERE id = %d", $string_id)); if (!$source_lang) $source_lang = 'en'; // default fallback $result = $this->google_translate_free($source_lang, $target_lang, $string_value); } else { $result = $this->call_ai_for_text($prompt); } if (is_wp_error($result)) { return new \WP_REST_Response(['success' => false, 'message' => $result->get_error_message()], 500); } if (trim($result) === '') { return new \WP_REST_Response(['success' => false, 'message' => 'Empty translation received'], 500); } icl_add_string_translation($string_id, $target_lang, trim($result), 10); return new \WP_REST_Response(['success' => true], 200); } private function call_ai_for_text($prompt) { if (!class_exists('\WordPress\AiClient\AiClient')) { return new \WP_Error('ai_missing', 'AI Client not found.'); } $preferred_model = get_option('aiutoma_wpml_model', ''); $auto_fallback = get_option('aiutoma_wpml_auto_fallback', 0); $fallback_models = get_option('aiutoma_wpml_fallback_models', []); $models_to_try = []; if (!empty($preferred_model)) { $models_to_try[] = $preferred_model; if ($auto_fallback && !empty($fallback_models)) { $models_to_try = array_merge($models_to_try, $fallback_models); } } if (empty($models_to_try)) { $registry = \WordPress\AiClient\AiClient::defaultRegistry(); $requirements = new \WordPress\AiClient\Providers\Models\DTO\ModelRequirements( [\WordPress\AiClient\Providers\Models\Enums\CapabilityEnum::textGeneration()], [] ); $providerModels = $registry->findModelsMetadataForSupport($requirements); foreach ($providerModels as $pm) { $pid = $pm->getProvider()->getId(); foreach ($pm->getModels() as $m) { $models_to_try[] = $pid . '|' . $m->getId(); break 2; } } } $last_exception = null; foreach ($models_to_try as $model_str) { $model_parts = explode('|', $model_str); if (count($model_parts) !== 2) continue; $max_retries = 2; for ($attempt = 0; $attempt <= $max_retries; $attempt++) { try { $ai_query = \WordPress\AiClient\AiClient::prompt([ new \WordPress\AiClient\Messages\DTO\UserMessage([ new \WordPress\AiClient\Messages\DTO\MessagePart($prompt) ]) ]); $ai_query->usingModelPreference($model_parts); $res = $ai_query->generateResult(); $text = $res->toText(); if (!empty($text)) { return $text; } else { throw new \Exception("Empty text returned from model."); } } catch (\Exception $e) { $last_exception = $e; $msg = strtolower($e->getMessage()); if (strpos($msg, 'token') !== false || strpos($msg, 'quota') !== false || strpos($msg, 'credit') !== false || strpos($msg, 'rate') !== false || strpos($msg, 'limit') !== false || strpos($msg, '429') !== false || strpos($msg, '408') !== false || strpos($msg, '500') !== false || strpos($msg, '502') !== false || strpos($msg, '503') !== false || strpos($msg, 'timeout') !== false) { if ($attempt < $max_retries) { sleep(2); continue; } } break; } } } if ($last_exception) { return new \WP_Error('ai_exception', 'All AI models failed. Last error: ' . $last_exception->getMessage()); } return new \WP_Error('ai_unknown_error', 'Failed to generate text.'); } public function aiutoma_wpml_has_strings() { global $wpdb; return (bool) $wpdb->get_var("SHOW TABLES LIKE '{$wpdb->prefix}icl_strings'"); } }