星期日 , 8 11 月 2026

如何用claude的api来自动翻译通过polylang

<?php
/**

  • Polylang AI Auto-Translator
    • This script automatically translates WordPress content using AI
  • and updates the database in Polylang’s required format.
    • Usage: php polylang-translator.php –source=en –target=zh-TW –type=post
      */

require_once(DIR . ‘/wp-load.php’);

class PolylangAITranslator {

private $source_lang;
private $target_lang;
private $content_type;
private $api_key;
private $batch_size = 5;

public function __construct($source_lang, $target_lang, $content_type = 'post') {
    $this->source_lang = $source_lang;
    $this->target_lang = $target_lang;
    $this->content_type = $content_type;
    $this->api_key = getenv('ANTHROPIC_API_KEY'); // Set this in your environment

    if (!function_exists('pll_get_post_language')) {
        die("Error: Polylang is not installed or activated.\n");
    }
}

/**
 * Main execution method
 */
public function run() {
    echo "Starting translation from {$this->source_lang} to {$this->target_lang}...\n";

    $items = $this->get_untranslated_items();
    echo "Found " . count($items) . " items to translate.\n";

    $batches = array_chunk($items, $this->batch_size);
    $total = count($items);
    $processed = 0;

    foreach ($batches as $batch) {
        foreach ($batch as $item) {
            $this->translate_item($item);
            $processed++;
            echo "Progress: {$processed}/{$total}\n";
        }

        // Avoid rate limiting
        sleep(1);
    }

    echo "Translation completed!\n";
}

/**
 * Get items that need translation
 */
private function get_untranslated_items() {
    $args = array(
        'post_type' => $this->content_type,
        'posts_per_page' => -1,
        'lang' => $this->source_lang,
        'post_status' => 'publish'
    );

    $query = new WP_Query($args);
    $items_to_translate = array();

    foreach ($query->posts as $post) {
        // Check if translation already exists
        $translation_id = pll_get_post($post->ID, $this->target_lang);

        if (!$translation_id) {
            $items_to_translate[] = $post;
        }
    }

    return $items_to_translate;
}

/**
 * Translate a single item
 */
private function translate_item($post) {
    echo "Translating: {$post->post_title} (ID: {$post->ID})\n";

    // Prepare content for translation
    $content_to_translate = array(
        'title' => $post->post_title,
        'content' => $post->post_content,
        'excerpt' => $post->post_excerpt
    );

    // Translate using AI
    $translated = $this->translate_with_ai($content_to_translate);

    if (!$translated) {
        echo "Error: Translation failed for post ID {$post->ID}\n";
        return false;
    }

    // Create translated post
    $new_post_id = $this->create_translated_post($post, $translated);

    if ($new_post_id) {
        // Link posts in Polylang
        $this->link_translations($post->ID, $new_post_id);

        // Translate post meta
        $this->translate_post_meta($post->ID, $new_post_id);

        // Translate taxonomies
        $this->translate_taxonomies($post->ID, $new_post_id);

        echo "Success: Created translation with ID {$new_post_id}\n";
        return true;
    }

    return false;
}

/**
 * Translate content using Claude AI
 */
private function translate_with_ai($content) {
    $prompt = $this->build_translation_prompt($content);

    $data = array(
        'model' => 'claude-sonnet-4-20250514',
        'max_tokens' => 4096,
        'messages' => array(
            array(
                'role' => 'user',
                'content' => $prompt
            )
        )
    );

    $ch = curl_init('https://api.anthropic.com/v1/messages');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
    curl_setopt($ch, CURLOPT_HTTPHEADER, array(
        'Content-Type: application/json',
        'x-api-key: ' . $this->api_key,
        'anthropic-version: 2023-06-01'
    ));

    $response = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($http_code !== 200) {
        echo "API Error: HTTP {$http_code}\n";
        return false;
    }

    $result = json_decode($response, true);

    if (isset($result['content'][0]['text'])) {
        return $this->parse_translation_response($result['content'][0]['text']);
    }

    return false;
}

/**
 * Build translation prompt
 */
private function build_translation_prompt($content) {
    $target_lang_name = $this->get_language_name($this->target_lang);

    $prompt = "Translate the following WordPress post content to {$target_lang_name}. ";
    $prompt .= "Maintain all HTML tags and formatting. Provide the translation in JSON format.\n\n";
    $prompt .= "Original content:\n";
    $prompt .= json_encode($content, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
    $prompt .= "\n\nRespond with ONLY a JSON object with keys: title, content, excerpt";

    return $prompt;
}

/**
 * Parse AI translation response
 */
private function parse_translation_response($response) {
    // Remove markdown code blocks if present
    $response = preg_replace('/```json\s*|\s*```/', '', $response);
    $response = trim($response);

    $decoded = json_decode($response, true);

    if (json_last_error() === JSON_ERROR_NONE) {
        return $decoded;
    }

    echo "JSON Parse Error: " . json_last_error_msg() . "\n";
    return false;
}

/**
 * Create translated post in WordPress
 */
private function create_translated_post($original_post, $translated_content) {
    $new_post = array(
        'post_title' => $translated_content['title'],
        'post_content' => $translated_content['content'],
        'post_excerpt' => $translated_content['excerpt'],
        'post_status' => 'publish',
        'post_type' => $original_post->post_type,
        'post_author' => $original_post->post_author,
        'post_date' => $original_post->post_date,
        'post_date_gmt' => $original_post->post_date_gmt,
        'menu_order' => $original_post->menu_order,
        'post_parent' => $original_post->post_parent
    );

    $new_post_id = wp_insert_post($new_post);

    if ($new_post_id && !is_wp_error($new_post_id)) {
        // Set language for new post
        pll_set_post_language($new_post_id, $this->target_lang);
        return $new_post_id;
    }

    return false;
}

/**
 * Link original and translated posts in Polylang
 */
private function link_translations($original_id, $translation_id) {
    $translations = pll_get_post_translations($original_id);
    $translations[$this->target_lang] = $translation_id;
    pll_save_post_translations($translations);
}

/**
 * Translate post meta fields
 */
private function translate_post_meta($original_id, $translation_id) {
    // Define meta fields that should be translated
    $translatable_meta = array('_yoast_wpseo_metadesc', '_yoast_wpseo_title');

    foreach ($translatable_meta as $meta_key) {
        $meta_value = get_post_meta($original_id, $meta_key, true);

        if (!empty($meta_value)) {
            $translated_meta = $this->translate_with_ai(array('text' => $meta_value));

            if ($translated_meta && isset($translated_meta['text'])) {
                update_post_meta($translation_id, $meta_key, $translated_meta['text']);
            }
        }
    }

    // Copy non-translatable meta
    $non_translatable_meta = array('_thumbnail_id');

    foreach ($non_translatable_meta as $meta_key) {
        $meta_value = get_post_meta($original_id, $meta_key, true);

        if (!empty($meta_value)) {
            update_post_meta($translation_id, $meta_key, $meta_value);
        }
    }
}

/**
 * Translate and assign taxonomies
 */
private function translate_taxonomies($original_id, $translation_id) {
    $taxonomies = get_object_taxonomies($this->content_type);

    foreach ($taxonomies as $taxonomy) {
        $terms = wp_get_post_terms($original_id, $taxonomy);
        $translated_term_ids = array();

        foreach ($terms as $term) {
            $translated_term_id = pll_get_term($term->term_id, $this->target_lang);

            if (!$translated_term_id) {
                // Create translated term if it doesn't exist
                $translated_term_id = $this->create_translated_term($term, $taxonomy);
            }

            if ($translated_term_id) {
                $translated_term_ids[] = $translated_term_id;
            }
        }

        if (!empty($translated_term_ids)) {
            wp_set_post_terms($translation_id, $translated_term_ids, $taxonomy);
        }
    }
}

/**
 * Create translated taxonomy term
 */
private function create_translated_term($original_term, $taxonomy) {
    $translated = $this->translate_with_ai(array(
        'name' => $original_term->name,
        'description' => $original_term->description
    ));

    if (!$translated) {
        return false;
    }

    $new_term = wp_insert_term(
        $translated['name'],
        $taxonomy,
        array('description' => $translated['description'])
    );

    if (!is_wp_error($new_term)) {
        pll_set_term_language($new_term['term_id'], $this->target_lang);

        // Link terms
        $translations = pll_get_term_translations($original_term->term_id);
        $translations[$this->target_lang] = $new_term['term_id'];
        pll_save_term_translations($translations);

        return $new_term['term_id'];
    }

    return false;
}

/**
 * Get language name from code
 */
private function get_language_name($code) {
    $languages = array(
        'en' => 'English',
        'zh-TW' => 'Traditional Chinese',
        'zh-CN' => 'Simplified Chinese',
        'ja' => 'Japanese',
        'ko' => 'Korean',
        'es' => 'Spanish',
        'fr' => 'French',
        'de' => 'German'
    );

    return isset($languages[$code]) ? $languages[$code] : $code;
}

}

// CLI execution
if (php_sapi_name() === ‘cli’) {
$options = getopt(”, array(‘source:’, ‘target:’, ‘type::’));

if (!isset($options['source']) || !isset($options['target'])) {
    echo "Usage: php polylang-translator.php --source=en --target=zh-TW [--type=post]\n";
    exit(1);
}

$source = $options['source'];
$target = $options['target'];
$type = isset($options['type']) ? $options['type'] : 'post';

$translator = new PolylangAITranslator($source, $target, $type);
$translator->run();

}

Polylang AI Auto-Translator Setup Guide

Prerequisites

