deepl-rb 3.7.0 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/.gitlab-ci.yml +4 -2
  3. data/CHANGELOG.md +39 -1
  4. data/Gemfile +0 -2
  5. data/README.md +225 -16
  6. data/VERSION +1 -1
  7. data/deepl-rb.gemspec +52 -19
  8. data/lib/deepl/document_api.rb +11 -1
  9. data/lib/deepl/requests/base.rb +55 -3
  10. data/lib/deepl/requests/document/upload.rb +50 -1
  11. data/lib/deepl/requests/rephrase.rb +3 -2
  12. data/lib/deepl/requests/translate.rb +6 -3
  13. data/lib/deepl/requests/translation_memory/base.rb +47 -0
  14. data/lib/deepl/requests/translation_memory/create_export.rb +41 -0
  15. data/lib/deepl/requests/translation_memory/create_import.rb +53 -0
  16. data/lib/deepl/requests/translation_memory/destroy.rb +37 -0
  17. data/lib/deepl/requests/translation_memory/download_export.rb +35 -0
  18. data/lib/deepl/requests/translation_memory/find.rb +38 -0
  19. data/lib/deepl/requests/translation_memory/find_job.rb +38 -0
  20. data/lib/deepl/requests/translation_memory/list.rb +5 -18
  21. data/lib/deepl/requests/translation_memory/segments.rb +46 -0
  22. data/lib/deepl/requests/translation_memory/storage_base.rb +47 -0
  23. data/lib/deepl/requests/translation_memory/upload_file.rb +47 -0
  24. data/lib/deepl/resources/translation_memory.rb +4 -1
  25. data/lib/deepl/resources/translation_memory_export.rb +37 -0
  26. data/lib/deepl/resources/translation_memory_import.rb +29 -0
  27. data/lib/deepl/resources/translation_memory_job.rb +142 -0
  28. data/lib/deepl/resources/translation_memory_segments.rb +78 -0
  29. data/lib/deepl/translation_memory_api.rb +293 -1
  30. data/lib/deepl/utils/time_parser.rb +26 -0
  31. data/lib/deepl.rb +38 -4
  32. data/lib/version.rb +1 -1
  33. data/spec/api/deepl_spec.rb +134 -332
  34. data/spec/integration_tests/document_api_spec.rb +51 -18
  35. data/spec/integration_tests/document_error_paths_spec.rb +33 -0
  36. data/spec/integration_tests/glossary_api_spec.rb +114 -0
  37. data/spec/integration_tests/glossary_error_paths_spec.rb +107 -0
  38. data/spec/integration_tests/integration_test_utils.rb +8 -0
  39. data/spec/integration_tests/languages_api_spec.rb +54 -0
  40. data/spec/integration_tests/languages_error_paths_spec.rb +25 -0
  41. data/spec/integration_tests/rephrase_api_spec.rb +90 -0
  42. data/spec/integration_tests/rephrase_error_paths_spec.rb +53 -0
  43. data/spec/integration_tests/smoke_test_spec.rb +24 -0
  44. data/spec/integration_tests/style_rule_api_spec.rb +1 -19
  45. data/spec/integration_tests/style_rule_error_paths_spec.rb +45 -0
  46. data/spec/integration_tests/translate_api_spec.rb +117 -0
  47. data/spec/integration_tests/translate_error_paths_spec.rb +48 -0
  48. data/spec/integration_tests/translation_memory_api_spec.rb +191 -17
  49. data/spec/integration_tests/translation_memory_error_paths_spec.rb +87 -0
  50. data/spec/integration_tests/usage_api_spec.rb +29 -0
  51. data/spec/integration_tests/usage_error_paths_spec.rb +18 -0
  52. data/spec/requests/document/upload_spec.rb +130 -0
  53. data/spec/requests/glossary/create_spec.rb +0 -21
  54. data/spec/requests/glossary/destroy_spec.rb +0 -39
  55. data/spec/requests/glossary/entries_spec.rb +0 -35
  56. data/spec/requests/glossary/find_spec.rb +0 -40
  57. data/spec/requests/glossary/language_pairs_spec.rb +0 -13
  58. data/spec/requests/glossary/list_spec.rb +0 -27
  59. data/spec/requests/languages_spec.rb +0 -41
  60. data/spec/requests/rephrase_spec.rb +13 -139
  61. data/spec/requests/style_rule/create_custom_instruction_spec.rb +0 -24
  62. data/spec/requests/style_rule/create_spec.rb +0 -16
  63. data/spec/requests/style_rule/destroy_custom_instruction_spec.rb +0 -26
  64. data/spec/requests/style_rule/destroy_spec.rb +0 -27
  65. data/spec/requests/style_rule/find_custom_instruction_spec.rb +0 -27
  66. data/spec/requests/style_rule/find_spec.rb +0 -28
  67. data/spec/requests/style_rule/list_spec.rb +0 -31
  68. data/spec/requests/style_rule/update_configured_rules_spec.rb +0 -21
  69. data/spec/requests/style_rule/update_custom_instruction_spec.rb +0 -26
  70. data/spec/requests/style_rule/update_spec.rb +0 -19
  71. data/spec/requests/translate_spec.rb +63 -217
  72. data/spec/requests/translation_memory/create_export_spec.rb +37 -0
  73. data/spec/requests/translation_memory/create_import_spec.rb +61 -0
  74. data/spec/requests/translation_memory/destroy_spec.rb +36 -0
  75. data/spec/requests/translation_memory/download_export_spec.rb +54 -0
  76. data/spec/requests/translation_memory/find_job_spec.rb +37 -0
  77. data/spec/requests/translation_memory/find_spec.rb +36 -0
  78. data/spec/requests/translation_memory/list_spec.rb +0 -34
  79. data/spec/requests/translation_memory/segments_spec.rb +58 -0
  80. data/spec/requests/translation_memory/upload_file_spec.rb +55 -0
  81. data/spec/requests/usage_spec.rb +0 -16
  82. data/spec/resources/custom_instruction_spec.rb +32 -0
  83. data/spec/resources/style_rule_spec.rb +68 -0
  84. data/spec/resources/translation_memory_export_spec.rb +38 -0
  85. data/spec/resources/translation_memory_import_spec.rb +30 -0
  86. data/spec/resources/translation_memory_job_spec.rb +109 -0
  87. data/spec/resources/translation_memory_segments_spec.rb +78 -0
  88. data/spec/resources/translation_memory_spec.rb +18 -1
  89. data/spec/spec_helper.rb +15 -45
  90. data/spec/support/live_mock_server.rb +12 -0
  91. data/spec/support/managed_glossary.rb +65 -0
  92. data/spec/support/managed_style_rule.rb +17 -0
  93. data/spec/support/managed_translation_memory.rb +55 -0
  94. metadata +50 -17
  95. data/spec/fixtures/vcr_cassettes/deepl_document.yml +0 -95
  96. data/spec/fixtures/vcr_cassettes/deepl_document_download.yml +0 -1214
  97. data/spec/fixtures/vcr_cassettes/deepl_glossaries.yml +0 -1163
  98. data/spec/fixtures/vcr_cassettes/deepl_languages.yml +0 -54
  99. data/spec/fixtures/vcr_cassettes/deepl_rephrase.yml +0 -87
  100. data/spec/fixtures/vcr_cassettes/deepl_translate.yml +0 -358
  101. data/spec/fixtures/vcr_cassettes/deepl_usage.yml +0 -129
  102. data/spec/fixtures/vcr_cassettes/glossaries.yml +0 -1702
  103. data/spec/fixtures/vcr_cassettes/languages.yml +0 -229
  104. data/spec/fixtures/vcr_cassettes/rephrase_texts.yml +0 -401
  105. data/spec/fixtures/vcr_cassettes/style_rules.yml +0 -92
  106. data/spec/fixtures/vcr_cassettes/style_rules_crud.yml +0 -926
  107. data/spec/fixtures/vcr_cassettes/translate_texts.yml +0 -10630
  108. data/spec/fixtures/vcr_cassettes/translation_memories.yml +0 -74
  109. data/spec/fixtures/vcr_cassettes/usage.yml +0 -171
