deepl-rb 3.6.1 → 3.8.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.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +8 -1
- data/CHANGELOG.md +35 -1
- data/Gemfile +0 -2
- data/README.md +165 -34
- data/Rakefile +2 -0
- data/VERSION +1 -1
- data/deepl-rb.gemspec +52 -20
- data/lib/deepl/requests/base.rb +16 -0
- data/lib/deepl/requests/document/upload.rb +6 -5
- data/lib/deepl/requests/rephrase.rb +3 -2
- data/lib/deepl/requests/style_rule/create.rb +46 -0
- data/lib/deepl/requests/style_rule/create_custom_instruction.rb +45 -0
- data/lib/deepl/requests/style_rule/destroy.rb +39 -0
- data/lib/deepl/requests/style_rule/destroy_custom_instruction.rb +40 -0
- data/lib/deepl/requests/style_rule/find.rb +40 -0
- data/lib/deepl/requests/style_rule/find_custom_instruction.rb +41 -0
- data/lib/deepl/requests/style_rule/update.rb +42 -0
- data/lib/deepl/requests/style_rule/update_configured_rules.rb +41 -0
- data/lib/deepl/requests/style_rule/update_custom_instruction.rb +47 -0
- data/lib/deepl/requests/translate.rb +17 -4
- data/lib/deepl/requests/translation_memory/list.rb +58 -0
- data/lib/deepl/resources/style_rule.rb +2 -1
- data/lib/deepl/resources/translation_memory.rb +25 -0
- data/lib/deepl/style_rule_api.rb +44 -0
- data/lib/deepl/translation_memory_api.rb +17 -0
- data/lib/deepl.rb +75 -55
- data/lib/version.rb +1 -1
- data/spec/api/deepl_spec.rb +134 -332
- data/spec/integration_tests/document_api_spec.rb +4 -18
- data/spec/integration_tests/document_error_paths_spec.rb +33 -0
- data/spec/integration_tests/glossary_api_spec.rb +114 -0
- data/spec/integration_tests/glossary_error_paths_spec.rb +107 -0
- data/spec/integration_tests/languages_api_spec.rb +54 -0
- data/spec/integration_tests/languages_error_paths_spec.rb +25 -0
- data/spec/integration_tests/rephrase_api_spec.rb +90 -0
- data/spec/integration_tests/rephrase_error_paths_spec.rb +53 -0
- data/spec/integration_tests/smoke_test_spec.rb +24 -0
- data/spec/integration_tests/style_rule_api_spec.rb +55 -17
- data/spec/integration_tests/style_rule_error_paths_spec.rb +45 -0
- data/spec/integration_tests/translate_api_spec.rb +98 -0
- data/spec/integration_tests/translate_error_paths_spec.rb +48 -0
- data/spec/integration_tests/translation_memory_api_spec.rb +54 -0
- data/spec/integration_tests/translation_memory_error_paths_spec.rb +19 -0
- data/spec/integration_tests/usage_api_spec.rb +29 -0
- data/spec/integration_tests/usage_error_paths_spec.rb +18 -0
- data/spec/requests/glossary/create_spec.rb +0 -21
- data/spec/requests/glossary/destroy_spec.rb +0 -39
- data/spec/requests/glossary/entries_spec.rb +0 -35
- data/spec/requests/glossary/find_spec.rb +0 -40
- data/spec/requests/glossary/language_pairs_spec.rb +0 -13
- data/spec/requests/glossary/list_spec.rb +0 -27
- data/spec/requests/languages_spec.rb +0 -41
- data/spec/requests/rephrase_spec.rb +13 -139
- data/spec/requests/style_rule/create_custom_instruction_spec.rb +30 -0
- data/spec/requests/style_rule/create_spec.rb +29 -0
- data/spec/requests/style_rule/destroy_custom_instruction_spec.rb +28 -0
- data/spec/requests/style_rule/destroy_spec.rb +27 -0
- data/spec/requests/style_rule/find_custom_instruction_spec.rb +29 -0
- data/spec/requests/style_rule/find_spec.rb +28 -0
- data/spec/requests/style_rule/list_spec.rb +27 -0
- data/spec/requests/style_rule/update_configured_rules_spec.rb +31 -0
- data/spec/requests/style_rule/update_custom_instruction_spec.rb +32 -0
- data/spec/requests/style_rule/update_spec.rb +29 -0
- data/spec/requests/translate_spec.rb +8 -218
- data/spec/requests/translation_memory/list_spec.rb +27 -0
- data/spec/requests/usage_spec.rb +0 -16
- data/spec/resources/custom_instruction_spec.rb +32 -0
- data/spec/resources/style_rule_spec.rb +68 -0
- data/spec/resources/translation_memory_spec.rb +35 -0
- data/spec/spec_helper.rb +15 -45
- data/spec/support/live_mock_server.rb +12 -0
- data/spec/support/managed_glossary.rb +17 -0
- data/spec/support/managed_style_rule.rb +17 -0
- data/spec/support/managed_translation_memory.rb +7 -0
- metadata +48 -19
- data/spec/fixtures/vcr_cassettes/deepl_document.yml +0 -95
- data/spec/fixtures/vcr_cassettes/deepl_document_download.yml +0 -1214
- data/spec/fixtures/vcr_cassettes/deepl_glossaries.yml +0 -1163
- data/spec/fixtures/vcr_cassettes/deepl_languages.yml +0 -54
- data/spec/fixtures/vcr_cassettes/deepl_rephrase.yml +0 -87
- data/spec/fixtures/vcr_cassettes/deepl_translate.yml +0 -358
- data/spec/fixtures/vcr_cassettes/deepl_usage.yml +0 -129
- data/spec/fixtures/vcr_cassettes/glossaries.yml +0 -1702
- data/spec/fixtures/vcr_cassettes/languages.yml +0 -229
- data/spec/fixtures/vcr_cassettes/rephrase_texts.yml +0 -401
- data/spec/fixtures/vcr_cassettes/style_rules.yml +0 -92
- data/spec/fixtures/vcr_cassettes/translate_texts.yml +0 -10630
- data/spec/fixtures/vcr_cassettes/usage.yml +0 -171
|
@@ -266,227 +266,17 @@ describe DeepL::Requests::Translate do
|
|
|
266
266
|
expect(request.options[:custom_instructions]).to eq(['Use informal language', 'Be concise'])
|
|
267
267
|
end
|
|
268
268
|
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
|
-
|
|
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
269
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
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
|
-
expected_model_type = model_type_str.sub(/^prefer_/, '')
|
|
405
|
-
expect(res.model_type_used).to eq(expected_model_type)
|
|
406
|
-
end
|
|
407
|
-
end
|
|
408
|
-
end
|
|
409
|
-
|
|
410
|
-
context 'when performing a request with extra_body_parameters' do
|
|
411
|
-
it 'allows extra parameters to override standard parameters' do
|
|
412
|
-
extra_options = { extra_body_parameters: { target_lang: 'FR', debug: '1' } }
|
|
413
|
-
translate = described_class.new(api, text, source_lang, target_lang, extra_options)
|
|
414
|
-
res = translate.request
|
|
415
|
-
|
|
416
|
-
expect(res).to be_a(DeepL::Resources::Text)
|
|
417
|
-
expect(res.text).to eq('Texte modèle')
|
|
418
|
-
expect(res.detected_source_language).to eq('EN')
|
|
419
|
-
end
|
|
420
|
-
end
|
|
421
|
-
|
|
422
|
-
context 'when performing a request with custom_instructions' do
|
|
423
|
-
let(:text) { 'Hello world' }
|
|
424
|
-
let(:target_lang) { 'DE' }
|
|
425
|
-
|
|
426
|
-
it 'includes custom_instructions in the payload' do
|
|
427
|
-
options = { custom_instructions: ['Use formal language', 'Be concise'] }
|
|
428
|
-
translate = described_class.new(api, text, source_lang, target_lang, options)
|
|
429
|
-
|
|
430
|
-
# Verify the options are properly stored
|
|
431
|
-
expect(translate.options[:custom_instructions]).to eq(['Use formal language', 'Be concise'])
|
|
270
|
+
context 'when passing additional headers' do
|
|
271
|
+
it 'merges the headers into the request headers' do
|
|
272
|
+
request = described_class.new(api, nil, nil, nil, {},
|
|
273
|
+
{ 'X-DeepL-Reporting-Tag' => 'my-tag' })
|
|
274
|
+
expect(request.send(:headers)).to include('X-DeepL-Reporting-Tag' => 'my-tag')
|
|
432
275
|
end
|
|
433
|
-
end
|
|
434
|
-
|
|
435
|
-
context 'when performing a request with tag_handling_version' do
|
|
436
|
-
let(:text) { '<p>Hello world</p>' }
|
|
437
|
-
let(:target_lang) { 'DE' }
|
|
438
|
-
|
|
439
|
-
%w[v1 v2].each do |version|
|
|
440
|
-
it "translates correctly with tag_handling_version #{version}" do
|
|
441
|
-
options = { tag_handling: 'html', tag_handling_version: version }
|
|
442
|
-
translate = described_class.new(api, text, source_lang, target_lang, options)
|
|
443
|
-
res = translate.request
|
|
444
|
-
|
|
445
|
-
expect(res).to be_a(DeepL::Resources::Text)
|
|
446
|
-
expect(res.text).not_to be_nil
|
|
447
|
-
expect(res.text).not_to be_empty
|
|
448
|
-
end
|
|
449
|
-
end
|
|
450
|
-
end
|
|
451
|
-
|
|
452
|
-
context 'when performing a bad request' do
|
|
453
|
-
context 'when using an invalid token' do
|
|
454
|
-
let(:api) do
|
|
455
|
-
api = build_deepl_api
|
|
456
|
-
api.configuration.auth_key = 'invalid'
|
|
457
|
-
api
|
|
458
|
-
end
|
|
459
|
-
|
|
460
|
-
it 'raises an unauthorized error' do
|
|
461
|
-
expect { translate.request }.to raise_error(DeepL::Exceptions::AuthorizationFailed)
|
|
462
|
-
end
|
|
463
|
-
end
|
|
464
|
-
|
|
465
|
-
context 'when using an invalid text' do
|
|
466
|
-
let(:text) { nil }
|
|
467
|
-
|
|
468
|
-
it 'raises a bad request error' do
|
|
469
|
-
message = "Invalid request: Expected 'text' parameter to be an array of strings"
|
|
470
|
-
expect { translate.request }.to raise_error(DeepL::Exceptions::BadRequest, message)
|
|
471
|
-
end
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
context 'when using an invalid target language' do
|
|
475
|
-
let(:target_lang) { nil }
|
|
476
|
-
|
|
477
|
-
it 'raises a bad request error' do
|
|
478
|
-
message = "Value for 'target_lang' not supported."
|
|
479
|
-
expect { translate.request }.to raise_error(DeepL::Exceptions::BadRequest, message)
|
|
480
|
-
end
|
|
481
|
-
end
|
|
482
|
-
end
|
|
483
|
-
|
|
484
|
-
context 'when performing a request with too many texts' do
|
|
485
|
-
let(:text) { Array.new(10_000) { |i| "This is the sentence number #{i}" } }
|
|
486
276
|
|
|
487
|
-
it '
|
|
488
|
-
|
|
489
|
-
|
|
277
|
+
it 'defaults to no additional headers' do
|
|
278
|
+
request = described_class.new(api, nil, nil, nil)
|
|
279
|
+
expect(request.send(:headers).keys).to contain_exactly('Authorization', 'User-Agent')
|
|
490
280
|
end
|
|
491
281
|
end
|
|
492
282
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
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::List do
|
|
9
|
+
subject(:translation_memory_list) { described_class.new(api, 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(:options) { {} }
|
|
19
|
+
|
|
20
|
+
describe '#initialize' do
|
|
21
|
+
context 'when building a request' do
|
|
22
|
+
it 'creates a request object' do
|
|
23
|
+
expect(translation_memory_list).to be_a(described_class)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/spec/requests/usage_spec.rb
CHANGED
|
@@ -24,20 +24,4 @@ describe DeepL::Requests::Usage do
|
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
|
-
|
|
28
|
-
describe '#request' do
|
|
29
|
-
around do |example|
|
|
30
|
-
VCR.use_cassette('usage') { example.call }
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
context 'when performing a valid request' do
|
|
34
|
-
it 'returns an usage object' do
|
|
35
|
-
usage = usage_req.request
|
|
36
|
-
|
|
37
|
-
expect(usage).to be_a(DeepL::Resources::Usage)
|
|
38
|
-
expect(usage.character_count).to be_a(Numeric)
|
|
39
|
-
expect(usage.character_limit).to be_a(Numeric)
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
27
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
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::Resources::CustomInstruction do
|
|
9
|
+
subject(:custom_instruction) do
|
|
10
|
+
described_class.new({
|
|
11
|
+
'id' => 'ci-1',
|
|
12
|
+
'label' => 'Formal',
|
|
13
|
+
'prompt' => 'Always use formal language',
|
|
14
|
+
'source_language' => 'en'
|
|
15
|
+
})
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe '#initialize' do
|
|
19
|
+
context 'when building a basic object' do
|
|
20
|
+
it 'creates a resource' do
|
|
21
|
+
expect(custom_instruction).to be_a(described_class)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'assigns the attributes' do
|
|
25
|
+
expect(custom_instruction.id).to eq('ci-1')
|
|
26
|
+
expect(custom_instruction.label).to eq('Formal')
|
|
27
|
+
expect(custom_instruction.prompt).to eq('Always use formal language')
|
|
28
|
+
expect(custom_instruction.source_language).to eq('en')
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
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::Resources::StyleRule do
|
|
9
|
+
subject(:style_rule) do
|
|
10
|
+
described_class.new({
|
|
11
|
+
'style_id' => 'dca2e053-8ae5-45e6-a0d2-881156e7f4e4',
|
|
12
|
+
'name' => 'Default Style Rule',
|
|
13
|
+
'creation_time' => '2025-01-01T00:00:00Z',
|
|
14
|
+
'updated_time' => '2025-01-02T00:00:00Z',
|
|
15
|
+
'language' => 'en',
|
|
16
|
+
'version' => 1
|
|
17
|
+
}, nil, nil)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe '#initialize' do
|
|
21
|
+
context 'when building a basic object' do
|
|
22
|
+
it 'creates a resource' do
|
|
23
|
+
expect(style_rule).to be_a(described_class)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'assigns the attributes' do
|
|
27
|
+
expect(style_rule.style_id).to eq('dca2e053-8ae5-45e6-a0d2-881156e7f4e4')
|
|
28
|
+
expect(style_rule.name).to eq('Default Style Rule')
|
|
29
|
+
expect(style_rule.language).to eq('en')
|
|
30
|
+
expect(style_rule.version).to eq(1)
|
|
31
|
+
expect(style_rule.creation_time).to eq(Time.parse('2025-01-01T00:00:00Z'))
|
|
32
|
+
expect(style_rule.updated_time).to eq(Time.parse('2025-01-02T00:00:00Z'))
|
|
33
|
+
expect(style_rule.configured_rules).to be_nil
|
|
34
|
+
expect(style_rule.custom_instructions).to be_nil
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context 'when building an object with configured rules and custom instructions' do
|
|
39
|
+
subject(:style_rule) do
|
|
40
|
+
described_class.new({
|
|
41
|
+
'style_id' => 'dca2e053-8ae5-45e6-a0d2-881156e7f4e4',
|
|
42
|
+
'name' => 'Detailed Style Rule',
|
|
43
|
+
'language' => 'en',
|
|
44
|
+
'version' => 1,
|
|
45
|
+
'configured_rules' => {
|
|
46
|
+
'dates_and_times' => { 'calendar_era' => 'use_bc_and_ad' }
|
|
47
|
+
},
|
|
48
|
+
'custom_instructions' => [
|
|
49
|
+
{ 'id' => 'ci-1', 'label' => 'Test', 'prompt' => 'Be formal' }
|
|
50
|
+
]
|
|
51
|
+
}, nil, nil)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'maps configured_rules into a ConfiguredRules resource' do
|
|
55
|
+
expect(style_rule.configured_rules).to be_a(DeepL::Resources::ConfiguredRules)
|
|
56
|
+
expect(style_rule.configured_rules.dates_and_times)
|
|
57
|
+
.to eq({ 'calendar_era' => 'use_bc_and_ad' })
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'maps custom_instructions into an array of CustomInstruction resources' do
|
|
61
|
+
expect(style_rule.custom_instructions).to all(be_a(DeepL::Resources::CustomInstruction))
|
|
62
|
+
expect(style_rule.custom_instructions.first.id).to eq('ci-1')
|
|
63
|
+
expect(style_rule.custom_instructions.first.label).to eq('Test')
|
|
64
|
+
expect(style_rule.custom_instructions.first.prompt).to eq('Be formal')
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
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::Resources::TranslationMemory do
|
|
9
|
+
subject(:translation_memory) do
|
|
10
|
+
described_class.new({
|
|
11
|
+
'translation_memory_id' => 'a74d88fb-ed2a-4943-a664-a4512398b994',
|
|
12
|
+
'name' => 'Legal',
|
|
13
|
+
'source_language' => 'en',
|
|
14
|
+
'target_languages' => %w[es de],
|
|
15
|
+
'segment_count' => 3542
|
|
16
|
+
}, nil, nil)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe '#initialize' do
|
|
20
|
+
context 'when building a basic object' do
|
|
21
|
+
it 'creates a resource' do
|
|
22
|
+
expect(translation_memory).to be_a(described_class)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'assigns the attributes' do
|
|
26
|
+
expect(translation_memory.translation_memory_id)
|
|
27
|
+
.to eq('a74d88fb-ed2a-4943-a664-a4512398b994')
|
|
28
|
+
expect(translation_memory.name).to eq('Legal')
|
|
29
|
+
expect(translation_memory.source_language).to eq('en')
|
|
30
|
+
expect(translation_memory.target_languages).to eq(%w[es de])
|
|
31
|
+
expect(translation_memory.segment_count).to eq(3542)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -14,59 +14,29 @@ SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter
|
|
|
14
14
|
require_relative '../lib/deepl'
|
|
15
15
|
require_relative 'integration_tests/integration_test_utils'
|
|
16
16
|
|
|
17
|
+
# Auto-load test helpers under spec/support
|
|
18
|
+
Dir[File.expand_path('support/**/*.rb', __dir__)].sort.each { |f| require f }
|
|
19
|
+
|
|
17
20
|
# Lib config
|
|
18
21
|
ENV['DEEPL_AUTH_KEY'] ||= 'TEST-TOKEN'
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
RSpec.configure do |config|
|
|
24
|
+
config.include ManagedGlossary
|
|
25
|
+
config.include ManagedStyleRule
|
|
26
|
+
config.include ManagedTranslationMemory
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
uri1 = request1.uri
|
|
28
|
-
uri2 = request2.uri
|
|
29
|
-
uri1_match = uri1.match(deepl_api_regexp)
|
|
30
|
-
uri2_match = uri2.match(deepl_api_regexp)
|
|
31
|
-
if uri1_match && uri2_match
|
|
32
|
-
uri1_without_deepl_domain = uri1.gsub(uri1_match[0], '')
|
|
33
|
-
uri2_without_deepl_domain = uri2.gsub(uri2_match[0], '')
|
|
34
|
-
uri1_without_deepl_domain == uri2_without_deepl_domain
|
|
35
|
-
else
|
|
36
|
-
uri1 == uri2
|
|
28
|
+
config.before(:each, :mock_server_only) do
|
|
29
|
+
skip 'Only runs on mock server' unless ENV.key?('DEEPL_MOCK_SERVER_PORT')
|
|
37
30
|
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
headers_ignoring_user_agent = lambda do |request1, request2|
|
|
41
|
-
user_agent_key = 'User-Agent'
|
|
42
|
-
# Pass by reference, so we need to use a copy of the headers
|
|
43
|
-
headers1 = request1.headers.dup
|
|
44
|
-
headers2 = request2.headers.dup
|
|
45
|
-
headers1_has_user_agent = headers1.key?(user_agent_key)
|
|
46
|
-
headers2_has_user_agent = headers2.key?(user_agent_key)
|
|
47
|
-
return false if headers1_has_user_agent != headers2_has_user_agent
|
|
48
31
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
32
|
+
config.before(:each, :real_server_only) do
|
|
33
|
+
skip 'Only runs on real server' if ENV.key?('DEEPL_MOCK_SERVER_PORT')
|
|
34
|
+
end
|
|
52
35
|
end
|
|
53
36
|
|
|
54
|
-
#
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
config.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
|
|
58
|
-
config.hook_into :webmock
|
|
59
|
-
config.filter_sensitive_data('VALID_TOKEN') { ENV.fetch('DEEPL_AUTH_KEY', nil) }
|
|
60
|
-
|
|
61
|
-
# to record new or missing VCR cassettes, call rspec like this:
|
|
62
|
-
# $ VCR_RECORD_MODE=new_episodes bundle exec rspec
|
|
63
|
-
|
|
64
|
-
record_mode = ENV['VCR_RECORD_MODE'] ? ENV['VCR_RECORD_MODE'].to_sym : :none
|
|
65
|
-
config.default_cassette_options = {
|
|
66
|
-
record: record_mode,
|
|
67
|
-
match_requests_on: [:method, uri_ignoring_deepl_api_subdomain, :body,
|
|
68
|
-
headers_ignoring_user_agent]
|
|
69
|
-
}
|
|
37
|
+
# General helpers
|
|
38
|
+
def build_deepl_api
|
|
39
|
+
DeepL::API.new(DeepL::Configuration.new)
|
|
70
40
|
end
|
|
71
41
|
|
|
72
42
|
# Test helpers
|
|
@@ -0,0 +1,12 @@
|
|
|
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 file.
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
|
|
6
|
+
# Shared setup for integration specs that hit the live mock server: expose an
|
|
7
|
+
# API the server rejects as unauthorized without mutating global DeepL state.
|
|
8
|
+
RSpec.shared_context 'with a live mock server' do
|
|
9
|
+
let(:unauthorized_api) do
|
|
10
|
+
DeepL::API.new(DeepL::Configuration.new(auth_key: 'invalid'))
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Copyright 2025 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 file.
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
|
|
6
|
+
module ManagedGlossary
|
|
7
|
+
def with_managed_glossary(name:, source_lang:, target_lang:, entries:, options: {})
|
|
8
|
+
glossary = DeepL.glossaries.create(name, source_lang, target_lang, entries, options)
|
|
9
|
+
yield glossary
|
|
10
|
+
ensure
|
|
11
|
+
begin
|
|
12
|
+
DeepL.glossaries.destroy(glossary.id) if glossary
|
|
13
|
+
rescue StandardError
|
|
14
|
+
nil
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Copyright 2025 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 file.
|
|
4
|
+
# frozen_string_literal: true
|
|
5
|
+
|
|
6
|
+
module ManagedStyleRule
|
|
7
|
+
def with_managed_style_rule(name:, language:, options: {})
|
|
8
|
+
style_rule = DeepL.style_rules.create(name, language, options)
|
|
9
|
+
yield style_rule
|
|
10
|
+
ensure
|
|
11
|
+
begin
|
|
12
|
+
DeepL.style_rules.destroy(style_rule.style_id) if style_rule
|
|
13
|
+
rescue StandardError
|
|
14
|
+
nil
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|