  1. WordPress installation with Polylang plugin activated
  2. PHP 7.4 or higher with cURL extension
  3. Anthropic API key (Claude AI)
  4. Command line access to your WordPress installation

Installation Steps

1. Save the Main Script

Save polylang-translator.php to your WordPress root directory.

2. Set API Key

Set your Anthropic API key as an environment variable:

export ANTHROPIC_API_KEY='your-api-key-here'

Or add it to your .bashrc or .zshrc:

echo 'export ANTHROPIC_API_KEY="your-api-key-here"' >> ~/.bashrc
source ~/.bashrc

3. Create Configuration File (Optional)

Create translator-config.php in your WordPress root:

<?php
/**
 * Polylang Translator Configuration
 */

return array(
    // API Settings
    'api_key' => getenv('ANTHROPIC_API_KEY'),
    'api_model' => 'claude-sonnet-4-20250514',
    'max_tokens' => 4096,
    
    // Translation Settings
    'batch_size' => 5,
    'rate_limit_delay' => 1, // seconds
    
    // Content Types to Translate
    'post_types' => array('post', 'page', 'product'),
    
    // Meta Fields to Translate
    'translatable_meta' => array(
        '_yoast_wpseo_title',
        '_yoast_wpseo_metadesc',
        'custom_field_name'
    ),
    
    // Meta Fields to Copy (not translate)
    'copy_meta' => array(
        '_thumbnail_id',
        '_product_image_gallery'
    ),
    
    // Language Pairs
    'languages' => array(
        'en' => 'English',
        'zh-TW' => 'Traditional Chinese',
        'zh-CN' => 'Simplified Chinese',
        'ja' => 'Japanese',
        'ko' => 'Korean'
    )
);

Usage

Basic Translation

Translate posts from English to Traditional Chinese:

php polylang-translator.php --source=en --target=zh-TW --type=post

Translate Pages

php polylang-translator.php --source=en --target=zh-TW --type=page

Translate Custom Post Types

php polylang-translator.php --source=en --target=ja --type=product

Advanced Usage

Batch Translation Script

Create batch-translate.sh for multiple language pairs:

#!/bin/bash

# Translate to multiple languages
languages=("zh-TW" "ja" "ko" "es")

for lang in "${languages[@]}"
do
    echo "Translating to $lang..."
    php polylang-translator.php --source=en --target=$lang --type=post
    php polylang-translator.php --source=en --target=$lang --type=page
done

echo "All translations completed!"

Make it executable:

chmod +x batch-translate.sh
./batch-translate.sh

WordPress Cron Integration

Add to your theme’s functions.php:

// Schedule automatic translation
add_action('wp', 'schedule_auto_translation');

function schedule_auto_translation() {
    if (!wp_next_scheduled('auto_translate_content')) {
        wp_schedule_event(time(), 'daily', 'auto_translate_content');
    }
}

add_action('auto_translate_content', 'run_auto_translation');

function run_auto_translation() {
    $command = 'cd ' . ABSPATH . ' && php polylang-translator.php --source=en --target=zh-TW --type=post';
    exec($command);
}

Monitoring and Logging

Create translator-log.php:

<?php
class TranslatorLogger {
    private $log_file;
    
