tr4n5l4te 0.1.17 → 1.1.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: c6b69aeaea5cf69583a1638d33142a030d45a14f0edfc1ad381af1a3ef6c683e
4
- data.tar.gz: 95744b495e3969b2964001ab5a7c3ced68f2fc0efcb339864de25f4b2c95c0b3
3
+ metadata.gz: de91f2f7be53edf09dac7ac551203443908e35313912974a829214b9171bf470
4
+ data.tar.gz: 6406468eb4da61b7fcb1448a24842b0a8125cb461680f673cbf7a82e5c0024d6
5
5
  SHA512:
6
- metadata.gz: aa2e68b9b86cbe35c65d070264dfc16e5db1159e8c9357b567cb1a343e76ea9bcc3e457a480e58e172c6f13fa23a791f46de39324d7eff78b967aaa3b932d0a3
7
- data.tar.gz: 716e133bc935b33f7c79270b7163a8746bb4488835e1f892ad66654fe899cced80b04fb51d3f8bdda7225dea3f5dd53236390772774eaf551b4410d4846f7e67
6
+ metadata.gz: bd08cbe5857f621d10569ce363e34364c88497b5688025b66790e770602af8e1622cc72b1ee64685544b17b2993cea2643d89e6bb838000611379f971f4d39fc
7
+ data.tar.gz: '0381e45fd11649394d0002c8e648ff1cb2be416e47dc5fdb84425f6f4a3a6fe69dff574b967e13bbf0101e0470e39d050bf15e5dbd4b26bd7bd4beba0e6f2e1f'
data/.gitignore CHANGED
@@ -11,3 +11,6 @@ test.html
11
11
  /stubs
12
12
  /node_modules/
13
13
  yarn.lock
14
+ .claude/
15
+ CLAUDE.md
16
+ spec/fixtures/es.yml
data/.rubocop.yml CHANGED
@@ -1,8 +1,3 @@
1
- require:
2
- - rubocop-factory_bot
3
- - rubocop-rspec
4
- - rubocop-rails
5
-
6
1
  AllCops:
7
2
  TargetRubyVersion: 3.2
8
3
 
@@ -161,6 +156,10 @@ Metrics/MethodLength:
161
156
  Metrics/ClassLength:
162
157
  Max: 120
163
158
 
159
+ Metrics/ModuleLength:
160
+ Exclude:
161
+ - spec/**/*
162
+
164
163
  Metrics/AbcSize:
165
164
  Max: 20
166
165
 
@@ -172,37 +171,6 @@ Metrics/BlockLength:
172
171
  - config/routes.rb
