
Traduzir conteúdo estruturado do Ruby com a gem PolyLingo
By Robert M
Traduzir conteúdo estruturado do Ruby com a gem PolyLingo
A gem PolyLingo para Ruby está agora disponível no RubyGems. Ela cobre toda a superfície da API PolyLingo: tradução síncrona, requisições em lote, trabalhos assíncronos com polling e todos os endpoints utilitários. Não possui dependências em tempo de execução e requer Ruby 2.7 ou superior.
Este post guia pela instalação, configuração do cliente e todos os métodos disponíveis na gem.
Instalação
Adicione ao seu Gemfile:
gem "polylingo"
Então execute:
bundle install
Ou instale diretamente:
gem install polylingo
Sem dependências em tempo de execução. A gem usa apenas a biblioteca padrão do Ruby para HTTP.
Configurando o cliente
require "polylingo"
client = PolyLingo.new(api_key: ENV.fetch("POLYLINGO_API_KEY"))
Duas configurações opcionais estão disponíveis:
client = PolyLingo.new(
api_key: ENV.fetch("POLYLINGO_API_KEY"),
base_url: "https://api.usepolylingo.com/v1", # padrão, sobrescreva para instâncias self-hosted
timeout: 120, # segundos (abertura + leitura), padrão 120
)
Mantenha sua chave API em uma variável de ambiente. Nunca a codifique diretamente e nunca a comite no controle de versão.
Traduzindo conteúdo
Requisição única
Passe seu conteúdo, um array de códigos de idiomas alvo e um formato opcional:
result = client.translate(
content: "# Olá\n\nEste é um conteúdo **estruturado**.",
targets: %w[es fr de],
format: "markdown"
)
puts result["translations"]["es"]
puts result["usage"]["total_tokens"]
O parâmetro format aceita plain, markdown, json ou html. Se omitido, a API detecta o formato automaticamente. Você também pode passar source como dica de idioma e model como "standard" (padrão) ou "advanced".
A preservação do formato funciona da mesma forma que o restante da API PolyLingo. Para json, apenas valores string são traduzidos e chaves, aninhamentos e tipos não-string permanecem intactos. Para markdown, títulos permanecem títulos e blocos de código são mantidos verbatim. Para html, tags e atributos são preservados e apenas nós de texto são traduzidos.
Traduzindo um arquivo JSON de localidade
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 "Escreveu config/locales/#{locale}.json"
end
Uma requisição trata todos os três locais. As chaves são idênticas à fonte em cada arquivo de saída.
Requisições em lote
Envie até 100 itens de conteúdo em uma única requisição, cada um com seu próprio id e format opcional:
result = client.batch(
items: [
{ id: "hero_title", content: "Bem-vindo de volta", format: "plain" },
{ id: "hero_subtitle", content: "Aqui está o que mudou hoje", format: "plain" },
{ id: "cta", content: "Comece agora", format: "plain" },
],
targets: %w[es fr de]
)
result["results"].each do |row|
puts "#{row["id"]}: #{row["translations"]["es"]}"
end
Todos os itens compartilham o mesmo array targets. O id que você passa é preservado na resposta para que você possa mapear os resultados de volta aos seus dados fonte sem depender da ordem.
Trabalhos assíncronos
Para traduções de longa duração, a API de trabalhos aceita a requisição, retorna um job_id imediatamente e permite que você faça polling pelo resultado. A gem trata isso de duas formas.
Enfileirar e fazer polling manualmente
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
Uma chamada que faz polling até terminar
done = client.jobs.translate(
content: File.read("content/long-article.md"),
targets: %w[es fr de],
format: "markdown",
# Sobrescritas opcionais (padrões mostrados):
poll_interval: 5, # segundos entre polls, padrão 5
timeout: 1200, # orçamento total de espera em segundos, padrão 1200 (20 minutos)
on_progress: ->(queue_position) { puts "Posição na fila: #{queue_position.inspect}" }
)
translations = done["translations"]
usage = done["usage"]
Todos os valores de tempo na gem Ruby usam segundos, consistente com as convenções Ruby. A lambda on_progress é disparada a cada poll e recebe a posição atual na fila como um inteiro, ou nil se a API não retornar uma.
Endpoints utilitários
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 e languages não requerem chave API. usage retorna o consumo de tokens para o mês corrente do calendário para a conta autenticada.
Tratamento de erros
Todos os erros herdam de PolyLingo::PolyLingoError. Capture as subclasses específicas que deseja tratar:
begin
result = client.translate(
content: "# Olá",
targets: %w[es],
format: "markdown"
)
rescue PolyLingo::AuthError => e
# HTTP 401 — chave API inválida, ausente ou revogada
puts "Falha na autenticação: #{e.message}"
rescue PolyLingo::RateLimitError => e
# HTTP 429 — limite por minuto atingido
retry_after = e.retry_after # segundos inteiros ou nil
sleep retry_after if retry_after
retry
rescue PolyLingo::JobFailedError => e
# Trabalho assíncrono atingiu status terminal falhado, ou polling expirou
puts "Trabalho falhou: #{e.job_id}"
rescue PolyLingo::PolyLingoError => e
# Todos os outros erros da API
puts "#{e.status}: #{e.error} — #{e.message}"
end
RateLimitError#retry_after retorna um inteiro do corpo JSON da resposta ou do cabeçalho Retry-After, o que estiver presente, ou nil se nenhum estiver incluído. JobFailedError#job_id fornece o ID do trabalho falhado quando conhecido.
Referência rápida
| Método | Endpoint | Requer autenticação |
|---|---|---|
client.health | GET /health | Não |
client.languages | GET /languages | Não |
client.translate(...) | POST /translate | Sim |
client.batch(...) | POST /translate/batch | Sim |
client.usage | GET /usage | Sim |
client.jobs.create(...) | POST /jobs | Sim |
client.jobs.get(job_id) | GET /jobs/:id | Sim |
client.jobs.translate(...) | POST /jobs + polling | Sim |
Comece agora
A gem está no RubyGems em rubygems.org/gems/polylingo. O código-fonte está em github.com/UsePolyLingo/polylingo-ruby. A documentação completa da API está em usepolylingo.com/docs.
O plano gratuito inclui 50.000 tokens por mês. Não é necessário cartão de crédito.
gem install polylingo