    public function __construct() {
        $this->log_file = __DIR__ . '/translation-log.txt';
    }
    
    public function log($message) {
        $timestamp = date('Y-m-d H:i:s');
        $entry = "[{$timestamp}] {$message}\n";
        file_put_contents($this->log_file, $entry, FILE_APPEND);
    }
    
    public function get_stats() {
        if (!file_exists($this->log_file)) {
            return array();
        }
        
        $content = file_get_contents($this->log_file);
        $success = substr_count($content, 'Success:');
        $errors = substr_count($content, 'Error:');
        
        return array(
            'total_translations' => $success,
            'errors' => $errors,
            'success_rate' => $success > 0 ? ($success / ($success + $errors)) * 100 : 0
        );
    }
}

Troubleshooting

Common Issues

  1. “Polylang is not installed or activated”
    • Ensure Polylang plugin is active
    • Check if pll_get_post_language() function exists
  2. API Rate Limits
    • Increase rate_limit_delay in config
    • Reduce batch_size
  3. Translation Quality Issues
    • Adjust the translation prompt in build_translation_prompt()
    • Consider using Claude Opus for better quality
  4. Memory Issues
    • Process in smaller batches
    • Increase PHP memory limit: php -d memory_limit=512M polylang-translator.php

Debug Mode

Add to the script for verbose output:

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);