@@ -29,30 +29,4 @@ describe DeepL::Requests::StyleRule::UpdateCustomInstruction do
29
29
  end
30
30
  end
31
31
  end
32
-
33
- describe '#request' do
34
- around do |example|
35
- VCR.use_cassette('style_rules_crud') { example.call }
36
- end
37
-
38
- context 'when performing a valid request' do
39
- subject(:update_instruction) do
40
- described_class.new(api, new_rule.style_id, new_instruction.id, label, prompt)
41
- end
42
-
43
- let(:new_rule) do
44
- DeepL::Requests::StyleRule::Create.new(api, 'Update Instruction Test', 'en').request
45
- end
46
- let(:new_instruction) do
47
- DeepL::Requests::StyleRule::CreateCustomInstruction.new(
48
- api, new_rule.style_id, 'Original', 'Original prompt'
49
- ).request
50
- end
51
-
52
- it 'returns a custom instruction object' do
53
- instruction = update_instruction.request
54
- expect(instruction).to be_a(DeepL::Resources::CustomInstruction)
55
- end
56
- end
57
- end
58
32
  end
@@ -26,23 +26,4 @@ describe DeepL::Requests::StyleRule::Update do
26
26
  end
27
27
  end
28
28
  end
29
-
30
- describe '#request' do
31
- around do |example|
32
- VCR.use_cassette('style_rules_crud') { example.call }
33
- end
34
-
35
- context 'when performing a valid request' do
36
- subject(:update) { described_class.new(api, new_rule.style_id, 'Updated Name') }
37
-
38
- let(:new_rule) do
39
- DeepL::Requests::StyleRule::Create.new(api, 'Update Test', 'en').request
40
- end
41
-
42
- it 'returns a style rule object' do
43
- style_rule = update.request
44
- expect(style_rule).to be_a(DeepL::Resources::StyleRule)
45
- end
46
- end
47
- end
48
29
  end