173
172
  - config/environments/*.rb
174
173
 
175
- ########################################
176
- # Rspec Cops
177
-
178
- RSpec/MultipleExpectations:
179
- Enabled: false
180
-
181
- RSpec/IndexedLet:
182
- Enabled: false
183
-
184
- RSpec/MultipleMemoizedHelpers:
185
- Enabled: false
186
-
187
- RSpec/ExampleLength:
188
- Enabled: false
189
-
190
- RSpec/ContextWording:
191
- Enabled: false
192
-
193
- RSpec/NestedGroups:
194
- Enabled: false
195
-
196
- RSpec/AnyInstance:
197
- Enabled: false
198
-
199
-
200
- ########################################
201
- # Rails Cops
202
-
203
- Rails/I18nLocaleTexts:
204
- Enabled: false
205
-
206
174
  ########################################
207
175
  # Bundler Cops
208
176
 
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.2
data/CHANGELOG CHANGED
@@ -1,3 +1,23 @@
1
+ *1.1.0* (February 17, 2026)
2
+
3
+ * Add proxy support for Net::HTTP requests (host:port or user:pass@host:port)
4
+ * Add -p/--proxy CLI option
5
+ * Add configurable proxy via Tr4n5l4te.configure
6
+ * Update README with proxy documentation
7
+
8
+ *1.0.0* (February 14, 2026)
9
+
10
+ * Replace PhantomJS/Poltergeist with direct HTTP translation via Google's undocumented translate endpoint
11
+ * Delete Agent class and all cookie/browser infrastructure
12
+ * Remove capybara and poltergeist gem dependencies (net/http, json, uri are stdlib)
13
+ * Rewrite Translator to use Net::HTTP POST to translate.googleapis.com
14
+ * Add error handling that returns original text on translation failure
15
+ * Interpolation variable preservation (%{var}) still works as before
16
+ * Move development dependencies from gemspec to Gemfile
17
+ * Add required_ruby_version >= 3.2 to gemspec
18
+ * Remove rubocop-rails and rubocop-factory_bot from linter config
19
+ * Fix all rubocop offenses
20
+
1
21
  *0.1.17* (February 06, 2024)
2
22
 
3
23
  * Upgrade Nokogiri
data/Gemfile CHANGED
@@ -4,3 +4,10 @@ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in tr4n5l4te.gemspec
6
6
  gemspec
7
+
8
+ gem 'bundler', '~> 2.1'
9
+ gem 'pry-nav'
10
+ gem 'rake', '~> 13.0'
11
+ gem 'rspec', '~> 3.0'
12
+ gem 'rubocop'
13
+ gem 'simplecov', '~> 0.11'
data/Gemfile.lock CHANGED
@@ -1,27 +1,15 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tr4n5l4te (0.1.17)
5
- capybara (~> 2.6)
4
+ tr4n5l4te (1.1.0)
6
5
  colored (~> 1)
7
6
  midwire_common (~> 0.1)
8
7
  optimist (~> 3.0)
9
- poltergeist (~> 1.9)
10
8
 
11
9
  GEM
12
10
  remote: https://rubygems.org/
13
11
  specs:
14
- addressable (2.8.6)
15
- public_suffix (>= 2.0.2, < 6.0)
16
12
  ast (2.4.2)
17
- capybara (2.18.0)
18
- addressable
19
- mini_mime (>= 0.1.3)
20
- nokogiri (>= 1.3.3)
21
- rack (>= 1.0.0)
22
- rack-test (>= 0.5.4)
23
- xpath (>= 2.0, < 4.0)
24
- cliver (0.3.2)
25
13
  coderay (1.1.3)
26
14
  colored (1.2)
27
15
  diff-lcs (1.5.1)
@@ -31,30 +19,17 @@ GEM
31
19
  method_source (1.0.0)
32
20
  midwire_common (0.3.0)
33
21
  thor (~> 0.19)
34
- mini_mime (1.1.5)
35
- mini_portile2 (2.8.5)
36
- nokogiri (1.16.2)
37
- mini_portile2 (~> 2.8.2)
38
- racc (~> 1.4)
39
22
  optimist (3.1.0)
40
23
  parallel (1.24.0)
41
24
  parser (3.3.0.5)
42
25
  ast (~> 2.4.1)
43
26
  racc
44
- poltergeist (1.18.1)
45
- capybara (>= 2.1, < 4)
46
- cliver (~> 0.3.1)
47
- websocket-driver (>= 0.2.0)
48
27
  pry (0.14.2)
49
28
  coderay (~> 1.1)
50
29
  method_source (~> 1.0)
51
30
  pry-nav (1.0.0)
52
31
  pry (>= 0.9.10, < 0.15)
53
- public_suffix (5.0.4)
54
32
  racc (1.7.3)
55
- rack (3.0.9)
56
- rack-test (2.1.0)
57
- rack (>= 1.3)
58
33
  rainbow (3.1.1)
59
34
  rake (13.1.0)
60
35
  regexp_parser (2.9.0)
@@ -94,11 +69,6 @@ GEM
94
69
  simplecov_json_formatter (0.1.4)
95
70
  thor (0.20.3)
96
71
  unicode-display_width (2.5.0)
97
- websocket-driver (0.7.6)
98
- websocket-extensions (>= 0.1.0)
99
- websocket-extensions (0.1.5)
100
- xpath (3.2.0)
101
- nokogiri (~> 1.8)
102
72
 
103
73
  PLATFORMS
104
74
  ruby
data/README.md CHANGED
@@ -1,15 +1,13 @@
1
1
  # Tr4n5l4te
2
2
 
3
- **Version: 0.1.17**
3
+ **Version: 1.1.0**
4
4
 
5
5
  Use Google Translate without an API key.
6
6
 
7
- Like me, maybe you've found that Google makes it a pain to work with their API. Tr4n5l4te gets around all that.
7
+ Like me, maybe you've found that Google makes it a pain to work with their API. Tr4n5l4te gets around all that by using Google's free translation endpoint directly via HTTP — no browser, no API key, no headless dependencies.
8
8
 
9
9
  ## Installation
10
10
 
11
- First, install [PhantomJS](http://phantomjs.org/).
12
-
13
11
  Add this line to your application's Gemfile:
14
12
 
15
13
  ```ruby
@@ -24,6 +22,8 @@ Or install it yourself as:
24
22
 
25
23
  $ gem install tr4n5l4te
26
24
 
25
+ Requires Ruby >= 3.2.
26
+
27
27
  ## Usage
28
28
 
29
29
  In your code:
@@ -41,6 +41,8 @@ end
41
41
  # => cómo estás
42
42
  ```
43
43
 
44
+ Ruby string interpolation variables (`%{var}`) are preserved through translation.
45
+
44
46
  ### Command Line
45
47
 
46
48
  ➤ ./exe/translate -h
@@ -49,7 +51,8 @@ end
49
51
  -l, --lang=<s> Destination language
50
52
  -i, --list List known languages
51
53
  -s, --sleep-time=<i> Sleep time (default: 2)
52
- -t, --timeout=<i> Poltergeist timeout option (default: 30)
54
+ -t, --timeout=<i> HTTP request timeout (default: 30)
55
+ -p, --proxy=<s> Proxy - host:port or user:pass@host:port
53
56
  -v, --verbose Be verbose with output
54
57
  -h, --help Show this message
55
58
 
@@ -63,10 +66,39 @@ The translator will sleep for 2 seconds, by default, between each string transla
63
66
 
64
67
  Warning: If you pass in '0' and translate a large file, it is very likely that Google will ban your IP address.
65
68
 
69
+ ### Proxy Support
70
+
71
+ Route requests through an HTTP proxy to avoid IP bans or to use from behind a firewall:
72
+
73
+ $ ./exe/translate -y config/locales/en.yml -l French -p proxy.example.com:8080
74
+
75
+ With authentication:
76
+
77
+ $ ./exe/translate -y config/locales/en.yml -l French -p user:pass@proxy.example.com:8080
78
+
79
+ You can also configure a proxy programmatically:
80
+
81
+ ```ruby
82
+ Tr4n5l4te.configure do |config|
83
+ config.proxy = { addr: 'proxy.example.com', port: 8080 }
84
+ # or with authentication:
85
+ config.proxy = { addr: 'proxy.example.com', port: 8080, user: 'user', pass: 'pass' }
86
+ end
87
+ ```
88
+
66
89
  To list all known languages
67
90
 
68
91
  $ ./exe/translate --list
69
92
 
93
+ ## Configuration
94
+
95
+ ```ruby
96
+ Tr4n5l4te.configure do |config|
97
+ config.timeout = 60 # HTTP request timeout in seconds (default: 30)
98
+ config.proxy = { addr: 'proxy.example.com', port: 8080 } # optional HTTP proxy
99
+ end
100
+ ```
101
+
70
102
  ## Development
71
103
 
72
104
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -2,10 +2,11 @@
2
2
 
3
3
  module Tr4n5l4te
4
4
  class Configuration
5
- attr_accessor :timeout
5
+ attr_accessor :timeout, :proxy
6
6
 
7
7
  def initialize
8
8
  @timeout = 30
9
+ @proxy = nil
9
10
  end
10
11
  end
11
12
  end
@@ -7,6 +7,7 @@ require 'midwire_common/string'
7
7
  require 'pry' unless ENV.fetch('GEM_ENV', nil).nil?
8
8
 
9
9
  module Tr4n5l4te
10
+ # rubocop:disable Metrics/ClassLength
10
11
  class Runner
11
12
  attr_accessor :logger, :options, :count
12
13
 
@@ -24,10 +25,7 @@ module Tr4n5l4te
24
25
  log_identifier(start_time)
25
26
  @count = 0
26
27
 
27
- # configure
28
- Tr4n5l4te.configure do |config|
29
- config.timeout = options[:timeout]
30
- end
28
+ apply_configuration
31
29
 
32
30
  hash = YAML.load_file(options[:yaml_file])
33
31
  translated = process(hash)
@@ -76,7 +74,7 @@ module Tr4n5l4te
76
74
  data = translated.to_yaml(line_width: -1)
77
75
  dir = File.dirname(options[:yaml_file])
78
76
  base = File.basename(options[:yaml_file]).gsub(/#{from_lang}\.yml$/, '')
79
- File.open(File.join(dir, "#{base}#{options[:lang]}.yml"), 'w') { |f| f.write(data) }
77
+ File.write(File.join(dir, "#{base}#{options[:lang]}.yml"), data)
80
78
  end
81
79
 
82
80
  # rubocop:disable Metrics/MethodLength
@@ -106,9 +104,14 @@ module Tr4n5l4te
106
104
  )
107
105
  opt(
108
106
  :timeout,
109
- 'Poltergeist timeout option - default 30',
107
+ 'HTTP request timeout - default 30',
110
108
  type: :integer, default: 30, short: 't'
111
109
  )
110
+ opt(
111
+ :proxy,
112
+ 'Proxy - host:port or user:pass@host:port',
113
+ type: :string, required: false, short: 'p'
114
+ )
112
115
  opt(
113
116
  :verbose,
114
117
  'Be verbose with output',
@@ -121,26 +124,46 @@ module Tr4n5l4te
121
124
  # rubocop:disable Metrics/AbcSize
122
125
  def validate_args
123
126
  if options[:list]
124
- puts('Valid languages:'.yellow + "\n\n")
125
- puts(Language.list.join(', ').yellow + "\n\n")
127
+ puts("#{'Valid languages:'.yellow}\n\n")
128
+ puts("#{Language.list.join(', ').yellow}\n\n")
126
129
  exit
127
130
  end
128
131
  if !options[:lang_given] || !Language.valid?(options[:lang])
129
- puts('Valid languages:'.red + "\n\n")
130
- puts(Language.list.join(', ').yellow + "\n\n")
132
+ puts("#{'Valid languages:'.red}\n\n")
133
+ puts("#{Language.list.join(', ').yellow}\n\n")
131
134
  Optimist.die(:lang, "'#{options[:lang]}' language unknown".red)
132
135
  end
133
136
  if !options[:yaml_file_given] || !File.exist?(options[:yaml_file])
134
- puts('A YAML file is required:'.red + "\n\n")
137
+ puts("#{'A YAML file is required:'.red}\n\n")
135
138
  Optimist.die(:yaml_file, "'#{options[:yaml_file]}' not found".red)
136
139
  end
137
140
  options[:lang] = Language.ensure_code(options[:lang])
138
141
  end
139
142
  # rubocop:enable Metrics/AbcSize
140
143
 
144
+ def apply_configuration
145
+ Tr4n5l4te.configure do |config|
146
+ config.timeout = options[:timeout]
147
+ config.proxy = parse_proxy(options[:proxy]) if options[:proxy]
148
+ end
149
+ end
150
+
151
+ def parse_proxy(proxy_string)
152
+ if proxy_string.include?('@')
153
+ auth, host_port = proxy_string.split('@', 2)
154
+ user, pass = auth.split(':', 2)
155
+ addr, port = host_port.split(':', 2)
156
+ { addr:, port: port.to_i, user:, pass: }
157
+ else
158
+ addr, port = proxy_string.split(':', 2)
159
+ { addr:, port: port.to_i }
160
+ end
161
+ end
162
+
141
163
  def log_identifier(start_time)
142
164
  timestr = start_time.strftime('%H:%M:%S.%3N')
143
165
  puts("Starting Tr4n5l4te v#{Tr4n5l4te::VERSION} @#{timestr}".green)
144
166
  end
145
167
  end
168
+ # rubocop:enable Metrics/ClassLength
146
169
  end
@@ -1,50 +1,75 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'open-uri'
3
+ require 'net/http'
4
+ require 'json'
5
+ require 'uri'
4
6
 
5
7
  module Tr4n5l4te
6
8
  class Translator
7
- START_PAGE = 'https://translate.google.com'
9
+ API_URL = 'https://translate.googleapis.com/translate_a/single'
8
10
 
9
- attr_reader :sleep_time, :agent
11
+ attr_reader :sleep_time
10
12
 
11
13
  def initialize(args = {})
12
14
  @sleep_time = args.fetch(:sleep_time, 2)
13
- @agent = Agent.new
14
15
  end
15
16
 
16
17
  def translate(text, from_lang, to_lang)
17
- encoded_text = validate_and_encode(text)
18
- return '' if encoded_text == ''
18
+ preprocessed = validate_and_encode(text)
19
+ return '' if preprocessed == ''
20
+
21
+ response = http_translate(preprocessed, from_lang, to_lang)
22
+ translated = extract_translation(response)
23
+ postprocess(translated)
24
+ rescue Net::HTTPError, JSON::ParserError, SocketError, Errno::ECONNREFUSED, Timeout::Error => e
25
+ puts("WARNING: Translation failed for '#{text}': #{e.message}")
26
+ text
27
+ end
28
+
29
+ private
19
30
 
20
- smart_visit(translator_url(encoded_text, from_lang, to_lang))
21
- result_box = browser.find('.JLqJ4b.ChMk0b > span:first-child')
22
- postprocess(result_box.text)
31
+ def http_translate(text, from_lang, to_lang)
32
+ uri = URI(API_URL)
33
+ params = { client: 'gtx', dt: 't', sl: from_lang.to_s, tl: to_lang.to_s, q: text }
23
34
 
24
- rescue Capybara::Ambiguous
25
- all_translations = browser.find_all('.JLqJ4b.ChMk0b > span:first-child')
26
- multiples = all_translations.collect(&:text)
27
- puts("WARNING: '#{text}' has multiple translations: [#{multiples.join(', ')}]")
28
- text
35
+ request = Net::HTTP::Post.new(uri.path)
36
+ request.set_form_data(params)
37
+
38
+ response = build_http(uri).request(request)
39
+ sleep_default
40
+
41
+ fail Net::HTTPError.new("HTTP #{response.code}", response) unless response.is_a?(Net::HTTPSuccess)
42
+
43
+ response.body
44
+ end
45
+
46
+ def build_http(uri)
47
+ config = Tr4n5l4te.configuration
48
+ http = create_http_client(uri, config.proxy)
49
+ http.use_ssl = true
50
+ http.open_timeout = config.timeout
51
+ http.read_timeout = config.timeout
52
+ http
53
+ end
29
54
 
30
- rescue Capybara::ElementNotFound
31
- all_translations = browser.find_all('.J0lOec > span:first-child')
32
- multiples = all_translations.collect(&:text)
33
- if multiples.any?
34
- puts("WARNING: '#{text}' has gender translations: [#{multiples.join(', ')}]")
35
- postprocess(multiples.last) # take the male form
55
+ def create_http_client(uri, proxy)
56
+ if proxy
57
+ Net::HTTP.new(uri.host, uri.port, proxy[:addr], proxy[:port], proxy[:user], proxy[:pass])
36
58
  else
37
- puts("WARNING: Could not find a translation for '#{text}'")
59
+ Net::HTTP.new(uri.host, uri.port)
38
60
  end
39
61
  end
40
62
 
41
- private
63
+ def extract_translation(body)
64
+ parsed = JSON.parse(body)
65
+ parsed[0].map { |segment| segment[0] }.join
66
+ end
42
67
 
43
68
  def preprocess(text)
44
- @interpolations = text.scan(/(%{.*})/).flatten
69
+ @interpolations = text.scan(/(%{.*?})/).flatten
45
70
  @interpolations.each_with_index do |var, ndx|
46
71
  stub = "VAR#{ndx}"
47
- text.gsub!(%r{#{var}}, stub)
72
+ text = text.gsub(var, stub)
48
73
  end
49
74
  text
50
75
  end
@@ -52,7 +77,7 @@ module Tr4n5l4te
52
77
  def postprocess(text)
53
78
  @interpolations.each_with_index do |interp, ndx|
54
79
  stub = /VAR#{ndx}/i
55
- text.gsub!(stub, interp)
80
+ text = text.gsub(stub, interp)
56
81
  end
57
82
  text
58
83
  end
@@ -61,34 +86,14 @@ module Tr4n5l4te
61
86
  return '' if text.nil?
62
87
  fail "Cannot translate a [#{text.class}]: '#{text}'" unless text.respond_to?(:gsub)
63
88
 
64
- CGI.escape(preprocess(text.strip))
65
- end
66
-
67
- def smart_visit(url)
68
- load_cookies
69
- agent.visit(url)
70
- store_cookies
71
- sleep_default
72
- end
73
-
74
- def translator_url(encoded_text, from_lang, to_lang)
75
- "#{START_PAGE}/##{from_lang}/#{to_lang}/#{encoded_text}"
76
- end
77
-
78
- def store_cookies
79
- agent.store_cookies(Tr4n5l4te.cookie_file)
80
- end
89
+ result = text.strip
90
+ return '' if result.empty?
81
91
 
82
- def load_cookies
83
- agent.load_cookies(Tr4n5l4te.cookie_file)
92
+ preprocess(result)
84
93
  end
85
94
 
86
95
  def sleep_default
87
96
  sleep(sleep_time)
88
97
  end
89
-
90
- def browser
91
- agent.browser
92
- end
93
98
  end
94
99
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tr4n5l4te
4
- VERSION = '0.1.17'.freeze
4
+ VERSION = '1.1.0'
5
5
  end
data/lib/tr4n5l4te.rb CHANGED
@@ -17,30 +17,8 @@ module Tr4n5l4te
17
17
  'tr4n5l4te'
18
18
  end
19
19
 
20
- def default_config_directory
21
- ".#{string_id}"
22
- end
23
-
24
- def default_cookie_filename
25
- 'cookies.yml'
26
- end
27
-
28
20
  def home_directory
29
- ENV.fetch('HOME')
30
- end
31
-
32
- # If you don't have a HOME directory defined, you are on an OS that is
33
- # retarded, and this call will fail.
34
- def cookie_file
35
- dir = File.join(home_directory, default_config_directory)
36
- module_string = string_id.upcase
37
- file = ENV.fetch(
38
- "#{module_string}_COOKIES",
39
- File.join(dir, default_cookie_filename)
40
- )
41
- FileUtils.mkdir_p(dir)
42
- FileUtils.touch(file)
43
- file
21
+ Dir.home
44
22
  end
45
23
 
46
24
  def configure
@@ -49,11 +27,10 @@ module Tr4n5l4te
49
27
  end
50
28
  end
51
29
 
52
- autoload :Agent, 'tr4n5l4te/agent'
53
30
  autoload :Configuration, 'tr4n5l4te/configuration'
54
31
  autoload :Language, 'tr4n5l4te/language'
55
32
  autoload :Runner, 'tr4n5l4te/runner'
56
33
  autoload :Translator, 'tr4n5l4te/translator'
57
34
  end
58
35
 
59
- Tr4n5l4te.configure {}
36
+ Tr4n5l4te.configuration = Tr4n5l4te::Configuration.new
data/tr4n5l4te.gemspec CHANGED
@@ -19,17 +19,10 @@ Gem::Specification.new do |spec|
19
19
  spec.bindir = 'exe'
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ['lib']
22
+ spec.required_ruby_version = '>= 3.2'
22
23
 
23
- spec.add_development_dependency 'bundler', '~> 2.1'
24
- spec.add_development_dependency 'pry-nav'
25
- spec.add_development_dependency 'rake', '~> 13.0'
26
- spec.add_development_dependency 'rspec', '~> 3.0'
27
- spec.add_development_dependency 'rubocop'
28
- spec.add_development_dependency 'simplecov', '~> 0.11'
29
-
30
- spec.add_dependency 'capybara', '~> 2.6'
31
24
  spec.add_dependency 'colored', '~> 1'
32
25
  spec.add_dependency 'midwire_common', '~> 0.1'
33
26
  spec.add_dependency 'optimist', '~> 3.0'
34
- spec.add_dependency 'poltergeist', '~> 1.9'
27
+ spec.metadata['rubygems_mfa_required'] = 'true'
35
28
  end
metadata CHANGED
@@ -1,113 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tr4n5l4te
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.17
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Blackburn
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-02-06 00:00:00.000000000 Z
10
+ date: 2026-02-17 00:00:00.000000000 Z
12
11
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '2.1'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '2.1'
27
- - !ruby/object:Gem::Dependency
28
- name: pry-nav
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: rake
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '13.0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '13.0'
55
- - !ruby/object:Gem::Dependency
56
- name: rspec
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '3.0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '3.0'
69
- - !ruby/object:Gem::Dependency
70
- name: rubocop
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: simplecov
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '0.11'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '0.11'
97
- - !ruby/object:Gem::Dependency
98
- name: capybara
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '2.6'
104
- type: :runtime
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '2.6'
111
12
  - !ruby/object:Gem::Dependency
112
13
  name: colored
113
14
  requirement: !ruby/object:Gem::Requirement
@@ -150,20 +51,6 @@ dependencies:
150
51
  - - "~>"
151
52
  - !ruby/object:Gem::Version
152
53
  version: '3.0'
153
- - !ruby/object:Gem::Dependency
154
- name: poltergeist
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - "~>"
158
- - !ruby/object:Gem::Version
159
- version: '1.9'
160
- type: :runtime
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - "~>"
165
- - !ruby/object:Gem::Version
166
- version: '1.9'
167
54
  description: Use Google Translate without an API key.
168
55
  email:
169
56
  - 87a1779b@opayq.com
@@ -175,6 +62,7 @@ files:
175
62
  - ".gitignore"
176
63
  - ".rspec"
177
64
  - ".rubocop.yml"
65
+ - ".ruby-version"
178
66
  - ".travis.yml"
179
67
  - CHANGELOG
180
68
  - CODE_OF_CONDUCT.md
@@ -192,7 +80,6 @@ files:
192
80
  - bin/setup
193
81
  - exe/translate
194
82
  - lib/tr4n5l4te.rb
195
- - lib/tr4n5l4te/agent.rb
196
83
  - lib/tr4n5l4te/configuration.rb
197
84
  - lib/tr4n5l4te/language.rb
198
85
  - lib/tr4n5l4te/runner.rb
@@ -202,8 +89,8 @@ files:
202
89
  homepage: https://github.com/midwire/tr4n5l4te
203
90
  licenses:
204
91
  - MIT
205
- metadata: {}
206
- post_install_message:
92
+ metadata:
93
+ rubygems_mfa_required: 'true'
207
94
  rdoc_options: []
208
95
  require_paths:
209
96
  - lib
@@ -211,15 +98,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
211
98
  requirements:
212
99
  - - ">="
213
100
  - !ruby/object:Gem::Version
214
- version: '0'
101
+ version: '3.2'
215
102
  required_rubygems_version: !ruby/object:Gem::Requirement
216
103
  requirements:
217
104
  - - ">="
218
105
  - !ruby/object:Gem::Version
219
106
  version: '0'
220
107
  requirements: []
221
- rubygems_version: 3.3.26
222
- signing_key:
108
+ rubygems_version: 3.6.5
223
109
  specification_version: 4
224
110
  summary: Use Google Translate without an API key.
225
111
  test_files: []
@@ -1,99 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'capybara'
4
- require 'capybara/poltergeist'
5
- require 'yaml'
6
-
7
- module Tr4n5l4te
8
- Capybara.register_driver :poltergeist do |app|
9
- Capybara::Poltergeist::Driver.new(
10
- app,
11
- js_errors: false,
12
- timeout: Tr4n5l4te.configuration.timeout,
13
- phantomjs_options: ['--load-images=no', '--ignore-ssl-errors=yes', '--web-security=false', '--ssl-protocol=any'],
14
- phantomjs_logger: StringIO.new,
15
- logger: StringIO.new
16
- )
17
- end
18
- Capybara.default_driver = :poltergeist
19
- Capybara.javascript_driver = :poltergeist
20
-
21
- class Agent
22
- # rubocop:disable Metrics/LineLength
23
- DEFAULT_UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/601.4.4 (KHTML, like Gecko) Version/9.0.3 Safari/601.4.4'
24
- # rubocop:enable Metrics/LineLength
25
-
26
- attr_reader :browser
27
-
28
- def initialize(options = {})
29
- Capybara.ignore_hidden_elements = false
30
- @browser = options[:browser] || Capybara.current_session
31
- browser.driver.headers = { 'User-Agent' => DEFAULT_UA }
32
- end
33
-
34
- def load_cookies(cookie_file)
35
- return false unless cookie_hash = YAML.safe_load(
36
- File.read(cookie_file), permitted_classes: [Capybara::Poltergeist::Cookie]
37
- )
38
-
39
- browser.driver.clear_cookies
40
- cookie_hash.each do |key, cookie_obj|
41
- browser.driver.set_cookie(
42
- key,
43
- cookie_obj.value,
44
- domain: cookie_obj.domain,
45
- path: cookie_obj.path,
46
- secure: cookie_obj.secure?,
47
- httponly: cookie_obj.httponly?,
48
- expires: cookie_obj.expires
49
- )
50
- end
51
- end
52
- # rubocop:enable
53
-
54
- def store_cookies(cookie_file)
55
- FileUtils.mkdir_p(File.dirname(cookie_file))
56
- data = YAML.dump(browser.driver.cookies)
57
- File.open(cookie_file, 'w') { |f| f.write(data) }
58
- end
59
-
60
- def set_cookie(name, value, options = {})
61
- browser.driver.set_cookie(
62
- name.to_s,
63
- value.to_s,
64
- domain: options.fetch(:domain, nil),
65
- path: options.fetch(:path, nil),
66
- secure: options.fetch(:secure, false),
67
- httponly: options.fetch(:httponly, false),
68
- expires: options.fetch(:expires, time_plus_years)
69
- )
70
- end
71
-
72
- def cookies
73
- browser.driver.cookies
74
- end
75
-
76
- def visit(url)
77
- response = browser.visit(url)
78
- response.recursively_symbolize_keys!
79
- end
80
-
81
- def body
82
- browser.body
83
- end
84
-
85
- def elements(selector_string)
86
- browser.all(selector_string)
87
- end
88
-
89
- private
90
-
91
- def time_plus_years(years = 30)
92
- Time.now + days(365) * years
93
- end
94
-
95
- def days(num)
96
- num * 86_400
97
- end
98
- end
99
- end