Назад в блог
Terminal window showing a Composer install command for the PolyLingo PHP SDK alongside a short PHP translate call and its JSON output.

Перевод структурированного контента из PHP с помощью PolyLingo SDK

By Robert M

Перевод структурированного контента из PHP с помощью PolyLingo SDK

SDK PolyLingo для PHP теперь доступен на Packagist. Установите его через Composer, передайте строку с обычным текстом, Markdown, JSON или HTML и получите переводы на все нужные вам языки — без написания сырого HTTP-запроса и без опасений, что структура будет повреждена при передаче.

В этом посте рассматриваются установка, аутентификация и полный функционал SDK: синхронный перевод, пакетные запросы, асинхронные задания и обработка ошибок.


Установка

Требуется PHP 7.4 или новее. Установите через Composer:

composer require usepolylingo/polylingo

SDK зависит от guzzlehttp/guzzle ^7.8 и psr/http-client ^1.0. Оба устанавливаются автоматически.


Настройка клиента

Создайте один экземпляр PolyLingo и используйте его во всем приложении. Единственный обязательный параметр — ваш API-ключ:

<?php
use PolyLingo\PolyLingo;

$client = new PolyLingo([
    'apiKey' => getenv('POLYLINGO_API_KEY'),
]);

Храните API-ключ в переменной окружения. Никогда не прописывайте его напрямую в коде и не коммитьте в систему контроля версий.

Два дополнительных параметра, о которых стоит знать:

$client = new PolyLingo([
    'apiKey'  => getenv('POLYLINGO_API_KEY'),
    'baseURL' => 'https://api.usepolylingo.com/v1', // по умолчанию, измените для собственных инстансов
    'timeout' => 120_000,                           // миллисекунды, по умолчанию 120000 (2 минуты)
]);

Перевод контента

Обычный текст, Markdown, JSON или HTML

Передайте содержимое и массив кодов целевых языков в метод translate(). Поле format сообщает SDK, с каким типом контента он работает:

$result = $client->translate([
    'content' => '# Привет',
    'targets' => ['es', 'fr', 'de'],
    'format'  => 'markdown',
]);

$es     = $result['translations']['es'];
$tokens = $result['usage']['total_tokens'];

Опция format принимает значения plain, markdown, json или html. Если её не указать, API автоматически определит формат по содержимому. Также можно передать подсказку source с исходным языком и значение modelstandard (по умолчанию) или advanced.

Сохранение формата — ключевое поведение. Для json переводятся только строковые значения. Ключи, вложенность, массивы и нестроковые типы возвращаются без изменений. Для markdown заголовки остаются заголовками, блоки кода не меняются, URL ссылок не трогаются. Для html теги и атрибуты сохраняются, переводятся только текстовые узлы.

Перевод JSON-файла локализации

Распространённый случай — перевод файла локализации. Отправьте весь объект в виде JSON-строки:

$source = json_decode(file_get_contents('messages/en.json'), true);

$result = $client->translate([
    'content' => json_encode($source),
    'format'  => 'json',
    'targets' => ['de', 'fr', 'ja'],
]);

foreach (['de', 'fr', 'ja'] as $locale) {
    $translated = json_decode($result['translations'][$locale], true);
    file_put_contents(
        "messages/{$locale}.json",
        json_encode($translated, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) . "\n"
    );
}

Один запрос обрабатывает все три локали. Ключи в выходных файлах не изменяются.


Пакетные запросы

Используйте batch(), когда нужно перевести несколько отдельных элементов контента. Можно отправить до 100 элементов в одном запросе, у каждого может быть свой id и опциональный format:

$batch = $client->batch([
    'items' => [
        ['id' => 'hero_title',    'content' => 'С возвращением',              'format' => 'plain'],
        ['id' => 'hero_subtitle', 'content' => 'Вот что нового сегодня',     'format' => 'plain'],
        ['id' => 'cta',           'content' => 'Начать',                     'format' => 'plain'],
    ],
    'targets' => ['es', 'fr'],
]);

foreach ($batch['results'] as $row) {
    echo $row['id'] . ': ' . $row['translations']['es'] . "\n";
}

Все элементы используют один и тот же массив targets. Ответ сохраняет id для каждого элемента, чтобы вы могли сопоставить результаты с исходными данными без зависимости от порядка.


Асинхронные задания