@@ -190,6 +190,61 @@ describe DeepL::Requests::Translate do
190
190
  end
191
191
  end
192
192
 
193
+ context 'when using `glossary_ids` options' do
194
+ it 'works with a nil value' do
195
+ request = described_class.new(api, nil, nil, nil, glossary_ids: nil)
196
+ expect(request.options[:glossary_ids]).to be_nil
197
+ end
198
+
199
+ it 'works with an array of strings' do
200
+ request = described_class.new(api, nil, nil, nil, glossary_ids: %w[id1 id2])
201
+ expect(request.options[:glossary_ids]).to eq(%w[id1 id2])
202
+ end
203
+ end
204
+
205
+ context 'when building the `glossary_ids` request parameter' do
206
+ def glossary_ids_param(source_lang, options)
207
+ described_class.new(api, text, source_lang, target_lang, options)
208
+ .send(:build_glossary_ids_param, source_lang)
209
+ end
210
+
211
+ it 'returns nil when `glossary_ids` is not provided' do
212
+ expect(glossary_ids_param('EN', {})).to be_nil
213
+ end
214
+
215
+ it 'returns nil when `glossary_ids` is nil' do
216
+ expect(glossary_ids_param('EN', { glossary_ids: nil })).to be_nil
217
+ end
218
+
219
+ it 'returns nil when `glossary_ids` is an empty array' do
220
+ expect(glossary_ids_param('EN', { glossary_ids: [] })).to be_nil
221
+ end
222
+
223
+ it 'resolves an array of IDs to an array of strings' do
224
+ expect(glossary_ids_param('EN', { glossary_ids: %w[id1 id2 id3] })).to eq(%w[id1 id2 id3])
225
+ end
226
+
227
+ it 'resolves glossary objects to their IDs' do
228
+ glossary = DeepL::Resources::Glossary.new({ 'glossary_id' => 'obj_id' }, nil, nil)
229
+ expect(glossary_ids_param('EN', { glossary_ids: [glossary, 'id2'] })).to eq(%w[obj_id id2])
230
+ end
231
+
232
+ it 'raises when `source_lang` is not set' do
233
+ expect { glossary_ids_param(nil, { glossary_ids: %w[id1] }) }
234
+ .to raise_error(ArgumentError, /requires `source_lang`/)
235
+ end
236
+
237
+ it 'raises when combined with the singular `glossary_id` option' do
238
+ expect { glossary_ids_param('EN', { glossary_id: 'single', glossary_ids: %w[id1] }) }
239
+ .to raise_error(ArgumentError, /cannot be used together with the `glossary_id`/)
240
+ end
241
+
242
+ it 'raises when more than 5 IDs are provided' do
243
+ expect { glossary_ids_param('EN', { glossary_ids: %w[id1 id2 id3 id4 id5 id6] }) }
244
+ .to raise_error(ArgumentError, /maximum of 5 glossary IDs/)
245
+ end
246
+ end
247
+
193
248
  context 'when using `formality` options' do
