From 1c6d471e0fbed2595f1ce5414833668c3f0cc7b2 Mon Sep 17 00:00:00 2001 From: IG Date: Wed, 9 Sep 2026 21:11:12 +0400 Subject: [PATCH] docs: show how to configure each of the six providers The provider table said which options each one takes; it did not say what a working configuration looks like. Somebody adopting Azure had to infer a snippet from a table row, and the two providers that break the usual pattern -- LibreTranslate, whose base URL is required and whose key is not, and Amazon, which is signed rather than keyed and reads no AWS environment variables -- were exactly the ones a reader was most likely to get wrong. Every snippet was run: the option names are checked against `Configuration.options`, and the ones needing no network were executed rather than eyeballed. Also records the Ruby 3.4 floor in Installation, where someone looks before adding the gem rather than after bundler refuses it, and gives the CHANGELOG a line naming the five providers this release adds. The existing entry described the Google provider in detail and left the other four to be discovered in the diff. --- CHANGELOG.md | 6 +++ README.md | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68320c1..c15d19e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -125,6 +125,12 @@ described below. Everything here is relative to `deepl_diff` 2.2.0. ### Added +- Five more providers, all on the same base class and the same transport: + `:google` (Cloud Translation v2), `:azure` (Azure AI Translator v3.0), + `:modernmt`, `:libretranslate` and `:amazon` (Amazon Translate). Each + declares its own options, its own limits, and what it can actually do -- + see the provider table in the README, which is written from the same + capabilities the library reads at runtime. - A Google provider: `config.provider = :google` translates through Cloud Translation v2 (Basic) over HTTP directly, with no Google gem installed. It declares `google_api_key`, `google_project_id` and `google_api_base`; an API diff --git a/README.md b/README.md index e8c2177..0f4bae0 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,8 @@ See [Getting started](#getting-started) below. ## Installation +Ruby 3.4 or newer is required. + Add this line to your application's Gemfile: ```ruby @@ -189,6 +191,120 @@ runtime: | LibreTranslate | `:libretranslate` | `libretranslate_api_base` | 50 | 5,000 | yes (`format`) | no | yes | no | | Amazon | `:amazon` | `amazon_access_key_id`, `amazon_secret_access_key`, `amazon_region` | 1 | 10,000 | no | no | yes | no | +### Configuring each provider + +Every example below is complete: set the options shown and +`TranslationDiff.translate` works. The option names, and which of them are +required, come from the provider itself -- see [Configuration +options](#configuration-options) for the full list and the environment +variables each one falls back to. + +**DeepL** is the default, so `config.provider` may be omitted. A key ending +in `:fx` is a free-plan key and selects the free host on its own. + +```ruby +TranslationDiff.configure do |config| + config.provider = :deepl + config.deepl_api_key = ENV["DEEPL_AUTH_KEY"] +end + +TranslationDiff.translate("Hello there. Second sentence.", from: "en", to: "ru") +``` + +**Google Cloud Translation** needs an API key and nothing else -- no project, +no service account. + +```ruby +TranslationDiff.configure do |config| + config.provider = :google + config.google_api_key = ENV["TRANSLATE_KEY"] +end +``` + +**Azure AI Translator** wants the region as well when the key belongs to a +multi-service Cognitive Services resource; a single-service Translator +resource needs no region. + +```ruby +TranslationDiff.configure do |config| + config.provider = :azure + config.azure_api_key = ENV["AZURE_TRANSLATOR_KEY"] + config.azure_region = "westeurope" +end +``` + +**ModernMT** takes a key and can be pointed at an adaptive memory per call, +since every unrecognised keyword reaches the provider untouched. + +```ruby +TranslationDiff.configure do |config| + config.provider = :modernmt + config.modernmt_api_key = ENV["MMT_API_KEY"] +end + +TranslationDiff.translate(text, from: "en", to: "ru", hints: "1234") +``` + +**LibreTranslate** inverts the usual arrangement: the base URL is required +because every instance is someone's own, and the key is optional because most +instances ask for none. It is also the only provider here you can run +yourself, which makes it the one to develop against. + +```ruby +TranslationDiff.configure do |config| + config.provider = :libretranslate + config.libretranslate_api_base = "http://localhost:5000" + config.libretranslate_api_key = ENV["LIBRETRANSLATE_KEY"] # optional +end +``` + +```bash +docker run -d --rm -p 5000:5000 libretranslate/libretranslate --load-only en,ru +``` + +**Amazon Translate** is signed rather than keyed, so it takes credentials and +a region. There is no environment fallback: this library does not implement +the AWS credential chain, so `AWS_ACCESS_KEY_ID` and friends are not read -- +pass them explicitly. + +```ruby +TranslationDiff.configure do |config| + config.provider = :amazon + config.amazon_access_key_id = ENV.fetch("AWS_ACCESS_KEY_ID") + config.amazon_secret_access_key = ENV.fetch("AWS_SECRET_ACCESS_KEY") + config.amazon_region = "eu-central-1" +end +``` + +Add `gem "aws-sigv4"` to your Gemfile for this one. It is Amazon's own +signing library and nothing more -- no clients, no service models -- and it +is required lazily, so an application on any other provider never installs it. + +**Null** translates nothing and returns what it was given. It exists so a +pipeline can be wired up, and its cache and instrumentation exercised, before +anyone has paid for a key. + +```ruby +TranslationDiff.configure { |config| config.provider = :null } +``` + +Different providers can be used side by side without disturbing the global +configuration -- `TranslationDiff.context` yields an isolated copy, and +`provider:` overrides one call: + +```ruby +formal = TranslationDiff.context do |config| + config.provider = :deepl + config.deepl_api_key = ENV["DEEPL_AUTH_KEY"] +end +formal.translate(contract, from: "en", to: "de", formality: :more) + +TranslationDiff.translate(blog_post, from: "en", to: "de", provider: :google) +``` + +Both read and write the same cache, keyed per provider, so switching one +never serves you the other's translations. + **Every keyword other than `from:`, `to:`, `provider:` and `config:` is forwarded to the provider, and every provider applies them the same way: its own defaults first, then your options, then the fields the request cannot