Для длительных переводов (большие документы, много целей или и то, и другое) API заданий принимает запрос, сразу возвращает job_id и позволяет опрашивать результат. SDK поддерживает два способа работы с этим.

Добавить в очередь и опрашивать вручную

$accepted = $client->jobs->create([
    'content' => file_get_contents('long-article.md'),
    'targets' => ['es', 'fr', 'de', 'ja', 'zh'],
    'format'  => 'markdown',
]);

$jobId = $accepted['job_id'];

// Опрашиваем, пока задание не завершится
do {
    sleep(5);
    $state = $client->jobs->get($jobId);
} while ($state['status'] === 'pending' || $state['status'] === 'processing');

if ($state['status'] === 'complete') {
    $translations = $state['translations'];
}

Один вызов с опросом до завершения

Если не нужен ручной контроль, jobs->translate() сам управляет циклом опроса:

$done = $client->jobs->translate([
    'content' => file_get_contents('long-article.md'),
    'targets' => ['es', 'fr', 'de'],
    'format'  => 'markdown',

    // Опциональные переопределения (показаны по умолчанию):
    // 'pollInterval' => 5000,       // мс между опросами, по умолчанию 5000
    // 'timeout'      => 1_200_000,  // общий лимит ожидания, по умолчанию 20 минут
    // 'onProgress'   => function (?int $queuePosition) {
    //     echo "Позиция в очереди: {$queuePosition}\n";
    // },
]);

$translations = $done['translations'];
$usage        = $done['usage'];

Колбэк onProgress вызывается при каждом опросе с текущей позицией в очереди, если API её возвращает, или null, если нет. Используйте для логирования прогресса или обновления интерфейса.


Утилитные эндпоинты

Три лёгких эндпоинта не требуют параметров, кроме аутентификации:

$health = $client->health();
// ['status' => 'ok', 'timestamp' => '...']

$langs = $client->languages();
// ['languages' => [['code' => 'en', 'name' => 'English', 'rtl' => false], ...]]

$usage = $client->usage();
// ['usage' => ['tokens_used' => 12000, 'tokens_remaining' => 88000, ...]]

GET /health и GET /languages не требуют API-ключа. GET /usage возвращает использование токенов за текущий календарный месяц для аутентифицированного аккаунта.


Обработка ошибок

Все ошибки SDK наследуются от PolyLingo\Errors\PolyLingoException. Обрабатывайте конкретные подтипы, если хотите различать ошибки:

use PolyLingo\Errors\AuthException;
use PolyLingo\Errors\JobFailedException;
use PolyLingo\Errors\PolyLingoException;
use PolyLingo\Errors\RateLimitException;

try {
    $result = $client->translate([
        'content' => '# Привет',
        'targets' => ['es'],
        'format'  => 'markdown',
    ]);
} catch (AuthException $e) {
    // HTTP 401 — неверный, отсутствующий или отозванный API-ключ
} catch (RateLimitException $e) {
    // HTTP 429 — достигнут лимит запросов в минуту
    $retryAfter = $e->getRetryAfter(); // int|null секунд
} catch (JobFailedException $e) {
    // Асинхронное задание завершилось с ошибкой
    $jobId = $e->getJobId();
} catch (PolyLingoException $e) {
    // Все остальные ошибки API
    $httpStatus = $e->getHttpStatus();
    $errorCode  = $e->getErrorCode(); // например, "invalid_request", "translation_error"
}

RateLimitException::getRetryAfter() возвращает количество секунд, которое нужно подождать перед повторной попыткой, если заголовок присутствует, или null, если нет. JobFailedException::getJobId() возвращает ID неудавшегося задания, чтобы вы могли его залогировать или показать пользователю.


Быстрая справка

МетодЭндпоинтТребуется аутентификация
$client->health()GET /healthНет
$client->languages()GET /languagesНет
$client->translate()POST /translateДа
$client->batch()POST /translate/batchДа
$client->usage()GET /usageДа
$client->jobs->create()POST /jobsДа
$client->jobs->get($id)GET /jobs/:idДа
$client->jobs->translate()POST /jobs + опросДа

Начало работы

SDK доступен на Packagist по адресу usepolylingo/polylingo. Полная документация API — на usepolylingo.com/docs.

Бесплатный тариф включает 50 000 токенов в месяц. Кредитная карта не требуется.

composer require usepolylingo/polylingo

Получите ваш API-ключ