Class: TranslationDiff::Providers::DeepL

Inherits:
HTTPProvider
  • Object
show all
Defined in:
lib/translation_diff/providers/deepl.rb

Overview

Talks to DeepL's REST API directly, not deepl-rb: it logged the auth key at DEBUG and defaulted notranslate off.

Constant Summary collapse

"https://api.deepl.com".freeze
FREE_HOST =
"https://api-free.deepl.com".freeze
FREE_KEY_SUFFIX =

A key ending in :fx is a free-plan key, and the free plan lives on its own host.

":fx".freeze
DEFAULT_OPTIONS =

DeepL honours class="notranslate" only under HTML tag handling -- otherwise content translates, tags survive.

{ tag_handling: :html, tag_handling_version: "v2" }.freeze
DETECTION_TARGET =

DeepL requires a target language even when only detection is wanted, so the provider picks one.

"EN".freeze

Constants inherited from HTTPProvider

HTTPProvider::RETRY_STATUSES, HTTPProvider::TRANSPORT_FAILURES

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from HTTPProvider

#connection, #translate

Class Method Details

.capabilities ⇒ Object

50 texts / 128 KiB are DeepL's documented per-request limits; max_batch_size was wrong before (it said 300).



13
14
15
16
17
18
# File 'lib/translation_diff/providers/deepl.rb', line 13

def self.capabilities
  TranslationDiff::Capabilities.new(
    max_request_size: 1_700, max_batch_size: 50, max_text_size: nil,
    html: :tag_handling, notranslate: true, detects_language: true, reports_billing: true
  )
end

.configuration_options ⇒ Object

DEEPL_AUTH_KEY is what deepl-rb read on our behalf; the callable keeps it read on use, not at load.



21
22
23
# File 'lib/translation_diff/providers/deepl.rb', line 21

def self.configuration_options
  [:deepl_api_base, { deepl_api_key: -> { ENV.fetch("DEEPL_AUTH_KEY", nil) } }]
end

.configuration_requirements ⇒ Object



25
# File 'lib/translation_diff/providers/deepl.rb', line 25

def self.configuration_requirements = %i[deepl_api_key]

.language_case ⇒ Object

DeepL is the one vendor documenting upper-case codes.



28
# File 'lib/translation_diff/providers/deepl.rb', line 28

def self.language_case = :upcase

Instance Method Details

#api_base ⇒ Object



33
34
35
# File 'lib/translation_diff/providers/deepl.rb', line 33

def api_base
  config.deepl_api_base || (free_key? ? FREE_HOST : PAID_HOST)
end

#detect(text) ⇒ Object

DeepL has no detection endpoint; translating a sample and reading the source it reports is the only way.



60
61
62
63
64
# File 'lib/translation_diff/providers/deepl.rb', line 60

def detect(text)
  request = TranslationDiff::Translation::Request.new(texts: [text], from: nil,
                                                      to: DETECTION_TARGET)
  translate(request).detected_source
end

#headers ⇒ Object



37
# File 'lib/translation_diff/providers/deepl.rb', line 37

def headers = { "Authorization" => "DeepL-Auth-Key #{config.deepl_api_key}" }

#languages ⇒ Object



66
67
68
69
# File 'lib/translation_diff/providers/deepl.rb', line 66

def languages
  { source: codes(get("v2/languages?type=source").body),
    target: codes(get("v2/languages?type=target").body) }
end

#languages_endpoint ⇒ Object

The source-list URL is enough to document what #languages fetches; the target one differs only by query.



72
# File 'lib/translation_diff/providers/deepl.rb', line 72

def languages_endpoint = "#{api_base}/v2/languages"

#parse_translate_response(body, _headers, request) ⇒ Object



48
49
50
51
52
53
54
55
56
57
# File 'lib/translation_diff/providers/deepl.rb', line 48

def parse_translate_response(body, _headers, request)
  translations = Array(body["translations"])

  TranslationDiff::Translation::Response.build(
    request: request,
    texts: translations.map { |t| t["text"] },
    detected_source: translations.first&.dig("detected_source_language")&.downcase,
    usage: usage_for(request, translations)
  )
end

#render_translate_payload(request) ⇒ Object



41
42
43
44
45
46
# File 'lib/translation_diff/providers/deepl.rb', line 41

def render_translate_payload(request)
  DEFAULT_OPTIONS
    .merge(request.options)
    .merge(text: request.texts, target_lang: language(request.to))
    .tap { |payload| payload[:source_lang] = language(request.from) unless request.from.nil? }
end

#translate_url ⇒ Object



39
# File 'lib/translation_diff/providers/deepl.rb', line 39

def translate_url = "v2/translate"