Powrót do bloga
Maven coordinates for the PolyLingo Java SDK alongside a short Java client setup snippet.

Tłumaczenie treści strukturalnych z Javy za pomocą PolyLingo SDK

By Robert

Tłumaczenie ustrukturyzowanej zawartości z Java za pomocą PolyLingo SDK

PolyLingo Java SDK jest teraz dostępne w Maven Central. Obejmuje pełne API PolyLingo: tłumaczenie synchroniczne, żądania wsadowe, zadania asynchroniczne z pollingiem oraz wszystkie punkty końcowe narzędziowe. Wymaga Java 11 lub nowszej, używa standardowego klienta HTTP z biblioteki standardowej i ma dokładnie jedną zależność w czasie wykonywania: Jackson do JSON.


Instalacja

Maven

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

Gradle

implementation 'com.usepolylingo:polylingo:0.1.0'

Nie jest wymagana dodatkowa zależność klienta HTTP. SDK używa java.net.http.HttpClient z biblioteki standardowej Java 11.


Konfiguracja klienta

import com.usepolylingo.polylingo.PolyLingo;
 
PolyLingo client = PolyLingo.builder()
    .apiKey(System.getenv("POLYLINGO_API_KEY"))
    .build();

Dostępne są dwa opcjonalne parametry buildera:

PolyLingo client = PolyLingo.builder()
    .apiKey(System.getenv("POLYLINGO_API_KEY"))
    .baseUrl("https://api.usepolylingo.com/v1") // domyślny, nadpisz dla instancji self-hosted
    .timeout(Duration.ofSeconds(30))            // domyślnie 120 sekund
    .build();

Przechowuj swój klucz API w zmiennej środowiskowej. Nigdy nie koduj go na stałe ani nie zatwierdzaj do kontroli wersji.

SDK używa wzorca buildera w całym kodzie. Brak konstruktorów pozycyjnych, brak wymaganego porządku pól. Wszystkie pola opcjonalne mają sensowne wartości domyślne, więc konfigurujesz tylko to, co faktycznie chcesz zmienić.


Tłumaczenie zawartości

Pojedyncze żądanie

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!

Builder TranslateParams akceptuje content i targets jako pola wymagane. Parametry opcjonalne to format (plain, markdown, json lub html — wykrywany automatycznie, jeśli pominięty), source jako wskazówka językowa oraz model jako standard (domyślny) lub advanced.

Zachowanie formatu działa tak samo jak w reszcie API PolyLingo. Dla zawartości json tłumaczone są tylko wartości tekstowe, a klucze, zagnieżdżenia i typy niebędące tekstem pozostają nietknięte. Dla markdown nagłówki pozostają nagłówkami, a bloki kodu są pozostawione dosłownie. Dla html tagi i atrybuty są zachowane, a tłumaczone są tylko węzły tekstowe.

Tłumaczenie pliku locale 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);
    }
});

Jedno żądanie obsługuje wszystkie trzy locale. Klucze są identyczne jak w źródle w każdym pliku wyjściowym.


Żądania wsadowe

Wyślij do 100 elementów zawartości w jednym żądaniu, każdy z własnym id i opcjonalnym 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());
}

Wszystkie elementy dzielą tę samą listę targets. Przypisane id jest zachowywane w odpowiedzi, dzięki czemu możesz mapować wyniki z powrotem do swoich danych źródłowych bez polegania na kolejności.


Zadania asynchroniczne

Dla długich dokumentów lub dużych obciążeń tłumaczeniowych API zadań przyjmuje żądanie, zwraca natychmiast identyfikator zadania i pozwala na polling wyniku. SDK obsługuje to na dwa sposoby.

Jedno wywołanie, które polluje aż do zakończenia

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) + "...")
);

Callback onProgress wywoływany jest przy każdym pollingu z aktualną pozycją w kolejce jako liczbą całkowitą lub null, jeśli API jej nie zwraca. Użyj go do logowania postępu lub aktualizacji interfejsu użytkownika.

Kolejkowanie i polling ręczny

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()
);
 
