deepl_diff 2.0.0 → 2.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca22132db1cfc83ab8e56a9a17bd635ca3648e9d7fde32a2df13dce21991f946
4
- data.tar.gz: '018f598439a77db2e229d2c95f7b8ff0c14c0f17ba7130e19cbdf3f897b716a6'
3
+ metadata.gz: 83f226ab695b30cfc248762a7760bceb6bf9166d9a6f7a9bee620235309c33d2
4
+ data.tar.gz: cb0b0e175dce7ae19ba282fb86a8cc15fac1266fc373ee1b5c56dd0cac707fba
5
5
  SHA512:
6
- metadata.gz: 0144f0c5d615c25036d0f2f2b41238667e6ab045442714e45235c8192f49c70fdeeb92753c6e7ec5f0e1189de3064191bdbb2014108a5715942ee1455f6ae76f
7
- data.tar.gz: 71a0a99b3f5869bec1f2383f8d212c6ead9bd63f9e5eb5a9f8ad98ed2aa93f0701d5775b9de3764c21aad7ac96f11afe2a506e674056f9a97a80ed5d357c65b6
6
+ metadata.gz: 0bd5a40578adf7e42ff6bae724f6983bae992af787bf4e0ade831353259683e097fc1a1f34cb25c3ac7a563faf6a75d6cf9e8983d7d2e973dbf9ec97a5897b30
7
+ data.tar.gz: b7abc9af4e0ee1f33c5dd3dafc764069776c7668a2c361bd74064c6068f4be3e98e399abedcb216d57dcb8e08e8010e89db487d3bf79f849962e6f5c08fe057a
data/deepl_diff.gemspec CHANGED
@@ -33,6 +33,15 @@ between revisions of long texts.
33
33
  "public gem pushes."
34
34
  end
35
35
 
36
+ spec.post_install_message = <<~MESSAGE
37
+ deepl_diff is being replaced by translation_diff, which supports
38
+ translation providers other than DeepL.
39
+
40
+ This version of deepl_diff keeps working and will not change again.
41
+
42
+ https://rubygems.org/gems/translation_diff
43
+ MESSAGE
44
+
36
45
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
37
46
  f.match(%r{^(test|spec|features)/})
38
47
  end
@@ -3,7 +3,7 @@
3
3
  class DeepLDiff::Chunker
4
4
  class Error < StandardError; end
5
5
 
6
- Chunk = Struct.new(:texts, :bytesize)
6
+ Chunk = Struct.new(:texts, :escaped_size)
7
7
 
8
8
  MAX_CHUNK_SIZE = 1700
9
9
  COUNT_LIMIT = 300
@@ -39,20 +39,25 @@ class DeepLDiff::Chunker
39
39
 
40
40
  def next_chunk?(tail, value)
41
41
  tail.nil? ||
42
- (size(value) + tail.bytesize > limit) ||
43
- tail.texts.size > count_limit
42
+ (escaped_size(value) + tail.escaped_size > limit) ||
43
+ tail.texts.size >= count_limit
44
44
  end
45
45
 
46
- def size(text)
46
+ # What the limit is about is the size of the request that goes over the
47
+ # wire, so every measurement here is of the escaped form. Mixing it with
48
+ # String#size lets a chunk of non-ASCII text run several times over.
49
+ def escaped_size(text)
47
50
  CGI.escape(text).size
48
51
  end
49
52
 
50
53
  def update_chunk(chunk, value)
51
54
  chunk.texts << value
52
- chunk.bytesize += value.size
55
+ chunk.escaped_size += escaped_size(value)
53
56
  end
54
57
 
55
58
  def validate_value_size(value)
56
- raise Error, "Too long part #{value.size} > #{limit}" if value.size > limit
59
+ size = escaped_size(value)
60
+
61
+ raise Error, "Too long part #{size} > #{limit}" if size > limit
57
62
  end
58
63
  end
@@ -3,18 +3,22 @@
3
3
  class DeepLDiff::Request
4
4
  extend Forwardable
5
5
 
6
+ class Error < StandardError; end
7
+
6
8
  def_delegators :DeepLDiff, :api, :cache_store, :rate_limiter