194
249
  it 'works with a nil values' do
195
250
  request = described_class.new(api, nil, nil, nil, formality: nil)
@@ -266,226 +321,17 @@ describe DeepL::Requests::Translate do
266
321
  expect(request.options[:custom_instructions]).to eq(['Use informal language', 'Be concise'])
267
322
  end
268
323
  end
269
- end
270
-
271
- describe '#request' do
272
- around do |example|
273
- VCR.use_cassette('translate_texts') { example.call }
274
- end
275
-
276
- context 'when performing a valid request with one text' do
277
- it 'returns a text object' do
278
- text = translate.request
279
-
280
- expect(text).to be_a(DeepL::Resources::Text)
281
- expect(text.text).to eq('Texto de muestra')
282
- expect(text.detected_source_language).to eq('EN')
283
- end
284
- end
285
-
286
- context 'when performing a valid request with multiple texts' do
287
- let(:text) { %w[Sample Word] }
288
-
289
- it 'returns a text object' do
290
- texts = translate.request
291
-
292
- expect(texts).to be_a(Array)
293
- expect(texts.first.text).to eq('Muestra')
294
- expect(texts.first.detected_source_language).to eq('EN')
295
-
296
- expect(texts.last.text).to eq('Palabra')
297
- expect(texts.last.detected_source_language).to eq('EN')
298
- end
299
- end
300
-
301
- context 'when performing a valid request with tag handling' do
302
- let(:text) { '<p>Sample text</p>' }
303
- let(:options) { { tag_handling: 'xml' } }
304
-
305
- it 'returns a text object' do
306
- text = translate.request
307
-
308
- expect(text).to be_a(DeepL::Resources::Text)
309
- expect(text.text).to eq('<p>Texto de muestra</p>')
310
- expect(text.detected_source_language).to eq('EN')
311
- end
312
- end
313
324
 
