The DeepL API is a language translation API that allows other computer programs to send texts and documents to DeepL's servers and receive high-quality translations. This opens a whole universe of opportunities for developers: any translation product you can imagine can now be built on top of DeepL's best-in-class translation technology.
The DeepL Ruby library offers a convenient way for applications written in Ruby to interact with the DeepL API. We intend to support all API functions with the library, though support for new features may be added to the library after they’re added to the API.
To use the DeepL Ruby Library, you'll need an API authentication key. To get a key, please create an account here. With a DeepL API Free account you can translate up to 500,000 characters/month for free.
Install this gem with
gem install deepl-rb
# Load it in your ruby file using `require 'deepl'`Or add it to your Gemfile:
gem 'deepl-rb', require: 'deepl'Create a DeepL::Client with your authentication key. Each client owns its configuration and
HTTP connection, so several clients with different keys or options can be used side by side.
The client reads no environment variables:
client = DeepL::Client.new(ENV.fetch('DEEPL_AUTH_KEY'))DeepL::Client.new accepts these keyword arguments:
| Option | Default | Description |
|---|---|---|
server_url: |
https://api-free.deepl.com for Free keys (ending in :fx), else https://api.deepl.com |
Base URL of the DeepL API. A path prefix is kept. |
headers: |
{} |
HTTP headers sent with every DeepL API request (not to pre-signed storage URLs). A User-Agent replaces the library's; Authorization cannot be replaced. |
max_retries: |
5 |
Retries after the first attempt, for HTTP 429, any 5xx and network failures. |
timeout: |
10 |
Timeout of each attempt in seconds. A longer backoff interval takes precedence. |
proxy: |
none | Proxy URL, e.g. http://user:password@proxy.example:8080. |
send_platform_info: |
true |
Adds the OS and Ruby versions to the User-Agent. |
app_info: |
none | A DeepL::AppInfo or a hash with app_name and app_version, added to the User-Agent. |
http_client_options: |
none | A DeepL::HTTPClientOptions with proxy, certificate, SSL verification and per-phase timeouts. Its timeouts take precedence over timeout:. |
logger: |
none | Logger for requests and retries, see Logging. |
The authentication key is trimmed; an empty key raises ArgumentError.
DeepL::Client.free_account_auth_key?(key) returns whether a key is a DeepL API Free key.
DeepL::Client offers text translation (translate_text, see Translate),
document translation (translate_document and its steps, see
Translate documents), rephrasing and correction (rephrase_text and
correct_text, see Rephrase Text and Correct Text),
multilingual glossaries (see Multilingual glossaries),
spoken terms (see
Spoken terms) and usage (get_usage, see Monitor usage); for the other operations, use the module-level API shown in the following sections. The module-level API (DeepL.configure, DeepL.translate, DeepL.glossaries, ...)
is deprecated: each method prints a deprecation warning once per process, and it will be
removed in the next major version.
Setup an environment variable named DEEPL_AUTH_KEY with your authentication key:
export DEEPL_AUTH_KEY="your-api-token"Alternatively, you can configure the API client within a ruby block:
DeepL.configure do |config|
config.auth_key = 'your-api-token'
endYou can also configure the API host and the API version:
DeepL.configure do |config|
config.auth_key = 'your-api-token'
config.host = 'https://api-free.deepl.com' # Default value is 'https://api.deepl.com'
endWithout a host, keys ending in :fx use https://api-free.deepl.com. The version setting
is deprecated.
get_source_languages and get_target_languages of DeepL::Client return the languages that
can be translated from and into, as DeepL::Resources::Language objects with upper-case codes:
languages = client.get_source_languages
puts languages.first.class
# => DeepL::Resources::Language
puts "#{languages.first.code} -> #{languages.first.name}"
# => "ES -> Spanish"
german = client.get_target_languages.find { |language| language.code == 'DE' }
puts german.supports_formality?
# => truesupports_formality? is true or false for target languages and nil for source languages.
All languages are also defined on the official API documentation.
The module-level DeepL.languages(type: :source) and DeepL.languages(type: :target) are
deprecated.
get_languages_for_resource returns the languages supported by a given API resource, with
source/target usability and per-feature support. The language codes are returned as the API sends
them (de, en-GB). The resources are defined in DeepL::Constants::LanguageResourceName
(TRANSLATE_TEXT, TRANSLATE_DOCUMENT, GLOSSARY, VOICE, WRITE, STYLE_RULES,
TRANSLATION_MEMORY). Pass include: with one value or an array of values from
DeepL::Constants::LanguageInclude (BETA, EXTERNAL) to also list beta languages and features
or features that rely on third-party providers. Other strings are sent unchanged, for both the
resource and include:.
languages = client.get_languages_for_resource(
DeepL::Constants::LanguageResourceName::TRANSLATE_TEXT,
include: [DeepL::Constants::LanguageInclude::BETA]
)
german = languages.find { |language| language.code == 'de' }
puts german.usable_as_target?
# => true
puts german.supports?(:formality)
# => true
puts german.features['formality'].status
# => "stable"get_language_resources lists every resource with its name and features, and whether a
feature must be supported by the source language, the target language, or both:
translate_text = client.get_language_resources.find { |resource| resource.name == 'translate_text' }
formality = translate_text.features['formality']
puts formality.needs_source_support?
# => false
puts formality.needs_target_support?
# => trueThe module-level DeepL.languages_for_resource and DeepL.language_resources are deprecated.
To translate a simple text, use the translate_text method of DeepL::Client:
translation = client.translate_text 'This is my text', 'EN', 'ES'
puts translation.class
# => DeepL::Resources::Text
puts translation.text
# => 'Este es mi texto'
puts translation.billed_characters
# => 15Each result has text, detected_source_language, billed_characters (the characters
billed for the text; the library always asks the API for it), model_type_used and
tag_handling_version (the tag handling version the API used, when tag handling was
requested). A field the response does not contain is nil.
Enable auto-detect source language by skipping the source language with nil:
translation = client.translate_text 'This is my text', nil, 'ES'
puts translation.detected_source_language
# => 'EN'Translate a list of texts by passing an array as an argument. An array, also one with a single text, returns an array of results:
texts = ['Sample text', 'Another text']
translations = client.translate_text texts, 'EN', 'ES'
puts translations.class
# => Array
puts translations.first.class
# => DeepL::Resources::TextOptions are passed as keyword arguments; an option set to nil is not sent. You can use
options like tag_handling, split_sentences, non_splitting_tags or ignore_tags:
translation = client.translate_text '<p>A sample</p>', 'EN', 'ES',
tag_handling: 'xml', split_sentences: false,
non_splitting_tags: 'h1', ignore_tags: %w[code pre]
puts translation.text
# => "<p>Una muestra</p>"To specify which version of the tag handling algorithm to use, you can use the tag_handling_version parameter:
translation = client.translate_text '<p>A sample</p>', 'EN', 'ES',
tag_handling: 'xml',
tag_handling_version: DeepL::Constants::TagHandlingVersion::V2
puts translation.text
# => "<p>Una muestra</p>"
puts translation.tag_handling_version
# => "v2"The available values are 'v1' and 'v2' (DeepL::Constants::TagHandlingVersion::V1 and
V2); other strings are sent as given.
To translate with context, simply supply the context parameter:
translation = client.translate_text 'That is hot!', 'EN', 'ES',
context: 'He did not like the jalapenos in his meal.'
puts translation.text
# => "¡Eso es picante!"To specify a type of translation model to use, you can use the model_type option:
translation = client.translate_text 'That is hot!', 'EN', 'DE',
model_type: 'quality_optimized'This would use next-gen translation models for the translation. The available values are
'quality_optimized': use a translation model that maximizes translation quality, at the cost of response time. This option may be unavailable for some language pairs.'prefer_quality_optimized': use the highest-quality translation model for the given language pair.'latency_optimized': use a translation model that minimizes response time, at the cost of translation quality.
To translate with custom instructions, supply the custom_instructions parameter, an array
of instructions. A single string is sent as one instruction, commas included:
translation = client.translate_text 'Hello, world!', 'EN', 'DE',
custom_instructions: ['Use informal language', 'Be concise']
puts translation.textUp to 10 custom instructions can be specified, each with a maximum of 300 characters.
The target language must be de, en, es, fr, it, ja, ko, zh or any variants.
Note that using custom_instructions will automatically use quality_optimized models,
and cannot be combined with model_type: 'latency_optimized'.
The following parameters will be automatically converted:
| Parameter | Conversion |
|---|---|
preserve_formatting |
Converts false to '0' and true to '1' |
split_sentences |
Converts false to '0' and true to '1' |
outline_detection |
Converts false to '0' and true to '1' |
splitting_tags |
Converts arrays to strings joining by commas |
non_splitting_tags |
Converts arrays to strings joining by commas |
ignore_tags |
Converts arrays to strings joining by commas |
formality |
No conversion applied |
glossary |
A glossary ID string, a Glossary or a MultilingualGlossary object, sent as glossary_id (see Glossaries) |
glossary_id |
Deprecated, use glossary. No conversion applied |
style_rule |
No conversion applied (can be a string ID or a StyleRule object) |
style_profile |
No conversion applied (can be a string ID or a StyleProfile object, see Style profiles) |
translation_memory |
No conversion applied (can be a string ID or a TranslationMemory object) |
translation_memory_threshold |
No conversion applied (integer 0-100, recommended minimum 75) |
context |
No conversion applied |
custom_instructions |
An array of strings; a string is sent as a one-element array |
tag_handling_version |
No conversion applied (DeepL::Constants::TagHandlingVersion) |
extra_body_parameters |
Hash of extra parameters to pass in the body of the HTTP request. Can be used to access beta features, or to override built-in parameters for testing purposes. Extra parameters can override keys explicitly set by the client. |
show_billed_characters: true is always sent.
The deprecated module-level DeepL.translate(text, source_lang, target_lang, options = {}, additional_headers = {}) takes the same options. Unlike translate_text, it returns a single
result for a one-element array.
To rephrase or improve text, including changing the writing style or tone of the text, use
the rephrase_text method of DeepL::Client:
rephrased_text = client.rephrase_text 'you will acquire new rephrased text', 'EN'
puts rephrased_text.class
# => DeepL::Resources::Text
puts rephrased_text.text
# => 'You get new rephrased text.'
puts rephrased_text.detected_source_language
# => 'en'
puts rephrased_text.target_language
# => 'en-US'As with translate_text, the text can be a string or an array of strings: a string returns a
DeepL::Resources::Text, an array returns an array of them (also for an array with one
element). The target language is optional.
Use the writing_style: or tone: keyword to choose the writing style or tone of the
rephrased text (DeepL::Constants::WritingStyle and DeepL::Constants::Tone list the values;
any string is sent as given). extra_body_parameters: is a hash added to the request body
last; it replaces fields of the same name.
rephrased_text = client.rephrase_text 'you will acquire new rephrased text', 'EN',
writing_style: 'casual'
puts rephrased_text.text
# => 'You'll get new, rephrased text.'rephrased_text = client.rephrase_text 'you will acquire new rephrased text', 'EN',
tone: DeepL::Constants::Tone::FRIENDLY
puts rephrased_text.text
# => 'You'll get to enjoy new, rephrased text!'The deprecated module-level DeepL.rephrase(text, target_lang = nil, writing_style = nil, tone = nil, options = {}, additional_headers = {}) takes the writing style and tone as
positional arguments. Unlike rephrase_text, it returns a single result for a one-element
array.
To fix grammar, spelling and punctuation, use the correct_text method of DeepL::Client.
It accepts a string or an array of strings, plus an optional target language and
extra_body_parameters::
corrected = client.correct_text 'I has a apple.', 'en-US'
puts corrected.text
# => 'It has an apple.'
puts corrected.target_language
# => 'en-US'A string returns a DeepL::Resources::Text; an array returns an array of them (also for an
array with one element). Empty text raises ArgumentError. The deprecated module-level
DeepL.correct(text, target_lang = nil, options = {}, additional_headers = {}) behaves the
same.
Both methods raise DeepL::Exceptions::Error if the response contains fewer improvements than
texts were sent.
To create a glossary, use the glossaries.create method. The glossary entries argument should be an array of text pairs. Each pair includes the source and the target translations.
entries = [
['Hello World', 'Hola Tierra'],
['car', 'auto']
]
glossary = DeepL.glossaries.create 'Mi Glosario', 'EN', 'ES', entries
puts glossary.class
# => DeepL::Resources::Glossary
puts glossary.id
# => 'aa48c7f0-0d02-413e-8a06-d5bbf0ca7a6e'
puts glossary.entry_count
# => 2Created glossaries can be used in text and document translation by specifying the
glossary option, a glossary ID or a Glossary / MultilingualGlossary object. It is sent
as glossary_id and replaces the deprecated glossary_id option:
translation = client.translate_text 'Hello World', 'EN', 'ES', glossary: 'aa48c7f0-0d02-413e-8a06-d5bbf0ca7a6e'
puts translation.class
# => DeepL::Resources::Text
puts translation.text
# => 'Hola Tierra'
translation = client.translate_text "I wish we had a car.", 'EN', 'ES', glossary: glossary
puts translation.class
# => DeepL::Resources::Text
puts translation.text
# => Ojalá tuviéramos un auto.To use more than one glossary at once, specify the glossary_ids option with an
array of up to 5 glossary IDs (as strings or DeepL::Resources::Glossary
objects) instead of glossary. This works for both text and document
translation. glossary_ids cannot be combined with glossary or glossary_id,
and raises ArgumentError if this rule is violated or more than 5 IDs are
provided. For text translation, a glossary (glossary or glossary_ids) can be
used without source_lang: the API detects the source language and uses the
glossary's dictionary for the detected language pair. Document translation with
glossary_ids requires source_lang and raises ArgumentError without it:
# Text translation with multiple glossaries
translation = client.translate_text 'Hello World', 'EN', 'ES',
glossary_ids: ['aa48c7f0-0d02-413e-8a06-d5bbf0ca7a6e',
'bb59d8g1-1e13-524f-9b17-e6ccg1db8b7f']
# Document translation with multiple glossaries
handle = DeepL.document.upload 'my_document.docx', 'EN', 'ES', 'my_document.docx',
glossary_ids: ['aa48c7f0-0d02-413e-8a06-d5bbf0ca7a6e',
'bb59d8g1-1e13-524f-9b17-e6ccg1db8b7f']To list all the glossaries available, use the glossaries.list method:
glossaries = DeepL.glossaries.list
puts glossaries.class
# => Array
puts glossaries.first.class
# => DeepL::Resources::GlossaryTo find an existing glossary, use the glossaries.find method:
glossary = DeepL.glossaries.find 'aa48c7f0-0d02-413e-8a06-d5bbf0ca7a6e'
puts glossary.class
# => DeepL::Resources::GlossaryThe glossary resource does not include the glossary entries. To list the glossary entries, use the glossaries.entries method:
entries = DeepL.glossaries.entries 'aa48c7f0-0d02-413e-8a06-d5bbf0ca7a6e'
puts entries.class
# => Array
puts entries.size
# => 2
pp entries.first
# => ["Hello World", "Hola Tierra"]To delete an existing glossary, use the glossaries.destroy method:
glossary_id = DeepL.glossaries.destroy 'aa48c7f0-0d02-413e-8a06-d5bbf0ca7a6e'
puts glossary_id
# => aa48c7f0-0d02-413e-8a06-d5bbf0ca7a6eYou can list all the language pairs supported by glossaries using the glossaries.language_pairs method:
language_pairs = DeepL.glossaries.language_pairs
puts language_pairs.class
# => Array
puts language_pairs.first.class
# => DeepL::Resources::LanguagePair
puts language_pairs.first.source_lang
# => en
puts language_pairs.first.target_lang
# => deMultilingual glossaries (v3) group several language-pair dictionaries under one
glossary and are managed through DeepL::Client. Every method that takes a
glossary accepts its ID or a DeepL::Resources::MultilingualGlossary object; the
ID is URL-encoded in the request path. A dictionary's entries are source/target
term pairs.
To create a multilingual glossary, pass a name and one
DeepL::Resources::MultilingualGlossaryDictionaryEntries (or a hash with
:source_lang, :target_lang and :entries) per language pair. A hash may also
give its entries as a TSV string, or as CSV with entries_format: 'csv'. Terms
given as pairs are checked like v2 glossary terms: each term is stripped of
surrounding whitespace, and an empty term or one with a control character raises
ArgumentError before anything is sent. Further options, such as
extra_body_parameters, are given as additional keywords:
glossary = client.create_multilingual_glossary(
'My Glossary',
[
DeepL::Resources::MultilingualGlossaryDictionaryEntries.new(
'EN', 'DE', [['Hello', 'Hallo'], ['World', 'Welt']]
),
{ source_lang: 'EN', target_lang: 'FR', entries: [['Hello', 'Bonjour']] }
]
)
puts glossary.class
# => DeepL::Resources::MultilingualGlossary
puts glossary.id
# => 'aa48c7f0-0d02-413e-8a06-d5bbf0ca7a6e'
puts glossary.creation_time.class
# => Time
puts glossary.dictionaries.first.entry_count
# => 2To create a multilingual glossary with one dictionary from CSV content (a string
or an IO), use create_multilingual_glossary_from_csv:
glossary = client.create_multilingual_glossary_from_csv(
'My Glossary', 'EN', 'DE', File.read('entries.csv')
)List or fetch multilingual glossaries with list_multilingual_glossaries and
get_multilingual_glossary. The glossary does not include the entries; fetch the
entries of one language pair with get_multilingual_glossary_dictionary_entries,
which raises DeepL::Exceptions::NotFound if the glossary has no dictionary for
that pair. The returned object can be passed to the create, update and replace
methods:
glossaries = client.list_multilingual_glossaries
glossary = client.get_multilingual_glossary 'aa48c7f0-0d02-413e-8a06-d5bbf0ca7a6e'
dictionary = client.get_multilingual_glossary_dictionary_entries(glossary, 'EN', 'DE')
puts dictionary.entries.inspect
# => [["Hello", "Hallo"], ["World", "Welt"]]update_multilingual_glossary renames the glossary and/or merges entries into
its dictionaries (a new language pair adds a dictionary). Keywords left nil are
not sent. update_multilingual_glossary_name,
update_multilingual_glossary_dictionary and
update_multilingual_glossary_dictionary_from_csv do one of these at a time. To
replace the entries of a dictionary instead, use
replace_multilingual_glossary_dictionary (or
replace_multilingual_glossary_dictionary_from_csv):
client.update_multilingual_glossary(
glossary, name: 'Renamed Glossary',
dictionaries: [{ source_lang: 'EN', target_lang: 'FR', entries: [['World', 'Monde']] }]
)
client.update_multilingual_glossary_name(glossary, 'Renamed Glossary')
client.update_multilingual_glossary_dictionary(
glossary, { source_lang: 'EN', target_lang: 'FR', entries: [['World', 'Monde']] }
)
client.replace_multilingual_glossary_dictionary(
glossary, { source_lang: 'EN', target_lang: 'DE', entries: [['Hello', 'Hallo'], ['car', 'Auto']] }
)To delete one dictionary or the entire glossary (both return nil):
client.delete_multilingual_glossary_dictionary(glossary, 'EN', 'FR')
client.delete_multilingual_glossary(glossary)The module-level DeepL.multilingual_glossaries (create, create_with_csv,
find, list, entries, update_name, update_dictionary,
update_dictionary_with_csv, replace_dictionary, replace_dictionary_with_csv,
destroy_dictionary, destroy) is deprecated; it sends the same requests and
returns the same objects as the methods above.
Spoken terms collections improve the transcription of terms such as product
names. A collection holds one list of terms per language and is managed through
DeepL::Client. Every method that takes a collection accepts its ID or a
DeepL::Resources::SpokenTerms object. Terms are passed and returned as arrays
of strings.
To create a collection, pass a name and one DeepL::Resources::SpokenTermsEntries
(or a hash with :lang and :entries) per language. Terms are checked like
glossary terms: each term is stripped of surrounding whitespace and sent stripped,
and create_spoken_terms, update_spoken_terms and replace_spoken_terms_list
raise ArgumentError before sending anything if a term is then empty or contains
a C0 or C1 control character (such as a tab or newline), U+2028 or U+2029.
Further options, such as extra_body_parameters, are given as additional
keywords:
spoken_terms = client.create_spoken_terms(
'Product names',
[DeepL::Resources::SpokenTermsEntries.new('en', ['DeepL', 'webhook'])]
)
puts spoken_terms.class
# => DeepL::Resources::SpokenTerms
puts spoken_terms.spoken_terms_id
# => 'a74d88fb-ed2a-4943-a664-a4512398b994'
puts spoken_terms.creation_time.class
# => Time
puts spoken_terms.term_lists.first.entry_count
# => 2creation_time is nil if the API returns a malformed timestamp. List all
collections or fetch one with list_spoken_terms and get_spoken_terms:
collections = client.list_spoken_terms
spoken_terms = client.get_spoken_terms 'a74d88fb-ed2a-4943-a664-a4512398b994'update_spoken_terms renames a collection and/or merges terms into the list of
each given language. Arguments that are not given are not sent:
client.update_spoken_terms(spoken_terms, name: 'Renamed')
client.update_spoken_terms(spoken_terms, name: 'Renamed',
extra_body_parameters: { example_param: 'value' })
updated = client.update_spoken_terms(
spoken_terms, term_lists: [{ lang: 'en', entries: ['authentication'] }]
)
puts updated.term_lists.first.entry_count
# => 3To read the terms of one language, use get_spoken_terms_entries:
entries = client.get_spoken_terms_entries(spoken_terms, 'en')
puts entries.entries.inspect
# => ["DeepL", "authentication", "webhook"]replace_spoken_terms_list replaces the terms of one language, or adds the list
if the language is new. It takes one DeepL::Resources::SpokenTermsEntries or a
hash with :lang and :entries:
term_list = client.replace_spoken_terms_list(
spoken_terms, DeepL::Resources::SpokenTermsEntries.new('en', ['API'])
)
puts term_list.class
# => DeepL::Resources::SpokenTermsList
puts term_list.entry_count
# => 1To delete the list of one language or the entire collection (both return nil):
client.delete_spoken_terms_list(spoken_terms, 'de')
client.delete_spoken_terms(spoken_terms)Style rules allow you to customize your translations using a managed, shared list
of rules for style, formatting, and more. Multiple style rule lists can be stored
with your account, each with a user-specified name and a uniquely-assigned ID
(style_id). DeepL::Client manages them with get_all_style_rules,
create_style_rule, get_style_rule, update_style_rule_name,
update_style_rule_configured_rules and delete_style_rule. Every method that
takes a style rule list accepts its ID string or a DeepL::Resources::StyleRule
object.
Use create_style_rule with a name and language code. The optional keywords
configured_rules (category -> rule -> value) and custom_instructions (hashes
with label, prompt and optionally source_language) are sent as given;
keywords left nil are not sent. extra_body_parameters adds fields to the
request body.
client = DeepL::Client.new(ENV.fetch('DEEPL_AUTH_KEY'))
# Simple creation with just a name and language
style_rule = client.create_style_rule('My Style Rule', 'en')
puts "Created: #{style_rule.name} (#{style_rule.style_id})"
# Creation with configured rules and custom instructions
style_rule = client.create_style_rule(
'Formal English',
'en',
configured_rules: { style_and_tone: { formality: 'formal' } },
custom_instructions: [{ label: 'Tone', prompt: 'Always use formal language' }]
)Use get_style_rule to retrieve a single style rule list, or get_all_style_rules
to list them one page at a time. get_all_style_rules returns a list of
StyleRule objects and accepts the optional keywords page (page number,
0-indexed), page_size (number of items per page) and detailed. When true,
the response includes configured_rules and custom_instructions for each style
rule list; when false (default), these fields are omitted for faster responses.
Keywords left nil are not sent.
# Get a single style rule list by ID
style_rule = client.get_style_rule('YOUR_STYLE_ID')
puts "#{style_rule.name} (#{style_rule.language})"
# List the first page of style rule lists
client.get_all_style_rules.each do |rule|
puts "#{rule.name} (#{rule.style_id})"
end
# List with pagination
style_rules = client.get_all_style_rules(page: 0, page_size: 10)
# List with detailed configuration
client.get_all_style_rules(detailed: true).each do |rule|
if rule.configured_rules
puts " Number formatting: #{rule.configured_rules.numbers.keys.join(', ')}"
end
endUse update_style_rule_name to rename a style rule list, and
update_style_rule_configured_rules to replace its configured rules. Both accept
extra_body_parameters.
# Update the name
updated = client.update_style_rule_name(style_rule, 'New Name')
# Update configured rules
updated = client.update_style_rule_configured_rules(
style_rule,
{ style_and_tone: { formality: 'formal' } }
)The configured_rules hash supports the following categories: dates_and_times,
formatting, numbers, punctuation, spelling_and_grammar, style_and_tone,
and vocabulary.
Custom instructions allow you to add free-text prompts to a style rule list. Each
instruction has an id, label, prompt, and source_language. Use
create_style_rule_custom_instruction, get_style_rule_custom_instruction,
update_style_rule_custom_instruction, and delete_style_rule_custom_instruction
to manage them. An instruction is given as its ID or a
DeepL::Resources::CustomInstruction object; source_language is optional and
not sent if nil.
# Create a custom instruction
instruction = client.create_style_rule_custom_instruction(
style_rule, 'Formal tone', 'Always use formal language'
)
puts "Created instruction: #{instruction.id}"
# Create with an optional source language
instruction = client.create_style_rule_custom_instruction(
style_rule, 'Formal tone', 'Always use formal language', source_language: 'en'
)
# Get a custom instruction
instruction = client.get_style_rule_custom_instruction(style_rule, instruction)
# Update a custom instruction
updated = client.update_style_rule_custom_instruction(
style_rule, instruction, 'Updated label', 'Use very formal language'
)
# Delete a custom instruction (returns nil)
client.delete_style_rule_custom_instruction(style_rule, instruction)Use delete_style_rule to delete a style rule list. It returns nil.
client.delete_style_rule('YOUR_STYLE_ID')The deprecated module-level DeepL.style_rules (list, create, find,
update_name, update_configured_rules, destroy, create_custom_instruction,
find_custom_instruction, update_custom_instruction,
destroy_custom_instruction) keeps working unchanged.
Style rules can be used in translate_text by specifying the style_rule option
with either a style rule ID string or a StyleRule object:
# Using a style rule ID
translation = client.translate_text('Hello World', 'EN', 'ES',
style_rule: 'dca2e053-8ae5-45e6-a0d2-881156e7f4e4')
# Or using a StyleRule object
style_rule = client.get_all_style_rules.first
translation = client.translate_text('Hello World', 'EN', 'ES', style_rule: style_rule)The same style_rule option can be passed to document translation
(translate_document or translate_document_upload), accepting either a style
rule ID string or a StyleRule object:
client.translate_document('my_document.docx', 'my_document_es.docx', 'EN', 'ES',
style_rule: 'dca2e053-8ae5-45e6-a0d2-881156e7f4e4')A style profile bundles glossaries, style rule lists and translation memories under one
name. DeepL::Client manages them with create_style_profile, get_style_profile,
list_style_profiles, update_style_profile and delete_style_profile. The last three
take a style profile ID string or a DeepL::Resources::StyleProfile object; the ID of a
profile is style_profile_id.
Only the name is required. The optional keywords are description, industry,
glossary_ids, style_rule_ids, translation_memory_ids and
glossary_priority_order_enabled (when true, the order of glossary_ids sets priority).
The component lists take IDs or the resource objects (Glossary, MultilingualGlossary,
StyleRule, TranslationMemory), which are sent as their IDs. If any component cannot be
used, the request fails and no style profile is created. extra_body_parameters adds
fields to the request body.
client = DeepL::Client.new(ENV.fetch('DEEPL_AUTH_KEY'))
# Only a name
profile = client.create_style_profile('Legal, German')
# With components
profile = client.create_style_profile(
'Legal, German',
description: 'Contract wording for the German market.',
industry: 'Legal',
glossary_ids: ['YOUR_GLOSSARY_ID'],
style_rule_ids: [style_rule], # a DeepL::Resources::StyleRule
translation_memory_ids: ['YOUR_TM_ID'],
glossary_priority_order_enabled: true
)
profile.class
# => DeepL::Resources::StyleProfile
profile.style_profile_id
# => "3f1c9d0e-7a24-4b58-9c31-8f0e5d2a1b47"
profile.style_rule_ids
# => ["YOUR_STYLE_ID"]
profile.creation_time.class
# => Timedescription and industry are nil when the style profile has none.
list_style_profiles returns an array of style profiles, one page at a time. It accepts
page: (0-indexed, default 0) and page_size: (default 10; values above 100 are reduced to
100).
profile = client.get_style_profile('YOUR_STYLE_PROFILE_ID')
profiles = client.list_style_profiles
profiles = client.list_style_profiles(page: 1, page_size: 100)update_style_profile takes the same keywords as create_style_profile, plus name.
Keywords you leave out (or set to nil) are not sent and leave the field unchanged. An
empty string clears description or industry. A component list you send replaces the
linked list in full; an empty array unlinks all components of that kind.
updated = client.update_style_profile(
'YOUR_STYLE_PROFILE_ID',
name: 'Legal, German (2026)',
industry: 'Legal',
description: '', # clears the description
style_rule_ids: [] # unlinks all style rule lists
)
updated.description
# => nildelete_style_profile returns nil.
client.delete_style_profile('YOUR_STYLE_PROFILE_ID')Pass the style_profile option, a style profile ID string or a StyleProfile object, to
translate_text, translate_document or translate_document_upload to apply the
profile's glossaries, style rule lists and translation memories. A component that does not
fit the language pair is left out. The option cannot be combined with glossary,
glossary_id, glossary_ids, style_rule, translation_memory,
translation_memory_threshold or custom_instructions; the API rejects such requests.
translation = client.translate_text('The artist is here.', nil, 'DE', style_profile: profile)
puts translation.text
# => Der Maler ist hier.
client.translate_document('/path/to/document.docx', '/path/to/translated.docx', 'EN', 'DE',
style_profile: 'YOUR_STYLE_PROFILE_ID')With documents, an unknown style profile is not rejected at upload: the translation fails
with a DeepL::Exceptions::DocumentTranslationError whose message contains
Style profile not found.
Translation memories allow you to store and reuse previously created translations. They can be used in text translation requests to improve consistency by matching against stored segments. Multiple translation memories can be stored with your account, each with a source language and one or more target languages.
Translation memories can also be managed in the DeepL UI via https://www.deepl.com/translation-memory.
DeepL::Client manages them with list_translation_memories,
get_translation_memory, list_translation_memory_segments,
import_translation_memory_from_filepath, export_translation_memory_to_filepath
and delete_translation_memory, plus the single steps of an import or export
described below. Every method that takes a translation memory accepts either a
string containing the translation memory ID or a TranslationMemory object, and
every method that takes a job accepts its ID or a TranslationMemoryJob.
list_translation_memories returns a list of TranslationMemory objects for
your stored translation memories, one page at a time. It accepts the optional
keywords page (page number for pagination, 0-indexed) and page_size (number
of items per page, max 25). Keywords left nil are not sent.
client = DeepL::Client.new(ENV.fetch('DEEPL_AUTH_KEY'))
# List translation memories
client.list_translation_memories.each do |tm|
puts "#{tm.name} (#{tm.translation_memory_id})"
puts " Source: #{tm.source_language}, Targets: #{tm.target_languages.join(', ')}"
puts " Segments: #{tm.segment_count}"
end
# List with pagination
translation_memories = client.list_translation_memories(page: 0, page_size: 10)get_translation_memory retrieves one translation memory. In addition to the
fields returned by list_translation_memories, the resource carries the
creation_time and updated_time timestamps (nil if the API sends none or a
malformed one).
tm = client.get_translation_memory('YOUR_TM_ID')
puts tm.class
# => DeepL::Resources::TranslationMemory
puts tm.name
# => 'Legal'
puts tm.segment_count
# => 12
puts tm.creation_time.class
# => Timelist_translation_memory_segments returns one page of the segments of a
translation memory as a TranslationMemorySegments object. Each segment holds
the source text and one target per target language of the translation memory.
Pagination is cursor-based: omit page_cursor on the first call, then pass the
next_page_cursor of the previous response until next_page? is false. The
method also accepts page_size (1-100, defaults to 50), filter_text (a
substring matched against the source and target texts, at least 2 characters)
and filter_case_sensitive (defaults to false). Keywords left nil are not
sent.
Note that segment_count is the number of segments stored in the translation
memory; a text filter does not reduce it.
page = client.list_translation_memory_segments('YOUR_TM_ID', page_size: 50)
puts page.class
# => DeepL::Resources::TranslationMemorySegments
puts page.segment_count
# => 12
puts page.segments.first.source_text
# => 'Quelltext Nummer 0'
puts page.segments.first.targets.first.target_text
# => 'Source text number 0'
# Walk through every page of segments
while page.next_page?
page = client.list_translation_memory_segments('YOUR_TM_ID',
page_size: 50,
page_cursor: page.next_page_cursor)
end
# Only the segments matching a text
page = client.list_translation_memory_segments('YOUR_TM_ID',
filter_text: 'Nummer 1',
filter_case_sensitive: true)import_translation_memory_from_filepath creates a new translation memory from
a TMX file. It creates the import job, uploads the file and waits until the job
is completed, and returns the TranslationMemoryJob. Its result carries the ID
of the newly created translation memory. The optional keywords are
display_name (the name of the translation memory, defaults to the file name),
content_type (the MIME type of the file, declared in the job and sent with the
upload, defaults to application/xml), timeout_s and extra_body_parameters
(fields added to the body of the import job request). It raises a
DeepL::Exceptions::Error with the API's error message if the job fails or
expires, and when timeout_s expires.
job = client.import_translation_memory_from_filepath('legal.tmx',
display_name: 'Legal',
timeout_s: 300)
puts job.class
# => DeepL::Resources::TranslationMemoryJob
puts job.status
# => 'completed'
puts job.result.translation_memory_id
# => 'a74d88fb-ed2a-4943-a664-a4512398b994'
puts job.result.skipped_segment_count
# => 0The three steps can also be performed separately with
create_translation_memory_import, upload_translation_memory_file and
wait_until_translation_memory_job_done, for example to upload a file that is
not available on the local file system. create_translation_memory_import
accepts content_type, display_name and extra_body_parameters; keywords left
nil are not sent. The upload URL is a pre-signed storage URL outside of the
DeepL API, so no authorization header and no configured headers are sent with
the upload; the proxy, SSL and timeout settings of the client apply.
content = File.binread('legal.tmx')
created = client.create_translation_memory_import('legal.tmx', content.bytesize,
content_type: 'application/xml',
display_name: 'Legal')
puts created.upload_url
# => 'https://...'
client.upload_translation_memory_file(created, content, content_type: 'application/xml')
job = client.wait_until_translation_memory_job_done(created.job_id)Until the file is uploaded the job stays in the awaiting_input status and
result.required_action describes what is missing. The API detects the upload
asynchronously, so the job keeps reporting awaiting_input for a while
afterwards, typically around half a minute, before it completes.
wait_until_translation_memory_job_done therefore polls through that status
like any other non-terminal one. A job whose file is never uploaded does not
finish on its own, so pass timeout_s when that is a possibility.
export_translation_memory_to_filepath writes a translation memory to a TMX
file. It creates the export job, waits until it is completed and downloads the
result, overwriting the output file if it already exists. It accepts
timeout_s and raises a DeepL::Exceptions::Error if the job fails or expires.
job = client.export_translation_memory_to_filepath('YOUR_TM_ID', 'export.tmx')
puts job.status
# => 'completed'The steps can be performed separately as well, with
create_translation_memory_export, wait_until_translation_memory_job_done and
download_translation_memory_export. Repeating the export of an unchanged
translation memory reuses the previously completed job instead of starting a new
one, which reused_existing? reports. Just like the upload URL, the download URL
is a pre-signed storage URL and is requested without an authorization header.
created = client.create_translation_memory_export('YOUR_TM_ID')
puts created.reused_existing?
# => false
job = client.wait_until_translation_memory_job_done(created.job_id)
puts job.result.download_url
# => 'https://...'
client.download_translation_memory_export(job, 'export.tmx')get_translation_memory_job returns the current status of an import or export
job, and wait_until_translation_memory_job_done polls it every five seconds
until it is completed, raising a DeepL::Exceptions::Error with the API's error
message if the job failed or expired. Pass timeout_s to give up after a number
of seconds instead of waiting forever.
done? is true once the job is completed, ok? is false once it failed or
expired (and true while it runs), and finished? is true for any terminal
status.
job = client.get_translation_memory_job('YOUR_JOB_ID')
puts job.operation
# => 'import'
puts job.status
# => 'processing'
puts [job.done?, job.ok?, job.finished?].inspect
# => [false, true, false]The status is one of awaiting_input, processing, completed, downloaded,
failed or expired.
delete_translation_memory deletes a translation memory. It returns nil.
client.delete_translation_memory('YOUR_TM_ID')The deprecated module-level DeepL.translation_memories (list, find,
segments, destroy, create_import, upload_file, import_from_filepath,
create_export, download_export, export_to_filepath, find_job,
wait_until_job_done) keeps working unchanged. Its import_from_filepath also
accepts content_type and extra_body_parameters, and create_import accepts
extra_body_parameters.
Pass the translation_memory option to translate_text to use a translation
memory. You can pass either a string containing the translation memory ID, or a
TranslationMemory object. Use translation_memory_threshold to control the
minimum matching percentage for fuzzy matches (0-100, recommended minimum of
75%).
# Using a translation memory ID
translation = client.translate_text('Hello, world!', 'EN', 'DE',
translation_memory: 'YOUR_TM_ID',
translation_memory_threshold: 80)
# Or using a TranslationMemory object
translation_memories = client.list_translation_memories
translation = client.translate_text('Hello, world!', 'EN', 'DE',
translation_memory: translation_memories.first)The same translation_memory and translation_memory_threshold options can be
passed to document translation via translate_document_upload (or
translate_document). The translation_memory option accepts either a
translation memory ID string or a TranslationMemory object:
handle = client.translate_document_upload('my_document.docx', 'EN', 'DE',
translation_memory: 'YOUR_TM_ID',
translation_memory_threshold: 80)To check current API usage, call get_usage. It returns a DeepL::Resources::Usage. Each
usage type is a DeepL::Resources::Usage::Detail with count, limit and limit_reached?:
character, plus document and team_document for accounts with a document limit.
any_limit_reached? checks character, document and team_document:
usage = client.get_usage
puts usage.character.count
# => 180118
puts usage.character.limit
# => 1250000
puts 'Translation limit reached.' if usage.any_limit_reached?
puts "Document usage: #{usage.document}" if usage.document
# => Document usage: 5 of 10DeepL.usage and the Usage readers character_count, character_limit and
quota_exceeded? are deprecated. Use client.get_usage, character.count,
character.limit and character.limit_reached? (or any_limit_reached?) instead.
For API Pro users, the response also contains this API key's usage, speech usage, the billing
period and a per-product breakdown. These fields are nil when the response does not contain
them (e.g. for API Free users). any_limit_reached? does not consider them; call
limit_reached? on them directly, e.g. usage.api_key_character.limit_reached?:
usage = client.get_usage
# Characters used by the whole account vs. by this API key
puts "account: #{usage.character}"
# => account: 5947223 of 1000000000000
puts "this key: #{usage.api_key_character}"
# => this key: 636 of 1000000000000
puts usage.speech_to_text_minutes # => 30 of 600
puts usage.speech_to_speech_minutes # => 12 of 600
puts usage.start_time # => 2025-05-13 09:18:42 UTC (Time)
puts usage.end_time # => 2025-06-13 09:18:42 UTC (Time)
usage.products&.each do |product|
# product_type and billing_unit are plain strings, e.g. 'translate' and 'characters'
puts "#{product.product_type}: key #{product.api_key_unit_count}, " \
"account #{product.account_unit_count} #{product.billing_unit}"
end
# => translate: key 636, account 5941580 charactersTo translate a document, use the translate_document method of DeepL::Client. It uploads
the document, waits until the translation is done and writes the translated document to the
output path, which must not exist yet. It returns the final
DeepL::Resources::DocumentTranslationStatus:
status = client.translate_document('/path/to/spanish_document.pdf',
'/path/to/translated_document.pdf', 'ES', 'EN')
puts status.billed_characters
# => 2045Every failure (also a failed translation) raises DeepL::Exceptions::DocumentTranslationError.
Once the upload succeeded, its document_handle is set, so you can still query the status and
download the document. timeout_s: limits the wait after the upload in seconds; by default
translate_document waits until the translation is done or failed:
begin
client.translate_document('/path/to/document.docx', '/path/to/translated.docx', 'EN', 'DE',
timeout_s: 600, formality: 'more')
rescue DeepL::Exceptions::DocumentTranslationError => e
puts "Translation failed: #{e.message}, document: #{e.document_handle&.document_id}"
endThe steps are also exposed. translate_document_upload returns a
DeepL::Resources::DocumentHandle (document_id, document_key).
translate_document_wait_until_done(handle, timeout_s: nil) queries the status every 5 seconds
until the translation is done and returns that status; it raises DeepL::Exceptions::Error
with the API's error message if the translation fails, and when timeout_s expires.
translate_document_get_status queries the status once, and translate_document_download
writes the translated document, overwriting an existing file; it raises
DeepL::Exceptions::DocumentNotReadyError if the translation is not done yet.
handle = client.translate_document_upload('/path/to/spanish_document.pdf', 'ES', 'EN',
filename: 'report.pdf')
status = client.translate_document_get_status(handle)
puts "#{status.status}, ok: #{status.ok?}, done: #{status.successful?}"
# => translating, ok: true, done: false
client.translate_document_wait_until_done(handle)
client.translate_document_download(handle, '/path/to/translated_document.pdf')A DeepL::Resources::DocumentTranslationStatus has document_id, status (a string;
DeepL::Constants::DocumentStatusCode has the values QUEUED, TRANSLATING, DONE and
ERROR), seconds_remaining, billed_characters and error_message, and the predicates
successful? (done), error? (failed), ok? (not failed, also while queued or translating)
and finished? (done or failed).
With the deprecated module-level API, the same methods are DeepL.document.translate_document,
upload, get_status and download, which take the filename as a positional parameter and
optional additional headers. DeepL.document.translate_document waits until the translation is
done or failed and returns the final status; the deprecated configuration setting
max_doc_status_queries limits the number of status requests. The deprecated
DocumentHandle#wait_until_document_translation_finished returns the final status also when
the translation failed.
doc_handle = DeepL.document.upload('/path/to/spanish_document.pdf', 'ES', 'EN')
doc_status = doc_handle.wait_until_document_translation_finished
DeepL.document.download(doc_handle, '/path/to/translated_document.pdf') unless doc_status.error?You can also pass additional options to document translation methods, including extra_body_parameters:
doc_handle = client.translate_document_upload('/path/to/spanish_document.pdf', 'ES', 'EN',
formality: 'more',
extra_body_parameters: { example_param: 'true' })Document translation options include:
filename(DeepL::Clientonly): the file name sent with the upload, including its extension. Defaults to the base name of the input path.formality: same as for text translation.glossary/glossary_ids: see the glossary sections above.glossary_idis deprecated, useglossary.output_format: file extension of the desired output format, e.g.'pdf'to translate adocxinto a PDF.enable_watermark:trueadds a "Translated by DeepL" watermark to the translated document. The API supports it only fordocxandpdfoutput and ignores it for other formats. When not set, the parameter is not sent.style_rule,style_profile,translation_memory,translation_memory_threshold: same as in text translation; see the style rules, style profiles and translation memory sections above.
client.translate_document('/path/to/document.docx', '/path/to/translated.pdf', 'EN', 'DE',
output_format: 'pdf', enable_watermark: true)The extra_body_parameters option allows you to pass arbitrary parameters in the request body. This can be used to access beta features by adding new parameters, or to override built-in parameters (such as target_lang, source_lang, etc.) for testing purposes.
The Admin API lets you manage the developer keys of your organization and retrieve usage analytics. It requires an admin API key, which you can create in the "Admin API Keys" tab of your DeepL account. Admin keys cannot be used for translation, and developer keys cannot access the Admin API: the API rejects a wrong key with DeepL::Exceptions::AuthorizationFailed.
Create a DeepL::AdminClient with your admin key. It is independent of DeepL.configure, does not read the DEEPL_AUTH_KEY and DEEPL_SERVER_URL environment variables, and uses the https://api.deepl.com server by default. The admin key is trimmed. It also accepts the server_url:, headers:, max_retries:, timeout:, proxy:, send_platform_info:, app_info:, http_client_options: and logger: keyword arguments of DeepL::Client; without server_url: it uses https://api.deepl.com, also for keys ending in :fx.
admin_client = DeepL::AdminClient.new('YOUR_ADMIN_KEY')key = admin_client.create_developer_key(label: 'Staging Team Key')
puts "Created #{key.label} (#{key.key_id})"
admin_client.list_developer_keys.each do |developer_key|
puts "#{developer_key.label}: deactivated=#{developer_key.deactivated?}"
end
key = admin_client.rename_developer_key(key, 'Production Team Key')
# Changes only the given limits; the others keep their current value.
# nil removes a limit (unlimited) and 0 blocks that usage.
key = admin_client.set_developer_key_usage_limits(key, characters: 500_000,
speech_to_text_milliseconds: 60_000)
key = admin_client.set_developer_key_usage_limits(key, speech_to_speech_milliseconds: nil)
# Deactivation is permanent.
admin_client.deactivate_developer_key(key)rename_developer_key, set_developer_key_usage_limits and deactivate_developer_key accept either a key ID or a DeepL::Resources::DeveloperKey object and return the updated DeepL::Resources::DeveloperKey. set_developer_key_usage_limits accepts characters:, speech_to_text_milliseconds: and speech_to_speech_milliseconds:. create_developer_key takes the label as the label: keyword argument; without it the API labels the key "DeepL API Key". Labels and limits are sent as given and validated by the API. create_developer_key, deactivate_developer_key, rename_developer_key and set_developer_key_usage_limits also accept extra_body_parameters:, a hash added to the request body last that replaces fields of the same name. A response without a key_id raises DeepL::Exceptions::Error. label and usage_limits are nil when the response does not contain them.
A failed create_developer_key request is retried only after HTTP 429, a DNS resolution error or a connection timeout, when the API cannot have created the key. Other requests are retried like all other requests of the library.
get_usage_analytics returns a DeepL::Resources::AdminUsageReport for a date range. Dates are UTC calendar days, and both the start day and the end day are included. They can be Date, Time or DateTime objects or YYYY-MM-DD strings. For Time and DateTime values the SDK sends the UTC date of that moment, so Time.new(2026, 10, 20, 0, 0, 0, '+02:00') is sent as 2026-10-19. An invalid date raises ArgumentError without sending a request. The API requires the end date to be after the start date, so a report covers at least two days, and at most 366 days after it; otherwise both analytics methods raise DeepL::Exceptions::BadRequest. Use group_by: to break the usage down by key (DeepL::Constants::AdminUsageGroupBy::KEY, see key_usages) or by key and day (DeepL::Constants::AdminUsageGroupBy::KEY_AND_DAY, see key_and_day_usages). The group_by of the report is the raw string the API returns. The usage breakdowns include speech_to_text_minutes and speech_to_speech_minutes.
report = admin_client.get_usage_analytics('2026-06-01', '2026-07-01',
group_by: DeepL::Constants::AdminUsageGroupBy::KEY)
puts "Total characters: #{report.total_usage.total_characters}"
report.key_usages.each do |key_usage|
puts "#{key_usage.api_key_label}: #{key_usage.usage.total_characters}"
endget_custom_tag_usage_analytics returns a DeepL::Resources::CustomTagUsageReport with the usage per custom tag, for a date range with the same limits. Use aggregate_by: to choose between the whole period (DeepL::Constants::CustomTagUsageAggregateBy::PERIOD, the default) and per-day usage (DeepL::Constants::CustomTagUsageAggregateBy::DAY). The results are paginated: pass the next_page value of a report as page: to get the next page. The aggregate_by of a custom tag report is the raw string the API returns.
page = nil
loop do
report = admin_client.get_custom_tag_usage_analytics('2026-06-01', '2026-07-01', page: page)
report.usage.each do |tag_usage|
puts "#{tag_usage.custom_tag}: #{tag_usage.breakdown.total_characters}"
end
break if report.next_page.nil?
page = report.next_page
endDeepL::Client.new(key, headers: { 'X-DeepL-Reporting-Tag' => 'my-tag' }) sends the headers
with every DeepL API request of that client. With the module-level API, you can pass additional HTTP headers to translate, rephrase, correct, and the
document methods. For example, to send the X-DeepL-Reporting-Tag header
for usage reporting (see the cookbook entry):
additional_headers = { 'X-DeepL-Reporting-Tag' => 'my-tag' }
translation = DeepL.translate 'Hello, world!', 'EN', 'DE', {}, additional_headers
rephrased = DeepL.rephrase 'Hello, world!', 'EN', nil, nil, {}, additional_headers
corrected = DeepL.correct 'Hello, world!', 'EN', {}, additional_headersYou can capture and process exceptions that may be raised during API calls. These are all the possible exceptions:
| Exception class | Description |
|---|---|
DeepL::Exceptions::AuthorizationFailed |
The authorization process has failed. Check your auth_key value. |
DeepL::Exceptions::BadRequest |
Something is wrong in your request. Check exception.message for more information. |
DeepL::Exceptions::ConnectionError |
No HTTP response after all retries (DNS, connection, TLS or timeout failure). The original exception is exception.cause. |
DeepL::Exceptions::DocumentNotReadyError |
A subclass of ServerError: HTTP 503 on a document download, the translated document is not ready yet. |
DeepL::Exceptions::DocumentTranslationError |
An error occured during document translation. Check exception.message for more information; exception.document_handle is the handle of the uploaded document, nil if the upload failed. |
DeepL::Exceptions::LimitExceeded |
You've reached the API's call limit. |
DeepL::Exceptions::QuotaExceeded |
You've reached the API's character limit. |
DeepL::Exceptions::RequestError |
Any other HTTP error status. Its message contains the status and the API's message; check exception.response and exception.request for more information. |
DeepL::Exceptions::NotSupported |
Deprecated, no longer raised by the library. |
DeepL::Exceptions::RequestEntityTooLarge |
Your request is too large, reduce the amount of data you are sending. The API has a request size limit of 128 KiB. |
DeepL::Exceptions::ServerError |
An error occured in the DeepL API (HTTP 5xx), raised after all retries. |
All of them are subclasses of DeepL::Exceptions::Error, which is also raised for a response
that cannot be parsed. Errors of an HTTP response carry the status as an Integer in
exception.http_status_code (nil otherwise).
An exampling of handling a generic exception:
def my_method
item = DeepL.translate 'This is my text', nil, 'ES'
rescue DeepL::Exceptions::RequestError => e
puts 'Oops!'
puts "Code: #{e.response.code}"
puts "Response body: #{e.response.body}"
puts "Request body: #{e.request.body}"
endTo enable logging, pass a suitable logging object (e.g. the default Logger from the Ruby standard library) when configuring the library. The library logs HTTP requests to INFO and debug information to DEBUG. Example:
require 'logger'
logger = Logger.new(STDOUT)
logger.level = Logger::INFO
deepl.configure do |config|
config.auth_key = configuration.auth_key
config.logger = logger
endRequests that fail with HTTP 429, any 5xx status or a network failure (DNS, refused or reset
connection, TLS error, timeout) are retried up to max_retries: times (default 5) with
exponential backoff. Each attempt has a timeout of timeout: seconds (default 10). After the
last retry, network failures raise DeepL::Exceptions::ConnectionError.
AdminClient#create_developer_key is only retried when the request was not sent (HTTP 429,
DNS failure, refused connection or connection timeout). With the module-level API, set
config.max_network_retries and config.timeout.
Pass a proxy URL to the client:
client = DeepL::Client.new(auth_key, proxy: 'http://user:password@localhost:3128')DeepL::HTTPClientOptions also takes the proxy as a URL or as a hash with proxy_addr and
proxy_port, together with certificate, SSL verification and timeout options. With the
module-level API, a session needs to be used; the proxy is configured as part of the HTTP client options:
client_options = HTTPClientOptions.new({ 'proxy_addr' => 'http://localhost', 'proxy_port' => 80 })
deepl.with_session(client_options) do |session|
# ...
endBy default, we send some basic information about the platform the client library is running on with each request, see here for an explanation. This data is completely anonymous and only used to improve our product, not track any individual users. If you do not wish to send this data, create the client with send_platform_info: false, or with the module-level API set the send_platform_info flag in the configuration to false like so:
deepl.configure({}, nil, nil, false) do |config|
# ...
endYou can also completely replace the User-Agent header with headers: { 'User-Agent' => 'myCustomUserAgent' }, or with the module-level API like so:
deepl.configure do |config|
config.user_agent = 'myCustomUserAgent'
endWhen writing an application that send multiple requests, using a HTTP session will give better performance through HTTP Keep-Alive. You can use it by simply wrapping your requests in a with_session block:
deepl.with_session do |session|
deepl.translate(sentence1, 'DE', 'EN-GB')
deepl.translate(sentence2, 'DE', 'EN-GB')
deepl.translate(sentence3, 'DE', 'EN-GB')
endIf you use this library in an application, please identify the application by setting the name and version of the plugin:
client = DeepL::Client.new(auth_key, app_info: { app_name: 'MyTranslationPlugin',
app_version: '1.0.1' })With the module-level API:
deepl.configure({}, 'MyTranslationPlugin', '1.0.1') do |config|
# ...
endThis information is passed along when the library makes calls to the DeepL API. Both name and version are required. Please note that setting the User-Agent header via deepl.configure will override this setting, if you need to use this, please manually identify your Application in the User-Agent header.
The available values for various possible options are provided under the DeepL::Constants namespace. The currently available options are
TagHandling
SplitSentences
ModelType
Formality
WritingStyle
Tone
To view all the possible options for a given constant, call options:
all_available_tones = DeepL::Constants::Tones.optionsTo check if a given string is a possible option for a given constant, call valid?:
DeepL::Constants::Tones.valid?('friendly') # true
DeepL::Constants::Tones.valid?('rude') # falseYou may use this gem as a standalone service by creating an initializer on your
config/initializers folder with your DeepL configuration. For example:
# config/initializers/deepl.rb
DeepL.configure do |config|
# Your configuration goes here
endSince the DeepL service is defined globally, you can use service anywhere in your code (controllers, models, views, jobs, plain ruby objects… you name it).
You may also take a look at i18n-tasks, which is a gem
that helps you find and manage missing and unused translations. deepl-rb is used as one of the
backend services to translate content.
Clone the repository, and install its dependencies:
git clone https://github.com/DeepLcom/deepl-rb
cd deepl-rb
bundle installThere are two suites of specs, which must run in separate processes:
-
spec/offlinetests options, validation, errors, retries and polling against intercepted requests (WebMock). It needs no key and no network:bundle exec rspec spec/offline -
spec/real_apisends every endpoint once to the real API. SetDEEPL_AUTH_KEYto a test key,DEEPL_ADMIN_KEYto an admin key for the Admin API specs, andDEEPL_SERVER_URLif the keys are not for the default server. The specs create resources namedsdktest-ruby-...and delete them again; developer keys cannot be deleted and are deactivated instead. The Admin API spec creates a key, renames it, sets its limits and deactivates it:DEEPL_AUTH_KEY=... DEEPL_ADMIN_KEY=... bundle exec rspec spec/real_api
To run the offline specs and rubocop, use
bundle exec rake test
This library was originally developed by Daniel Herzog, we are grateful for his contributions. Beginning with v3.0.0, DeepL took over development and officially supports and maintains the library together with Daniel.