7
9
  def_delegators :"DeepLDiff::Linearizer", :linearize, :restore
8
10
 
9
11
  def initialize(values, options)
10
12
  @values = values
11
- @options = options
13
+ # #from and #to consume their keys so the rest can go to the API as-is.
14
+ # Copy first: the caller's hash is theirs, and it is often frozen.
15
+ @options = options.dup
12
16
  end
13
17
 
14
18
  def call
15
19
  validate_globals
16
20
 
17
- return values if from == to || values.empty?
21
+ return values if same_language? || nothing_to_translate?
18
22
 
19
23
  translation
20
24
  end
@@ -31,6 +35,19 @@ class DeepLDiff::Request
31
35
  @to ||= options.delete(:to) { nil }
32
36
  end
33
37
 
38
+ # A detected language arrives as a String while :to is usually a Symbol, so
39
+ # the two have to be compared on equal footing or the short circuit never
40
+ # fires and the text gets translated into its own language.
41
+ def same_language?
42
+ !to.nil? && from.to_s.casecmp?(to.to_s)
43
+ end
44
+
45
+ # Covers values holding no translatable text at all: "", nil, an empty
46
+ # collection, or a scalar the tokenizer has nothing to say about.
47
+ def nothing_to_translate?
48
+ text_tokens_texts.all?(&:empty?)
49
+ end
50
+
34
51
  def detect_language
35
52
  api.translate(text_tokens_texts.join(" ")[0..100], nil, to)
36
53
  .detected_source_language.downcase
@@ -126,7 +143,12 @@ class DeepLDiff::Request
126
143
  # Restores texts from tokens
127
144
  # [..., "<b>Horoshiy</b> Malchik", ...]
128
145
  def texts_translated
129
- @texts_translated ||= tokens_translated.map do |group|
146
+ @texts_translated ||= tokens_translated.map.with_index do |group, index|
147
+ source = texts[index]
148
+ # Only strings are rebuilt from tokens. Anything else has no tokens to
149
+ # rebuild from; nil keeps collapsing to "" the way it always has.
150
+ next source unless source.nil? || source.is_a?(String)
151
+
130
152
  group.map { |value, type| type == :text ? value : fix_ascii(value) }.join
131
153
  end
132
154
  end
@@ -138,7 +160,13 @@ class DeepLDiff::Request
138
160
 
139
161
  def call_api(values)
140
162
  check_rate_limit(values)
141
- [api.translate(values, from, to, options)].flatten.map(&:text)
163
+ translations = [api.translate(values, from, to, options)].flatten.map(&:text)
164
+ return translations if translations.size == values.size
165
+
166
+ # Letting a short response through means shifting nils into the results,
167
+ # which surfaces much later as a NoMethodError far from the cause.
168
+ raise Error,
169
+ "API returned #{translations.size} translations for #{values.size} values"
142
170
  end
143
171
 
144
172
  def cache
@@ -149,7 +149,8 @@ class DeepLDiff::Tokenizer < Ox::Sax
149
149
 
150
150
  class << self
151
151
  def tokenize(value)
152
- return [] if value.nil?
152
+ # Anything that is not a string has no markup and no sentences in it.
153
+ return [] unless value.is_a?(String)
153
154
 
154
155
  tokenizer = new(value).tap do |h|
155
156
  Ox.sax_parse(h, StringIO.new(value), HTML_OPTIONS)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DeepLDiff
4
- VERSION = "2.0.0"
4
+ VERSION = "2.2.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deepl_diff
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Islam Gagiev
@@ -127,6 +127,13 @@ metadata:
127
127
  homepage_uri: https://github.com/Halvanhelv/deepl_diff
128
128
  source_code_uri: https://github.com/Halvanhelv/deepl_diff
129
129
  rubygems_mfa_required: 'true'
130
+ post_install_message: |
131
+ deepl_diff is being replaced by translation_diff, which supports
132
+ translation providers other than DeepL.
133
+
134
+ This version of deepl_diff keeps working and will not change again.
135
+
136
+ https://rubygems.org/gems/translation_diff
130
137
  rdoc_options: []
131
138
  require_paths:
132
139
  - lib