Повернутися до блогу
Maven coordinates for the PolyLingo Java SDK alongside a short Java client setup snippet.

Переклад структурованого контенту з Java за допомогою PolyLingo SDK

By Robert

Переклад структурованого контенту з Java за допомогою PolyLingo SDK

PolyLingo Java SDK тепер доступний на Maven Central. Він охоплює повний PolyLingo API: синхронний переклад, пакетні запити, асинхронні завдання з опитуванням та всі допоміжні кінцеві точки. Потрібен Java 11 або новіший, використовується стандартний HTTP-клієнт бібліотеки, і є лише одна залежність часу виконання: Jackson для JSON.


Встановлення

Maven

<dependency>
  <groupId>com.usepolylingo</groupId>
  <artifactId>polylingo</artifactId>
  <version>0.1.0</version>
</dependency>

Gradle

implementation 'com.usepolylingo:polylingo:0.1.0'

Додаткові залежності HTTP-клієнта не потрібні. SDK використовує java.net.http.HttpClient зі стандартної бібліотеки Java 11.


Налаштування клієнта

import com.usepolylingo.polylingo.PolyLingo;

PolyLingo client = PolyLingo.builder()
    .apiKey(System.getenv("POLYLINGO_API_KEY"))
    .build();

Доступні два необов’язкові параметри конструктора:

PolyLingo client = PolyLingo.builder()
    .apiKey(System.getenv("POLYLINGO_API_KEY"))
    .baseUrl("https://api.usepolylingo.com/v1") // за замовчуванням, змінити для власних інстансів
    .timeout(Duration.ofSeconds(30))            // за замовчуванням 120 секунд
    .build();

Зберігайте свій API-ключ у змінній середовища. Ніколи не хардкодьте його і не комітьте у систему контролю версій.

SDK використовує патерн builder повсюди. Немає позиційних конструкторів, немає обов’язкового порядку полів. Усі необов’язкові поля мають розумні значення за замовчуванням, тож ви налаштовуєте лише те, що дійсно потрібно змінити.


Переклад контенту

Одиночний запит

import com.usepolylingo.polylingo.types.TranslateParams;
import com.usepolylingo.polylingo.types.TranslateResult;

TranslateResult result = client.translate(
    TranslateParams.builder()
        .content("Hello, world!")
        .targets(List.of("es", "fr", "de"))
        .build()
);

result.getTranslations().forEach((lang, text) ->
    System.out.println(lang + ": " + text)
);
// es: ¡Hola, mundo!
// fr: Bonjour le monde !
// de: Hallo Welt!

Конструктор TranslateParams приймає content і targets як обов’язкові поля. Необов’язкові параметри включають format (plain, markdown, json або html — автоматично визначається, якщо пропущено), source як підказку мови та model як standard (за замовчуванням) або advanced.

Збереження формату працює так само, як і в решті PolyLingo API. Для json контенту перекладаються лише рядкові значення, ключі, вкладені структури та типи, що не є рядками, залишаються без змін. Для markdown заголовки залишаються заголовками, а блоки коду залишаються без змін. Для html теги та атрибути зберігаються, перекладаються лише текстові вузли.

Переклад JSON-файлу локалі

import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.file.Files;
import java.nio.file.Path;

ObjectMapper mapper = new ObjectMapper();
String sourceJson = Files.readString(Path.of("messages/en.json"));

TranslateResult result = client.translate(
    TranslateParams.builder()
        .content(sourceJson)
        .format("json")
        .targets(List.of("fr", "de", "ja"))
        .build()
);