// Polluj samodzielnie
Job status = client.jobs().get(job.getJobId());
System.out.println(status.getStatus()); // pending / processing / completed / failed

Punkty końcowe narzędziowe

// Sprawdź stan API (nie wymaga klucza API)
HealthResponse health = client.health();
System.out.println(health.getStatus()); // "ok"
 
// Lista obsługiwanych języków (nie wymaga klucza API)
LanguagesResponse langs = client.languages();
langs.getLanguages().forEach(l ->
    System.out.println(l.getCode() + " — " + l.getName())
);
 
// Sprawdź użycie tokenów za bieżący miesiąc rozliczeniowy
UsageResponse usage = client.usage();
System.out.println("Tokens used: " + usage.getUsage().getTokensUsed());
System.out.println("Tokens remaining: " + usage.getUsage().getTokensRemaining());

Obsługa błędów

Wszystkie wyjątki są unchecked. Brak wymuszonych deklaracji throws, brak łańcuchów wyjątków do rozwinięcia:

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 — nieprawidłowy, brakujący lub cofnięty klucz API
    System.out.println("Auth failed: " + e.getError());
} catch (RateLimitException e) {
    // HTTP 429 — osiągnięto limit na minutę
    e.getRetryAfter().ifPresent(s ->
        System.out.println("Retry after: " + s + "s")
    );
} catch (JobFailedException e) {
    // Zadanie async osiągnęło stan końcowy z błędem lub polling przekroczył limit czasu
    System.out.println("Job " + e.getJobId() + " failed: " + e.getError());
} catch (PolyLingoException e) {
    // Wszystkie inne błędy API
    System.out.println(e.getStatus() + ": " + e.getMessage());
}

RateLimitException.getRetryAfter() zwraca Optional<Integer> — obecny z liczbą sekund do odczekania, jeśli API zawiera tę wartość, pusty w przeciwnym razie. JobFailedException.getJobId() zwraca ID nieudanego zadania do logowania lub logiki ponownej próby.


Notatki projektowe

Kilka decyzji wartych poznania, jeśli oceniasz SDK:

Synchroniczne API. Każda metoda blokuje i zwraca wynik bezpośrednio. Brak Future, brak CompletableFuture, brak reaktywnych strumieni. Polling zadań to async historia SDK dla dużych obciążeń — wyślij zadanie, SDK polluje na twoim wątku i wywołuje twój callback onProgress gdy pozycja w kolejce się zmienia.

Wzorzec buildera wszędzie. Każdy obiekt parametrów używa buildera. Brak konstruktorów pozycyjnych oznacza brak zgadywania kolejności argumentów, brak przypadkowej zamiany pól i czytelny kod w miejscu wywołania.

Jedna zależność runtime. Jackson do serializacji JSON. Wszystko inne to biblioteka standardowa. Brak OkHttp, brak Apache HttpClient, brak Guava.

Java 11+. Używa java.net.http.HttpClient wprowadzonego w Java 11. Jeśli twój projekt celuje w Java 8 lub starszą, SDK nie jest kompatybilne.


Szybkie odniesienie

MetodaEndpointWymaga autoryzacji
client.health()GET /healthNie
client.languages()GET /languagesNie
client.translate(...)POST /translateTak
client.batch(...)POST /translate/batchTak
client.usage()GET /usageTak
client.jobs().create(...)POST /jobsTak
client.jobs().get(jobId)GET /jobs/:idTak
client.jobs().translate(...)POST /jobs + pollingTak

Rozpocznij

SDK jest dostępne w Maven Central pod adresem central.sonatype.com/artifact/com.usepolylingo/polylingo. Kod źródłowy i Javadoc są na github.com/UsePolyLingo/polylingo-Java. Pełna dokumentacja API jest na usepolylingo.com/docs/sdk/java.

Darmowy poziom obejmuje 50 000 tokenów miesięcznie. Nie jest wymagana karta kredytowa.

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

Pobierz swój klucz API

Tłumaczenie treści strukturalnych z Javy za pomocą PolyLingo SDK | PolyLingo