314
- context 'when performing a valid request and passing a variable' do
315
- let(:text) { 'Welcome and <code>Hello great World</code> Good Morning!' }
316
- let(:options) { { tag_handling: 'xml', ignore_tags: %w[code span] } }
317
-
318
- it 'returns a text object' do
319
- text = translate.request
320
-
321
- expect(text).to be_a(DeepL::Resources::Text)
322
- expect(text.text).to eq('Bienvenido y <code>Hello great World</code> ¡Buenos días!')
323
- expect(text.detected_source_language).to eq('EN')
324
- end
325
- end
326
-
327
- context 'when performing a valid request with an HTML document' do
328
- let(:text) do
329
- <<~XML
330
- <document>
331
- <meta>
332
- <title>A document's title</title>
333
- </meta>
334
- <content>
335
- <par>This is the first sentence. Followed by a second one.</par>
336
- <par>This is the third sentence.</par>
337
- </content>
338
- </document>
339
- XML
340
- end
341
- let(:options) do
342
- {
343
- tag_handling: 'xml',
344
- split_sentences: 'nonewlines',
345
- outline_detection: false,
346
- splitting_tags: %w[title par]
347
- }
348
- end
349
-
350
- it 'returns a text object' do
351
- text = translate.request
352
-
353
- expect(text).to be_a(DeepL::Resources::Text)
354
- expect(text.text).to eq(
355
- <<~XML
356
- <document>
357
- <meta>
358
- <title>Título de un documento</title>
359
- </meta>
360
- <content>
361
- <par>Es la primera frase. Seguido de una segunda.</par>
362
- <par>Esta es la tercera frase.</par>
363
- </content>
364
- </document>
365
- XML
366
- )
367
- expect(text.detected_source_language).to eq('EN')
368
- end
369
- end
370
-
371
- context 'when performing a valid request with context' do
372
- let(:text) { 'That is hot!' }
373
-
374
- context 'when context is empty' do
375
- let(:options) { { context: '' } }
376
-
377
- it 'translates correctly with empty context' do
378
- res = translate.request
379
- expect(res).to be_a(DeepL::Resources::Text)
380
- expect(res.text).to eq('¡Eso está caliente!')
381
- end
382
- end
383
-
384
- context 'when context is set' do
385
- let(:options) { { context: 'He did not like the jalapenos in his meal.' } }
386
-
387
- it 'translates correctly with context taken into account' do
388
- res = translate.request
389
- expect(res).to be_a(DeepL::Resources::Text)
390
- expect(res.text).to eq('¡Eso es picante!')
391
- end
392
- end
393
- end
394
-
395
- context 'when performing a request with a model type' do
396
- let(:target_lang) { 'DE' }
397
-
398
- %w[quality_optimized latency_optimized prefer_quality_optimized].each do |model_type_str|
399
- it "translates correctly with #{model_type_str} models" do
400
- options = { model_type: model_type_str }
401
- translate = described_class.new(api, text, source_lang, target_lang, options)
402
- res = translate.request
403
- expect(res).to be_a(DeepL::Resources::Text)
404
- expect(res.model_type_used).not_to be_nil
405
- end
406
- end
407
- end
408
-
409
- context 'when performing a request with extra_body_parameters' do
410
- it 'allows extra parameters to override standard parameters' do
411
- extra_options = { extra_body_parameters: { target_lang: 'FR', debug: '1' } }
412
- translate = described_class.new(api, text, source_lang, target_lang, extra_options)
413
- res = translate.request
414
-
415
- expect(res).to be_a(DeepL::Resources::Text)
416
- expect(res.text).to eq('Texte modèle')
417
- expect(res.detected_source_language).to eq('EN')
325
+ context 'when passing additional headers' do
326
+ it 'merges the headers into the request headers' do
327
+ request = described_class.new(api, nil, nil, nil, {},
328
+ { 'X-DeepL-Reporting-Tag' => 'my-tag' })
329
+ expect(request.send(:headers)).to include('X-DeepL-Reporting-Tag' => 'my-tag')
418
330
  end
419
- end
420
-
421
- context 'when performing a request with custom_instructions' do
422
- let(:text) { 'Hello world' }
423
- let(:target_lang) { 'DE' }
424
-
425
- it 'includes custom_instructions in the payload' do
426
- options = { custom_instructions: ['Use formal language', 'Be concise'] }
427
- translate = described_class.new(api, text, source_lang, target_lang, options)
428
-
429
- # Verify the options are properly stored
430
- expect(translate.options[:custom_instructions]).to eq(['Use formal language', 'Be concise'])
431
- end
432
- end
433
-
434
- context 'when performing a request with tag_handling_version' do
435
- let(:text) { '<p>Hello world</p>' }
436
- let(:target_lang) { 'DE' }
437
-
438
- %w[v1 v2].each do |version|
439
- it "translates correctly with tag_handling_version #{version}" do
440
- options = { tag_handling: 'html', tag_handling_version: version }
441
- translate = described_class.new(api, text, source_lang, target_lang, options)
442
- res = translate.request
443
-
444
- expect(res).to be_a(DeepL::Resources::Text)
445
- expect(res.text).not_to be_nil
446
- expect(res.text).not_to be_empty
447
- end
448
- end
449
- end
450
-
451
- context 'when performing a bad request' do
452
- context 'when using an invalid token' do
453
- let(:api) do
454
- api = build_deepl_api
455
- api.configuration.auth_key = 'invalid'
456
- api
457
- end
458
-
459
- it 'raises an unauthorized error' do
460
- expect { translate.request }.to raise_error(DeepL::Exceptions::AuthorizationFailed)
461
- end
462
- end
463
-
464
- context 'when using an invalid text' do
465
- let(:text) { nil }
466
-
467
- it 'raises a bad request error' do
468
- message = "Invalid request: Expected 'text' parameter to be an array of strings"
469
- expect { translate.request }.to raise_error(DeepL::Exceptions::BadRequest, message)
470
- end
471
- end
472
-
473
- context 'when using an invalid target language' do
474
- let(:target_lang) { nil }
475
-
476
- it 'raises a bad request error' do
477
- message = "Value for 'target_lang' not supported."
478
- expect { translate.request }.to raise_error(DeepL::Exceptions::BadRequest, message)
479
- end
480
- end
481
- end
482
-
483
- context 'when performing a request with too many texts' do
484
- let(:text) { Array.new(10_000) { |i| "This is the sentence number #{i}" } }
485
331
 
