ブログに戻る
Maven coordinates for the PolyLingo Java SDK alongside a short Java client setup snippet.

PolyLingo SDKを使ってJavaから構造化コンテンツを翻訳する

By Robert

PolyLingo SDKを使ったJavaからの構造化コンテンツの翻訳

PolyLingo Java SDKは現在Maven Centralで利用可能です。同期翻訳、バッチリクエスト、ポーリング付き非同期ジョブ、すべてのユーティリティエンドポイントを含む完全なPolyLingo APIをカバーしています。Java 11以降が必要で、標準ライブラリのHTTPクライアントを使用し、ランタイム依存はJSON用のJacksonが1つだけです。


インストール

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 11標準ライブラリのjava.net.http.HttpClientを使用します。


クライアントのセットアップ

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

オプションのビルダーパラメータが2つあります:

PolyLingo client = PolyLingo.builder()
    .apiKey(System.getenv("POLYLINGO_API_KEY"))
    .baseUrl("https://api.usepolylingo.com/v1") // デフォルト。セルフホスト環境用に上書き可能
    .timeout(Duration.ofSeconds(30))            // デフォルトは120秒
    .build();

APIキーは環境変数に保存してください。コードにハードコーディングしたりバージョン管理にコミットしたりしないでください。

SDKはビルダーパターンを全面的に採用しています。位置引数のコンストラクタはなく、必須フィールドの順序もありません。すべてのオプションフィールドには妥当なデフォルトがあるため、変更が必要な部分だけ設定すればよいです。


コンテンツの翻訳

単一リクエスト

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ビルダーはcontenttargetsを必須フィールドとして受け入れます。オプションパラメータにはformatplainmarkdownjsonhtmlのいずれか。省略時は自動検出)、言語ヒントとしてのsourcestandard(デフォルト)またはadvancedmodelがあります。

フォーマットの保持は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);
    }
});

1つのリクエストで3つのロケールすべてを処理します。すべての出力ファイルでキーはソースと同一です。


バッチリクエスト

1回のリクエストで最大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はこれを2つの方法で扱います。

完了までポーリングする1回の呼び出し

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コールバックは各ポーリング時に現在のキュー位置(整数)で呼ばれます。APIが返さない場合はnullです。進捗のログやUIの更新に使います。

手動でキューに入れてポーリング

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

エラーハンドリング

すべての例外はチェックされません。強制的なthrows宣言もなく、チェック例外のチェーンを解く必要もありません:

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 — 1分あたりの制限に達した
    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。 すべてのメソッドはブロックし、結果を直接返します。FutureCompletableFutureもリアクティブストリームもありません。ジョブのポーリングが重い負荷向けのSDKの非同期機能です — ジョブを送信し、SDKがスレッド上でポーリングし、キュー位置の更新に応じてonProgressコールバックを呼びます。

ビルダーパターンを全面採用。 すべてのパラメータオブジェクトはビルダーを使います。位置引数のコンストラクタがないため、引数の順序を推測する必要がなく、フィールドの入れ替えミスもなく、呼び出し元のコードが明確です。

ランタイム依存は1つだけ。 JSONシリアライズ用のJackson。その他は標準ライブラリのみ。OkHttp、Apache HttpClient、Guavaは使いません。

Java 11以上。 Java 11で導入されたjava.net.http.HttpClientを使用。プロジェクトが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キーを取得する