result.getTranslations().forEach((locale, translated) -> {
    try {
        Object parsed = mapper.readValue(translated, Object.class);
        String pretty = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(parsed);
        Files.writeString(Path.of("messages/" + locale + ".json"), pretty);
        System.out.println("Wrote messages/" + locale + ".json");
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
});

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


Пакетні запити

Надсилайте до 100 елементів контенту в одному запиті, кожен зі своїм id та необов’язковим format:

import com.usepolylingo.polylingo.types.BatchParams;
import com.usepolylingo.polylingo.types.BatchItem;
import com.usepolylingo.polylingo.types.BatchResult;

BatchResult result = client.batch(
    BatchParams.builder()
        .targets(List.of("es", "ja"))
        .addItem(BatchItem.builder().id("title").content("Welcome").build())
        .addItem(BatchItem.builder().id("body").content("Get started today.").build())
        .build()
);

for (BatchItemResult item : result.getResults()) {
    System.out.println(item.getId() + ": " + item.getTranslations());
}

Усі елементи використовують один і той же список targets. Присвоєний вами id зберігається у відповіді, щоб ви могли зіставити результати з вихідними даними без залежності від порядку.


Асинхронні завдання

Для довгих документів або великих обсягів перекладу API завдань приймає запит, повертає одразу ID завдання і дозволяє опитувати результат. SDK підтримує це двома способами.

Один виклик, що опитує до завершення

import com.usepolylingo.polylingo.types.JobsTranslateParams;

TranslateResult result = client.jobs().translate(
    JobsTranslateParams.builder()
        .content(longArticleText)
        .targets(List.of("fr", "de", "ja", "zh"))
        .pollInterval(Duration.ofSeconds(3))
        .timeout(Duration.ofMinutes(10))
        .onProgress(queuePosition ->
            System.out.println("Queue position: " + queuePosition))
        .build()
);

result.getTranslations().forEach((lang, text) ->
    System.out.println(lang + ": " + text.substring(0, 100) + "...")
);

Зворотний виклик onProgress виконується при кожному опитуванні з поточною позицією в черзі як цілим числом або null, якщо API не повертає її. Використовуйте для логування прогресу або оновлення інтерфейсу.

Відправка в чергу та опитування вручну

import com.usepolylingo.polylingo.types.CreateJobParams;
import com.usepolylingo.polylingo.types.Job;

Job job = client.jobs().create(
    CreateJobParams.builder()
        .content("Translate this.")
        .targets(List.of("es"))
        .build()
);

// Опитуйте самі
Job status = client.jobs().get(job.getJobId());
System.out.println(status.getStatus()); // pending / processing / completed / failed

Допоміжні кінцеві точки

// Перевірка стану API (API-ключ не потрібен)
HealthResponse health = client.health();
System.out.println(health.getStatus()); // "ok"

// Список підтримуваних мов (API-ключ не потрібен)
LanguagesResponse langs = client.languages();
langs.getLanguages().forEach(l ->
    System.out.println(l.getCode() + " — " + l.getName())
);

// Перевірка використання токенів за поточний платіжний місяць
UsageResponse usage = client.usage();
System.out.println("Tokens used: " + usage.getUsage().getTokensUsed());
System.out.println("Tokens remaining: " + usage.getUsage().getTokensRemaining());

Обробка помилок

Всі виключення unchecked. Немає примусових декларацій throws, немає ланцюжків checked виключень для розплутування:

import com.usepolylingo.polylingo.errors.*;

try {
    TranslateResult result = client.translate(
        TranslateParams.builder()
            .content("# Hello")
            .targets(List.of("es", "fr"))
            .format("markdown")
            .build()
    );
} catch (AuthException e) {
    // HTTP 401 — недійсний, відсутній або відкликаний API-ключ
    System.out.println("Auth failed: " + e.getError());
} catch (RateLimitException e) {
    // HTTP 429 — досягнуто ліміт за хвилину
    e.getRetryAfter().ifPresent(s ->
        System.out.println("Retry after: " + s + "s")
    );
} catch (JobFailedException e) {
    // Асинхронне завдання досягло статусу помилки або час опитування вичерпано
    System.out.println("Job " + e.getJobId() + " failed: " + e.getError());
} catch (PolyLingoException e) {
    // Всі інші помилки API
    System.out.println(e.getStatus() + ": " + e.getMessage());
}

RateLimitException.getRetryAfter() повертає Optional<Integer> — присутній із кількістю секунд очікування, якщо API включає це значення, інакше порожній. JobFailedException.getJobId() дає ID невдалого завдання для логування або логіки повторної спроби.


Примітки щодо дизайну

Декілька рішень, які варто знати, якщо ви оцінюєте SDK:

Синхронний API. Кожен метод блокує і повертає результат безпосередньо. Немає Future, CompletableFuture, реактивних потоків. Опитування завдань — це асинхронна історія SDK для великих навантажень — відправляєте завдання, SDK опитує у вашому потоці і викликає ваш зворотний виклик onProgress при оновленні позиції в черзі.

Патерн builder повсюди. Кожен об’єкт параметрів використовує builder. Відсутність позиційних конструкторів означає відсутність здогадок щодо порядку аргументів, випадкової заміни полів і чистий код у точці виклику.

Одна залежність часу виконання. Jackson для серіалізації JSON. Все інше — стандартна бібліотека. Немає OkHttp, Apache HttpClient, Guava.

Java 11+. Використовує java.net.http.HttpClient, доданий у Java 11. Якщо ваш проєкт орієнтований на Java 8 або ранішу версію, SDK не сумісний.


Швидкий довідник

МетодКінцева точкаПотрібна автентифікація
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(jobId)GET /jobs/:idТак
client.jobs().translate(...)POST /jobs + опитуванняТак

Початок роботи

SDK доступний на Maven Central за адресою central.sonatype.com/artifact/com.usepolylingo/polylingo. Вихідний код і Javadoc — на github.com/UsePolyLingo/polylingo-Java. Повна документація API — на usepolylingo.com/docs/sdk/java.

Безкоштовний рівень включає 50 000 токенів на місяць. Кредитна картка не потрібна.

<dependency>
  <groupId>com.usepolylingo</groupId>
  <artifactId>polylingo</artifactId>
  <version>0.1.0</version>
</dependency>

Отримайте свій API-ключ