Volver al blog
Maven coordinates for the PolyLingo Java SDK alongside a short Java client setup snippet.

Traducir contenido estructurado desde Java con el SDK de PolyLingo

By Robert

Traducir contenido estructurado desde Java con el SDK PolyLingo

El SDK PolyLingo para Java ya está disponible en Maven Central. Cubre toda la API de PolyLingo: traducción síncrona, solicitudes por lotes, trabajos asíncronos con sondeo y todos los endpoints de utilidad. Requiere Java 11 o superior, usa el cliente HTTP de la biblioteca estándar y tiene exactamente una dependencia en tiempo de ejecución: Jackson para JSON.


Instalación

Maven

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

Gradle

implementation 'com.usepolylingo:polylingo:0.1.0'

No se requiere dependencia adicional para el cliente HTTP. El SDK usa java.net.http.HttpClient de la biblioteca estándar de Java 11.


Configuración del cliente

import com.usepolylingo.polylingo.PolyLingo;

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

Hay dos parámetros opcionales en el builder:

PolyLingo client = PolyLingo.builder()
    .apiKey(System.getenv("POLYLINGO_API_KEY"))
    .baseUrl("https://api.usepolylingo.com/v1") // por defecto, sobrescribir para instancias autoalojadas
    .timeout(Duration.ofSeconds(30))            // por defecto es 120 segundos
    .build();

Guarda tu clave API en una variable de entorno. Nunca la codifiques directamente ni la subas al control de versiones.

El SDK usa el patrón builder en todo momento. No hay constructores posicionales ni orden obligatorio de campos. Todos los campos opcionales tienen valores predeterminados sensatos para que solo configures lo que realmente necesitas cambiar.


Traducción de contenido

Solicitud única

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!

El builder TranslateParams acepta content y targets como campos obligatorios. Los parámetros opcionales incluyen format (plain, markdown, json o html — se detecta automáticamente si se omite), source como pista de idioma y model como standard (predeterminado) o advanced.

La preservación del formato funciona igual que en el resto de la API de PolyLingo. Para contenido json, solo se traducen los valores de cadena y las claves, anidamientos y tipos no cadena permanecen intactos. Para markdown, los encabezados permanecen encabezados y los bloques de código se mantienen tal cual. Para html, las etiquetas y atributos se preservan y solo se traducen los nodos de texto.

Traducción de un archivo JSON de localización

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);
    }
});

Una sola solicitud maneja los tres locales. Las claves son idénticas a la fuente en cada archivo de salida.


Solicitudes por lotes

Envía hasta 100 elementos de contenido en una sola solicitud, cada uno con su propio id y format opcional:

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());
}

Todos los elementos comparten la misma lista targets. El id que asignas se conserva en la respuesta para que puedas mapear los resultados a tus datos fuente sin depender del orden.


Trabajos asíncronos

Para documentos largos o grandes cargas de traducción, la API de trabajos acepta una solicitud, devuelve inmediatamente un ID de trabajo y te permite hacer polling para obtener el resultado. El SDK lo maneja de dos maneras.

Una llamada que hace polling hasta que termina

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

El callback onProgress se dispara en cada polling con la posición actual en la cola como entero, o null si la API no devuelve uno. Úsalo para registrar el progreso o actualizar una interfaz de usuario.

Encolar y hacer polling manualmente

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()
);

// Haz polling tú mismo
Job status = client.jobs().get(job.getJobId());
System.out.println(status.getStatus()); // pending / processing / completed / failed

Endpoints de utilidad

// Comprobar salud de la API (no requiere clave API)
HealthResponse health = client.health();
System.out.println(health.getStatus()); // "ok"

// Listar idiomas soportados (no requiere clave API)
LanguagesResponse langs = client.languages();
langs.getLanguages().forEach(l ->
    System.out.println(l.getCode() + " — " + l.getName())
);

// Comprobar uso de tokens para el mes de facturación actual
UsageResponse usage = client.usage();
System.out.println("Tokens usados: " + usage.getUsage().getTokensUsed());
System.out.println("Tokens restantes: " + usage.getUsage().getTokensRemaining());

Manejo de errores

Todas las excepciones son unchecked. Sin declaraciones forzadas de throws, sin cadenas de excepciones checked para desenrollar:

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 — clave API inválida, ausente o revocada
    System.out.println("Auth failed: " + e.getError());
} catch (RateLimitException e) {
    // HTTP 429 — límite por minuto alcanzado
    e.getRetryAfter().ifPresent(s ->
        System.out.println("Retry after: " + s + "s")
    );
} catch (JobFailedException e) {
    // Trabajo asíncrono alcanzó estado terminal fallido o el polling expiró
    System.out.println("Job " + e.getJobId() + " failed: " + e.getError());
} catch (PolyLingoException e) {
    // Todos los demás errores de API
    System.out.println(e.getStatus() + ": " + e.getMessage());
}

RateLimitException.getRetryAfter() devuelve un Optional<Integer> — presente con el número de segundos a esperar si la API incluye ese valor, vacío de lo contrario. JobFailedException.getJobId() te da el ID del trabajo fallido para registro o lógica de reintento.


Notas de diseño

Algunas decisiones que vale la pena conocer si evalúas el SDK:

API síncrona. Cada método bloquea y devuelve un resultado directamente. Sin Future, sin CompletableFuture, sin streams reactivos. El polling de trabajos es la solución asíncrona del SDK para cargas pesadas — envía el trabajo, el SDK hace polling en tu hilo y llama a tu callback onProgress conforme se actualiza la posición en la cola.

Patrón builder en todo. Cada objeto de parámetros usa un builder. Sin constructores posicionales significa sin adivinar el orden de argumentos, sin intercambios accidentales de campos y código claro en el sitio de llamada.

Una dependencia en tiempo de ejecución. Jackson para serialización JSON. Todo lo demás es biblioteca estándar. Sin OkHttp, sin Apache HttpClient, sin Guava.

Java 11+. Usa java.net.http.HttpClient introducido en Java 11. Si tu proyecto apunta a Java 8 o anterior, el SDK no es compatible.


Referencia rápida

MétodoEndpointRequiere Auth
client.health()GET /healthNo
client.languages()GET /languagesNo
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 + polling

Comenzar

El SDK está en Maven Central en central.sonatype.com/artifact/com.usepolylingo/polylingo. El código fuente y Javadoc están en github.com/UsePolyLingo/polylingo-Java. La documentación completa del API está en usepolylingo.com/docs/sdk/java.

El nivel gratuito incluye 50,000 tokens por mes. No se requiere tarjeta de crédito.

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

Obtén tu clave API