486
- it 'raises a request entity too large error' do
487
- expect { translate.request }.to raise_error(DeepL::Exceptions::RequestEntityTooLarge,
488
- /request size has reached the supported limit/)
332
+ it 'defaults to no additional headers' do
333
+ request = described_class.new(api, nil, nil, nil)
334
+ expect(request.send(:headers).keys).to contain_exactly('Authorization', 'User-Agent')
489
335
  end
490
336
  end
491
337
  end
@@ -0,0 +1,37 @@
1
+ # Copyright 2026 DeepL SE (https://www.deepl.com)
2
+ # Use of this source code is governed by an MIT
3
+ # license that can be found in the LICENSE.md file.
4
+ # frozen_string_literal: true
5
+
6
+ require 'spec_helper'
7
+
8
+ describe DeepL::Requests::TranslationMemory::CreateExport do
9
+ subject(:translation_memory_create_export) { described_class.new(api, id, options) }
10
+
11
+ around do |tests|
12
+ tmp_env = replace_env_preserving_deepl_vars_except_mock_server
13
+ tests.call
14
+ ENV.replace(tmp_env)
15
+ end
16
+
17
+ let(:api) { build_deepl_api }
18
+ let(:id) { 'a74d88fb-ed2a-4943-a664-a4512398b994' }
19
+ let(:options) { {} }
20
+
21
+ describe '#initialize' do
22
+ context 'when building a request' do
23
+ it 'creates a request object' do
24
+ expect(translation_memory_create_export).to be_a(described_class)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe '#to_s' do
30
+ context 'when building a request' do
31
+ it 'posts to the export endpoint below the v3 prefix' do
32
+ expect(translation_memory_create_export.to_s)
33
+ .to eq("POST /v3/translation_memories/#{id}/export")
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,61 @@
1
+ # Copyright 2026 DeepL SE (https://www.deepl.com)
2
+ # Use of this source code is governed by an MIT
3
+ # license that can be found in the LICENSE.md file.
4
+ # frozen_string_literal: true
5
+
6
+ require 'spec_helper'
7
+
8
+ describe DeepL::Requests::TranslationMemory::CreateImport do
9
+ subject(:translation_memory_create_import) do
10
+ described_class.new(api, file_name, content_length, options)
11
+ end
12
+
13
+ around do |tests|
14
+ tmp_env = replace_env_preserving_deepl_vars_except_mock_server
15
+ tests.call
16
+ ENV.replace(tmp_env)
17
+ end
18
+
19
+ let(:api) { build_deepl_api }
20
+ let(:file_name) { 'legal.tmx' }
21
+ let(:content_length) { 128 }
22
+ let(:options) { {} }
23
+
24
+ describe '#initialize' do
25
+ context 'when building a request' do
26
+ it 'creates a request object' do
27
+ expect(translation_memory_create_import).to be_a(described_class)
28
+ end
29
+ end
30
+ end
31
+
32
+ describe '#to_s' do
33
+ context 'when building a request' do
34
+ it 'posts to the import endpoint below the v3 prefix' do
35
+ expect(translation_memory_create_import.to_s)
36
+ .to eq('POST /v3/translation_memories/import')
37
+ end
38
+ end
39
+ end
40
+
41
+ describe '#details' do
42
+ context 'when only the required parameters are given' do
43
+ it 'declares the source file without the optional fields' do
44
+ expect(translation_memory_create_import.details).to include('legal.tmx', '128')
45
+ expect(translation_memory_create_import.details).not_to include('content_type')
46
+ expect(translation_memory_create_import.details).not_to include('parameters')
47
+ end
48
+ end
49
+
50
+ context 'when the optional parameters are given' do
51
+ let(:options) { { content_type: 'text/xml', display_name: 'Legal' } }
52
+
53
+ it 'declares the content type and the display name' do
54
+ expect(translation_memory_create_import.details)
55
+ .to include('content_type', 'text/xml')
56
+ expect(translation_memory_create_import.details)
57
+ .to include('parameters', 'display_name', 'Legal')
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,36 @@
1
+ # Copyright 2026 DeepL SE (https://www.deepl.com)
2
+ # Use of this source code is governed by an MIT
3
+ # license that can be found in the LICENSE.md file.
4
+ # frozen_string_literal: true
5
+
6
+ require 'spec_helper'
7
+
8
+ describe DeepL::Requests::TranslationMemory::Destroy do
9
+ subject(:translation_memory_destroy) { described_class.new(api, id, options) }
10
+
11
+ around do |tests|
12
+ tmp_env = replace_env_preserving_deepl_vars_except_mock_server
13
+ tests.call
14
+ ENV.replace(tmp_env)
15
+ end
16
+
17
+ let(:api) { build_deepl_api }
18
+ let(:id) { 'a74d88fb-ed2a-4943-a664-a4512398b994' }
19
+ let(:options) { {} }
20
+
21
+ describe '#initialize' do
22
+ context 'when building a request' do
23
+ it 'creates a request object' do
24
+ expect(translation_memory_destroy).to be_a(described_class)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe '#to_s' do
30
+ context 'when building a request' do
31
+ it 'deletes the translation memory below the v3 prefix' do
32
+ expect(translation_memory_destroy.to_s).to eq("DELETE /v3/translation_memories/#{id}")
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,54 @@
1
+ # Copyright 2026 DeepL SE (https://www.deepl.com)
2
+ # Use of this source code is governed by an MIT
3
+ # license that can be found in the LICENSE.md file.
4
+ # frozen_string_literal: true
5
+
6
+ require 'spec_helper'
7
+
8
+ describe DeepL::Requests::TranslationMemory::DownloadExport do
9
+ subject(:download_export) { described_class.new(api, download_url, output_path) }
10
+
11
+ around do |tests|
12
+ tmp_env = replace_env_preserving_deepl_vars_except_mock_server
13
+ tests.call
14
+ ENV.replace(tmp_env)
15
+ end
16
+
17
+ let(:api) { build_deepl_api }
18
+ let(:download_url) { 'https://storage.example.com/download/tm?signature=abc' }
19
+ let(:output_path) { '/tmp/export.tmx' }
20
+
21
+ describe '#initialize' do
22
+ context 'when building a request' do
23
+ it 'creates a request object' do
24
+ expect(download_export).to be_a(described_class)
25
+ end
26
+ end
27
+
28
+ context 'when no download URL is given' do
29
+ let(:download_url) { nil }
30
+
31
+ it 'raises an error' do
32
+ expect { download_export }.to raise_error(DeepL::Exceptions::Error, /must not be empty/)
33
+ end
34
+ end
35
+ end
36
+
37
+ describe '#to_s' do
38
+ context 'when building a request' do
39
+ it 'gets from the pre-signed storage URL' do
40
+ expect(download_export.to_s).to eq('GET /download/tm?signature=abc')
41
+ end
42
+ end
43
+ end
44
+
45
+ describe '#details' do
46
+ context 'when building a request' do
47
+ # The download URL points outside of the DeepL API, so the auth key must not be sent there.
48
+ it 'does not send the DeepL authorization header' do
49
+ expect(download_export.details).not_to include('Authorization')
50
+ expect(download_export.details).to include('User-Agent')
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,37 @@
1
+ # Copyright 2026 DeepL SE (https://www.deepl.com)
2
+ # Use of this source code is governed by an MIT
3
+ # license that can be found in the LICENSE.md file.
4
+ # frozen_string_literal: true
5
+
6
+ require 'spec_helper'
7
+
8
+ describe DeepL::Requests::TranslationMemory::FindJob do
9
+ subject(:translation_memory_find_job) { described_class.new(api, job_id, options) }
10
+
11
+ around do |tests|
12
+ tmp_env = replace_env_preserving_deepl_vars_except_mock_server
13
+ tests.call
14
+ ENV.replace(tmp_env)
15
+ end
16
+
17
+ let(:api) { build_deepl_api }
18
+ let(:job_id) { '5b1a0a52-1f3b-4b7f-9f6b-9d4d3f5b6c7d' }
19
+ let(:options) { {} }
20
+
21
+ describe '#initialize' do
22
+ context 'when building a request' do
23
+ it 'creates a request object' do
24
+ expect(translation_memory_find_job).to be_a(described_class)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe '#to_s' do
30
+ context 'when building a request' do
31
+ it 'requests the job below the v3 prefix' do
32
+ expect(translation_memory_find_job.to_s)
33
+ .to eq("GET /v3/translation_memories/jobs/#{job_id}")
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,36 @@
1
+ # Copyright 2026 DeepL SE (https://www.deepl.com)
2
+ # Use of this source code is governed by an MIT
3
+ # license that can be found in the LICENSE.md file.
4
+ # frozen_string_literal: true
5
+
6
+ require 'spec_helper'
7
+
8
+ describe DeepL::Requests::TranslationMemory::Find do
9
+ subject(:translation_memory_find) { described_class.new(api, id, options) }
10
+
11
+ around do |tests|
12
+ tmp_env = replace_env_preserving_deepl_vars_except_mock_server
13
+ tests.call
14
+ ENV.replace(tmp_env)
15
+ end
16
+
17
+ let(:api) { build_deepl_api }
18
+ let(:id) { 'a74d88fb-ed2a-4943-a664-a4512398b994' }
19
+ let(:options) { {} }
20
+
21
+ describe '#initialize' do
22
+ context 'when building a request' do
23
+ it 'creates a request object' do
24
+ expect(translation_memory_find).to be_a(described_class)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe '#to_s' do
30
+ context 'when building a request' do
31
+ it 'requests the translation memory below the v3 prefix' do
32
+ expect(translation_memory_find.to_s).to eq("GET /v3/translation_memories/#{id}")
33
+ end
34
+ end
35
+ end
36
+ end
@@ -24,38 +24,4 @@ describe DeepL::Requests::TranslationMemory::List do
24
24
  end
