Powrót do bloga
Terminal window showing a Gemfile entry for the PolyLingo gem alongside a short Ruby translate call and its output hash.

Tłumaczenie ustrukturyzowanej zawartości z Ruby za pomocą gemu PolyLingo

By Robert M

Tłumaczenie ustrukturyzowanej zawartości z Ruby za pomocą gemu PolyLingo

Gem PolyLingo Ruby jest teraz dostępny na RubyGems. Obejmuje pełny interfejs API PolyLingo: tłumaczenia synchroniczne, żądania wsadowe, zadania asynchroniczne z pollingiem oraz wszystkie punkty końcowe narzędziowe. Nie ma zależności w czasie wykonywania i wymaga Ruby 2.7 lub nowszego.

Ten wpis przeprowadza przez instalację, konfigurację klienta oraz każdą metodę dostępną w gemie.


Instalacja

Dodaj do swojego Gemfile:

gem "polylingo"

Następnie uruchom:

bundle install

Lub zainstaluj bezpośrednio:

gem install polylingo

Brak zależności w czasie wykonywania. Gem używa tylko standardowej biblioteki Ruby do HTTP.


Konfiguracja klienta

require "polylingo"

client = PolyLingo.new(api_key: ENV.fetch("POLYLINGO_API_KEY"))

Dostępne są dwie opcjonalne ustawienia:

client = PolyLingo.new(
  api_key:  ENV.fetch("POLYLINGO_API_KEY"),
  base_url: "https://api.usepolylingo.com/v1", # domyślny, nadpisz dla instancji self-hosted
  timeout:  120,                               # sekundy (otwarcie + odczyt), domyślnie 120
)

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


Tłumaczenie zawartości

Pojedyncze żądanie

Przekaż swoją zawartość, tablicę kodów języków docelowych oraz opcjonalny format:

result = client.translate(
  content: "# Hello\n\nThis is **structured** content.",
  targets: %w[es fr de],
  format:  "markdown"
)

puts result["translations"]["es"]
puts result["usage"]["total_tokens"]

Parametr format akceptuje plain, markdown, json lub html. Jeśli zostanie pominięty, API automatycznie wykrywa format. Możesz także przekazać source jako wskazówkę językową oraz model jako "standard" (domyślny) lub "advanced".

Zachowanie formatu działa tak samo jak w reszcie API PolyLingo. Dla json tłumaczone są tylko wartości typu string, a klucze, zagnieżdżenia i typy nie-string 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

require "json"

source = JSON.parse(File.read("config/locales/en.yml"))

result = client.translate(
  content: source.to_json,
  format:  "json",
  targets: %w[fr de ja]
)

%w[fr de ja].each do |locale|
  translated = JSON.parse(result["translations"][locale])
  File.write(
    "config/locales/#{locale}.json",
    JSON.pretty_generate(translated)
  )
  puts "Wrote config/locales/#{locale}.json"
end

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:

result = client.batch(
  items: [
    { id: "hero_title",    content: "Welcome back",   format: "plain" },
    { id: "hero_subtitle", content: "Here is what changed today", format: "plain" },
    { id: "cta",           content: "Get started",    format: "plain" },
  ],
  targets: %w[es fr de]
)

result["results"].each do |row|
  puts "#{row["id"]}: #{row["translations"]["es"]}"
end

Wszystkie elementy dzielą tę samą tablicę targets. Przekazane 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 tłumaczeń długotrwałych API zadań akceptuje żądanie, zwraca natychmiast job_id i pozwala na polling wyniku. Gem obsługuje to na dwa sposoby.

Kolejkowanie i ręczne pollowanie

accepted = client.jobs.create(
  content: File.read("content/long-article.md"),
  targets: %w[es fr de ja zh],
  format:  "markdown"
)

job_id = accepted["job_id"]

loop do
  sleep 5
  state = client.jobs.get(job_id)
  break if %w[complete failed].include?(state["status"])
end

if state["status"] == "complete"
  translations = state["translations"]
end

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

done = client.jobs.translate(
  content:       File.read("content/long-article.md"),
  targets:       %w[es fr de],
  format:        "markdown",

  # Opcjonalne nadpisania (pokazane wartości domyślne):
  poll_interval: 5,    # sekundy między pollami, domyślnie 5
  timeout:       1200, # całkowity budżet oczekiwania w sekundach, domyślnie 1200 (20 minut)
  on_progress:   ->(queue_position) { puts "Queue position: #{queue_position.inspect}" }
)

translations = done["translations"]
usage        = done["usage"]

Wszystkie wartości czasu w gemie Ruby używają sekund, zgodnie z konwencjami Ruby. Lambda on_progress wywoływana jest przy każdym pollu i otrzymuje aktualną pozycję w kolejce jako liczbę całkowitą lub nil, jeśli API jej nie zwraca.


Punkty końcowe narzędziowe

health    = client.health
# => { "status" => "ok", "timestamp" => "..." }

languages = client.languages
# => { "languages" => [{ "code" => "en", "name" => "English", "rtl" => false }, ...] }

usage     = client.usage
# => { "usage" => { "tokens_used" => 12000, "tokens_remaining" => 38000, ... } }

health i languages nie wymagają klucza API. usage zwraca zużycie tokenów za bieżący miesiąc kalendarzowy dla uwierzytelnionego konta.


Obsługa błędów

Wszystkie błędy dziedziczą po PolyLingo::PolyLingoError. Przechwytuj konkretne podklasy, które chcesz obsłużyć:

begin
  result = client.translate(
    content: "# Hello",
    targets: %w[es],
    format:  "markdown"
  )
rescue PolyLingo::AuthError => e
  # HTTP 401 — nieprawidłowy, brakujący lub cofnięty klucz API
  puts "Auth failed: #{e.message}"
rescue PolyLingo::RateLimitError => e
  # HTTP 429 — osiągnięto limit na minutę
  retry_after = e.retry_after # liczba sekund lub nil
  sleep retry_after if retry_after
  retry
rescue PolyLingo::JobFailedError => e
  # Zadanie async osiągnęło status końcowy niepowodzenia lub polling przekroczył limit czasu
  puts "Job failed: #{e.job_id}"
rescue PolyLingo::PolyLingoError => e
  # Wszystkie inne błędy API
  puts "#{e.status}: #{e.error} — #{e.message}"
end

RateLimitError#retry_after zwraca liczbę całkowitą z ciała odpowiedzi JSON lub nagłówka Retry-After, w zależności co jest obecne, lub nil jeśli żadne z nich nie jest dołączone. JobFailedError#job_id podaje ID nieudanego zadania, gdy jest znane.


Szybkie odniesienie

MetodaPunkt końcowyWymaga autoryzacji
client.healthGET /healthNie
client.languagesGET /languagesNie
client.translate(...)POST /translateTak
client.batch(...)POST /translate/batchTak
client.usageGET /usageTak
client.jobs.create(...)POST /jobsTak
client.jobs.get(job_id)GET /jobs/:idTak
client.jobs.translate(...)POST /jobs + pollingTak

Zacznij

Gem jest dostępny na RubyGems pod adresem rubygems.org/gems/polylingo. Kod źródłowy jest na github.com/UsePolyLingo/polylingo-ruby. Pełna dokumentacja API jest na usepolylingo.com/docs.

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

gem install polylingo

Pobierz swój klucz API