
Перевод структурированного контента из Ruby с помощью библиотеки PolyLingo
By Robert M
Перевод структурированного контента из Ruby с помощью библиотеки PolyLingo
Библиотека PolyLingo для Ruby теперь доступна на RubyGems. Она охватывает весь API PolyLingo: синхронный перевод, пакетные запросы, асинхронные задания с опросом и все вспомогательные конечные точки. Не имеет зависимостей во время выполнения и требует Ruby 2.7 или новее.
В этом посте описывается установка, настройка клиента и все доступные методы библиотеки.
Установка
Добавьте в ваш Gemfile:
gem "polylingo"
Затем выполните:
bundle install
Или установите напрямую:
gem install polylingo
Нет зависимостей во время выполнения. Библиотека использует только стандартную библиотеку Ruby для HTTP.
Настройка клиента
require "polylingo"
client = PolyLingo.new(api_key: ENV.fetch("POLYLINGO_API_KEY"))
Доступны две необязательные настройки:
client = PolyLingo.new(
api_key: ENV.fetch("POLYLINGO_API_KEY"),
base_url: "https://api.usepolylingo.com/v1", # по умолчанию, переопределите для self-hosted инстансов
timeout: 120, # секунды (открытие + чтение), по умолчанию 120
)
Храните ваш API ключ в переменной окружения. Никогда не хардкодьте его и не коммитьте в систему контроля версий.
Перевод контента
Один запрос
Передайте ваш контент, массив кодов целевых языков и необязательный формат:
result = client.translate(
content: "# Привет\n\nЭто **структурированный** контент.",
targets: %w[es fr de],
format: "markdown"
)
puts result["translations"]["es"]
puts result["usage"]["total_tokens"]
Параметр format принимает значения plain, markdown, json или html. Если опущен, API автоматически определяет формат. Также можно передать source как подсказку языка и model как "standard" (по умолчанию) или "advanced".
Сохранение формата работает так же, как и в остальной части API PolyLingo. Для json переводятся только строковые значения, ключи, вложенность и нестроковые типы остаются без изменений. Для markdown заголовки остаются заголовками, а блоки кода сохраняются без изменений. Для html теги и атрибуты сохраняются, переводятся только текстовые узлы.
Перевод 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 "Записан config/locales/#{locale}.json"
end
Один запрос обрабатывает все три локали. Ключи идентичны исходным во всех выходных файлах.
Пакетные запросы
Отправьте до 100 элементов контента в одном запросе, каждый с собственным id и необязательным format:
result = client.batch(
items: [
{ id: "hero_title", content: "С возвращением", format: "plain" },
{ id: "hero_subtitle", content: "Вот что изменилось сегодня", format: "plain" },
{ id: "cta", content: "Начать", format: "plain" },
],
targets: %w[es fr de]
)
result["results"].each do |row|
puts "#{row["id"]}: #{row["translations"]["es"]}"
end
Все элементы используют один и тот же массив targets. Переданный вами id сохраняется в ответе, чтобы вы могли сопоставить результаты с исходными данными без зависимости от порядка.
Асинхронные задания
Для длительных переводов API заданий принимает запрос, сразу возвращает job_id и позволяет опрашивать результат. Библиотека обрабатывает это двумя способами.
Добавить в очередь и опрашивать вручную
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
Один вызов, который опрашивает до завершения
done = client.jobs.translate(
content: File.read("content/long-article.md"),
targets: %w[es fr de],
format: "markdown",
# Необязательные переопределения (показаны по умолчанию):
poll_interval: 5, # секунд между опросами, по умолчанию 5
timeout: 1200, # общий лимит ожидания в секундах, по умолчанию 1200 (20 минут)
on_progress: ->(queue_position) { puts "Позиция в очереди: #{queue_position.inspect}" }
)
translations = done["translations"]
usage = done["usage"]
Все временные значения в Ruby-библиотеке указаны в секундах, в соответствии с конвенциями Ruby. Лямбда on_progress вызывается при каждом опросе и получает текущую позицию в очереди как целое число или nil, если API не возвращает её.
Вспомогательные конечные точки
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 и languages не требуют ключа API. usage возвращает потребление токенов за текущий календарный месяц для аутентифицированного аккаунта.
Обработка ошибок
Все ошибки наследуются от PolyLingo::PolyLingoError. Обрабатывайте конкретные подклассы, которые хотите:
begin
result = client.translate(
content: "# Привет",
targets: %w[es],
format: "markdown"
)
rescue PolyLingo::AuthError => e
# HTTP 401 — неверный, отсутствующий или отозванный ключ API
puts "Ошибка аутентификации: #{e.message}"
rescue PolyLingo::RateLimitError => e
# HTTP 429 — достигнут лимит запросов в минуту
retry_after = e.retry_after # целые секунды или nil
sleep retry_after if retry_after
retry
rescue PolyLingo::JobFailedError => e
# Асинхронная задача завершилась с ошибкой или время опроса истекло
puts "Задача не выполнена: #{e.job_id}"
rescue PolyLingo::PolyLingoError => e
# Все остальные ошибки API
puts "#{e.status}: #{e.error} — #{e.message}"
end
RateLimitError#retry_after возвращает целое число из тела JSON-ответа или заголовка Retry-After, что присутствует, или nil, если ни того, ни другого нет. JobFailedError#job_id возвращает ID неудачной задачи, если он известен.
Быстрая справка
| Метод | Endpoint | Требуется аутентификация |
|---|---|---|
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(job_id) | GET /jobs/:id | Да |
client.jobs.translate(...) | POST /jobs + опрос | Да |
Начало работы
Библиотека доступна на RubyGems по адресу rubygems.org/gems/polylingo. Исходный код на github.com/UsePolyLingo/polylingo-ruby. Полная документация API на usepolylingo.com/docs.
Бесплатный тариф включает 50 000 токенов в месяц. Кредитная карта не требуется.
gem install polylingo