25
25
  end
26
26
  end
27
-
28
- describe '#request' do
29
- around do |example|
30
- VCR.use_cassette('translation_memories') { example.call }
31
- end
32
-
33
- context 'when requesting a list of all translation memories' do
34
- it 'returns an array of translation memories' do
35
- translation_memories = translation_memory_list.request
36
- expect(translation_memories).to be_an(Array)
37
- expect(translation_memories).not_to be_empty
38
- expect(translation_memories.first).to be_a(DeepL::Resources::TranslationMemory)
39
- expect(translation_memories.first.translation_memory_id).to be_a(String)
40
- expect(translation_memories.first.name).to be_a(String)
41
- expect(translation_memories.first.source_language).to be_a(String)
42
- expect(translation_memories.first.target_languages).to be_an(Array)
43
- expect(translation_memories.first.segment_count).to be_an(Integer)
44
- end
45
- end
46
-
47
- context 'when performing a bad request' do
48
- context 'when using an invalid token' do
49
- let(:api) do
50
- api = build_deepl_api
51
- api.configuration.auth_key = 'invalid'
52
- api
53
- end
54
-
55
- it 'raises an authorization failed error' do
56
- expect { translation_memory_list.request }.to raise_error(DeepL::Exceptions::AuthorizationFailed)
57
- end
58
- end
59
- end
60
- end
61
27
  end