Best Practices

  1. Backup First: Always backup your database before running translations
  2. Test on Staging: Test the script on a staging environment first
  3. Review Translations: Manually review AI translations for accuracy
  4. Rate Limiting: Respect API rate limits to avoid throttling
  5. Language Context: Provide context in prompts for better translations
  6. SEO Meta: Always translate SEO meta fields for better search visibility

Cost Estimation

Claude Sonnet pricing (approximate):

  • Input: $3 per million tokens
  • Output: $15 per million tokens

Average post (1000 words):

  • ~1500 input tokens
  • ~2000 output tokens
  • Cost: ~$0.03-0.05 per post

For 100 posts: ~$3-5

Security Considerations

  1. Store API keys in environment variables, never in code
  2. Restrict file permissions: chmod 600 polylang-translator.php
  3. Use HTTPS for API calls
  4. Validate and sanitize all inputs
  5. Limit execution to authorized users only

Support

For issues or improvements, check:

  • Polylang documentation: https://polylang.pro/doc/
  • Claude API docs: https://docs.anthropic.com/
  • WordPress Codex: https://codex.wordpress.org/

×
如何用claude的api来自动翻译通过polylang

如何用claude的api来自动翻译通过polylang

<?php/** Polylang...

查看更多

AI agent 如何翻译网站(标签+动态内容)

先让AI把网站进行i18n化, …