web_translate_it 3.1.2 → 3.2.1

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: d4db3eb8623580c53dff0ca3d6e4dea860781436b20c9ff4580bf53e5a7661d0
4
- data.tar.gz: f68c3e3ef4b7ed934a6df20da1c4eb13afaa7c115468595f241efc4bc3f5dea5
3
+ metadata.gz: d9a027a46383d8932b3776d7c614592e3bb186bed328954f0a39bd2e168f2ba3
4
+ data.tar.gz: 75bd8ab7c9129e6fb4f6c3c982fee30b1793a01ce2ba8219aa4e2480cb491246
5
5
  SHA512:
6
- metadata.gz: 2faab2844f1ed735004291f6dc7def7cdb630837c18e4e526ca90dc83cb537379090f825403a5cfb2b758fa7213945419fd47eb45e849b154b20af1cbf54d3a5
7
- data.tar.gz: b1ae273de1459eabe8ad461d0eee5261e2428aff6ad69230ee7af9a1806302efb09fcea4af7f864c0f6fde697ef7558339777717d583a6cdac95e92a5e9c70ae
6
+ metadata.gz: 20ce007c03f2a00b5eb2c4ba019f37b814ad5184792a1d14a6231351402f0c5988d470a6f64e1b732a2409c74a8f9696b542b3b12aa7ab9c267f0f1c94c5f3ef
7
+ data.tar.gz: 6aafb08ddff729b498093150eddafd55410f45a1f8d0239d7a11a5c1a2a06ccff802bd53996d442ef89da955ba38b290b25aad6e0f8bb7182e15527faec2d418
data/bin/wti CHANGED
@@ -13,6 +13,7 @@ show_commands = <<~COMMANDS
13
13
  pull Pull target language file(s)
14
14
  push Push master language file(s)
15
15
  match Display matching of local files with File Manager
16
+ diff Display a diff between local and remote files
16
17
  add Create and push a new master language file
17
18
  rm Delete a master language file from a project
18
19
  mv Moves a file both locally and from a project
@@ -26,7 +27,7 @@ show_commands = <<~COMMANDS
26
27
  [options] are:
27
28
  COMMANDS
28
29
 
29
- SUB_COMMANDS = %w[pull push match add rm mv addlocale rmlocale status st init].freeze
30
+ SUB_COMMANDS = %w[pull push match diff add rm mv addlocale rmlocale status st init].freeze
30
31
  global_options = Optimist.options do
31
32
  stop_on SUB_COMMANDS
32
33
  banner show_commands
@@ -65,6 +66,15 @@ when 'push'
65
66
  opt :all, 'DEPRECATED -- See `wti push --target` instead'
66
67
  opt :debug, 'Display debug information'
67
68
  end
69
+ when 'diff'
70
+ Optimist.options do
71
+ banner <<~BANNER
72
+ wti diff [filename] - Display a diff between local and remote files
73
+ [options] are:
74
+ BANNER
75
+ opt :config, 'Path to a configuration file', short: '-c', default: '.wti'
76
+ opt :debug, 'Display debug information'
77
+ end
68
78
  when 'add'
69
79
  Optimist.options do
70
80
  banner 'wti add filename - Create and push a new master language file'
data/history.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## Version 3.2.1 / 2026-03-02
2
+
3
+ * Refactor `Connection` class to eliminate class variables. #254
4
+ * Fix `find_all` to guard against non-2xx API responses. #355
5
+
6
+ ## Version 3.2.0 / 2026-01-14
7
+
8
+ * Add `wti diff` command.
9
+
1
10
  ## Version 3.1.2 / 2025-06-06
2
11
 
3
12
  * Fix `wti mv` command. #366
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'tempfile'
4
+
3
5
  module WebTranslateIt
4
6
 
5
7
  class CommandLine # rubocop:todo Metrics/ClassLength
6
8
 
7
9
  attr_accessor :configuration, :global_options, :command_options, :parameters
8
10
 
9
- def initialize(command, command_options, _global_options, parameters, project_path) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/MethodLength
11
+ def initialize(command, command_options, _global_options, parameters, project_path) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/AbcSize
10
12
  self.command_options = command_options
11
13
  self.parameters = parameters
12
14
  unless command == 'init'
@@ -15,6 +17,8 @@ module WebTranslateIt
15
17
  'Pulling files'
16
18
  when 'push'
17
19
  'Pushing files'
20
+ when 'diff'
21
+ 'Diffing files'
18
22
  when 'add'
19
23
  'Creating master files'
20
24
  when 'rm'
@@ -64,9 +68,9 @@ module WebTranslateIt
64
68
  next if file_array.empty?
65
69
 
66
70
  threads << Thread.new(file_array) do |f_array|
67
- WebTranslateIt::Connection.new(configuration.api_key) do |http|
71
+ WebTranslateIt::Connection.new(configuration.api_key) do |conn|
68
72
  f_array.each do |file|
69
- success = file.fetch(http, command_options.force)
73
+ success = file.fetch(conn.http_connection, command_options.force)
70
74
  complete_success = false unless success
71
75
  end
72
76
  end
@@ -107,7 +111,7 @@ module WebTranslateIt
107
111
  complete_success = true
108
112
  $stdout.sync = true
109
113
  before_push_hook
110
- WebTranslateIt::Connection.new(configuration.api_key) do |http|
114
+ WebTranslateIt::Connection.new(configuration.api_key) do |conn|
111
115
  fetch_locales_to_push(configuration).each do |locale|
112
116
  files = if parameters.any?
113
117
  configuration.files.find_all { |file| parameters.include?(file.file_path) }.sort { |a, b| a.file_path <=> b.file_path }
@@ -118,7 +122,7 @@ module WebTranslateIt
118
122
  puts "Couldn't find any local files registered on WebTranslateIt to push."
119
123
  else
120
124
  files.each do |file|
121
- success = file.upload(http, command_options[:merge], command_options.ignore_missing, command_options.label, command_options[:minor], command_options.force)
125
+ success = file.upload(conn.http_connection, command_options[:merge], command_options.ignore_missing, command_options.label, command_options[:minor], command_options.force)
122
126
  complete_success = false unless success
123
127
  end
124
128
  end
@@ -150,6 +154,42 @@ module WebTranslateIt
150
154
  end
151
155
  end
152
156
 
157
+ def diff # rubocop:todo Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
158
+ complete_success = true
159
+ $stdout.sync = true
160
+ WebTranslateIt::Connection.new(configuration.api_key) do |conn| # rubocop:todo Metrics/BlockLength
161
+ files = if parameters.any?
162
+ configuration.files.find_all { |file| parameters.include?(file.file_path) }.sort { |a, b| a.file_path <=> b.file_path }
163
+ else
164
+ configuration.files.find_all { |file| file.locale == configuration.source_locale }.sort { |a, b| a.file_path <=> b.file_path }
165
+ end
166
+ if files.empty?
167
+ puts "Couldn't find any local files registered on WebTranslateIt to diff."
168
+ else
169
+ files.each do |file|
170
+ if File.exist?(file.file_path)
171
+ remote_content = file.fetch_remote_content(conn.http_connection)
172
+ if remote_content
173
+ temp_file = Tempfile.new('wti')
174
+ temp_file.write(remote_content)
175
+ temp_file.close
176
+ puts "Diff for #{file.file_path}:"
177
+ system "diff #{temp_file.path} #{file.file_path}"
178
+ temp_file.unlink
179
+ else
180
+ puts StringUtil.failure("Couldn't fetch remote file #{file.file_path}")
181
+ complete_success = false
182
+ end
183
+ else
184
+ puts StringUtil.failure("Can't diff #{file.file_path}. File doesn't exist locally.")
185
+ complete_success = false
186
+ end
187
+ end
188
+ end
189
+ end
190
+ complete_success
191
+ end
192
+
153
193
  def add # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
154
194
  complete_success = true
155
195
  $stdout.sync = true
@@ -158,13 +198,13 @@ module WebTranslateIt
158
198
  puts 'Usage: wti add path/to/master_file_1 path/to/master_file_2 ...'
159
199
  exit
160
200
  end
161
- WebTranslateIt::Connection.new(configuration.api_key) do |http|
201
+ WebTranslateIt::Connection.new(configuration.api_key) do |conn|
162
202
  added = configuration.files.find_all { |file| file.locale == configuration.source_locale }.to_set { |file| File.expand_path(file.file_path) }
163
203
  to_add = parameters.reject { |param| added.include?(File.expand_path(param)) }
164
204
  if to_add.any?
165
205
  to_add.each do |param|
166
206
  file = TranslationFile.new(nil, param.gsub(/ /, '\\ '), nil, configuration.api_key)
167
- success = file.create(http)
207
+ success = file.create(conn.http_connection)
168
208
  complete_success = false unless success
169
209
  end
170
210
  else
@@ -182,14 +222,14 @@ module WebTranslateIt
182
222
  puts 'Usage: wti rm path/to/master_file_1 path/to/master_file_2 ...'
183
223
  exit
184
224
  end
185
- WebTranslateIt::Connection.new(configuration.api_key) do |http| # rubocop:todo Metrics/BlockLength
225
+ WebTranslateIt::Connection.new(configuration.api_key) do |conn| # rubocop:todo Metrics/BlockLength
186
226
  parameters.each do |param|
187
227
  next unless Util.ask_yes_no("Are you sure you want to delete the master file #{param}?\nThis will also delete its target files and translations.", false)
188
228
 
189
229
  files = configuration.files.find_all { |file| file.file_path == param }
190
230
  if files.any?
191
231
  files.each do |master_file|
192
- master_file.delete(http)
232
+ master_file.delete(conn.http_connection)
193
233
  # delete files
194
234
  if File.exist?(master_file.file_path)
195
235
  success = File.delete(master_file.file_path)
@@ -225,10 +265,10 @@ module WebTranslateIt
225
265
  end
226
266
  source = parameters[0]
227
267
  destination = parameters[1]
228
- WebTranslateIt::Connection.new(configuration.api_key) do |http|
268
+ WebTranslateIt::Connection.new(configuration.api_key) do |conn|
229
269
  if Util.ask_yes_no("Are you sure you want to move the master file #{source} and its target files?", true)
230
270
  configuration.files.find_all { |file| file.file_path == source }.each do |master_file|
231
- master_file.upload(http, false, false, nil, false, true, true, destination)
271
+ master_file.upload(conn.http_connection, false, false, nil, false, true, true, destination)
232
272
  # move master file
233
273
  if File.exist?(source)
234
274
  success = File.rename(source, destination) if File.exist?(source)
@@ -243,7 +283,7 @@ module WebTranslateIt
243
283
  end
244
284
  configuration.reload
245
285
  configuration.files.find_all { |file| file.master_id == master_file.id }.each do |target_file|
246
- success = target_file.fetch(http)
286
+ success = target_file.fetch(conn.http_connection)
247
287
  complete_success = false unless success
248
288
  end
249
289
  puts StringUtil.success('All done.') if complete_success
@@ -262,8 +302,8 @@ module WebTranslateIt
262
302
  end
263
303
  parameters.each do |param|
264
304
  print StringUtil.success("Adding locale #{param.upcase}... ")
265
- WebTranslateIt::Connection.new(configuration.api_key) do
266
- WebTranslateIt::Project.create_locale(param)
305
+ WebTranslateIt::Connection.new(configuration.api_key) do |conn|
306
+ WebTranslateIt::Project.create_locale(conn, param)
267
307
  end
268
308
  puts 'Done.'
269
309
  end
@@ -280,8 +320,8 @@ module WebTranslateIt
280
320
  next unless Util.ask_yes_no("Are you certain you want to delete the locale #{param.upcase}?\nThis will also delete its files and translations.", false)
281
321
 
282
322
  print StringUtil.success("Deleting locale #{param.upcase}... ")
283
- WebTranslateIt::Connection.new(configuration.api_key) do
284
- WebTranslateIt::Project.delete_locale(param)
323
+ WebTranslateIt::Connection.new(configuration.api_key) do |conn|
324
+ WebTranslateIt::Project.delete_locale(conn, param)
285
325
  end
286
326
  puts 'Done.'
287
327
  end
@@ -296,7 +336,7 @@ module WebTranslateIt
296
336
  api_key = Util.ask(' Project API Key:')
297
337
  path = Util.ask(' Path to configuration file:', '.wti')
298
338
  end
299
- FileUtils.mkpath(path.split('/')[0..path.split('/').size - 2].join('/')) unless path.split('/').size == 1
339
+ FileUtils.mkpath(path.split('/')[0..(path.split('/').size - 2)].join('/')) unless path.split('/').size == 1
300
340
  project = JSON.parse WebTranslateIt::Project.fetch_info(api_key)
301
341
  project_info = project['project']
302
342
  if File.exist?(path) && !File.writable?(path)
@@ -4,36 +4,36 @@ module WebTranslateIt
4
4
 
5
5
  class Connection
6
6
 
7
- @@api_key = nil
8
- @@http_connection = nil
9
- @@debug = false
7
+ @debug = false
8
+
9
+ class << self
10
+
11
+ attr_reader :debug
12
+
13
+ end
14
+
15
+ attr_reader :api_key, :http_connection
10
16
 
11
17
  #
12
18
  # Initialize and yield a HTTPS Keep-Alive connection to WebTranslateIt.com
13
19
  #
14
20
  # Usage:
15
21
  #
16
- # WebTranslateIt::Connection.new(api_key) do
17
- # # do something with Connection.api_key and Connection.http_connection
18
- # end
19
- #
20
- # Or:
21
- #
22
- # WebTranslateIt::Connection.new(api_key) do |http_connection|
23
- # http_connection.request(request)
22
+ # WebTranslateIt::Connection.new(api_key) do |connection|
23
+ # connection.http_connection.request(request)
24
24
  # end
25
25
  #
26
26
  def initialize(api_key) # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
27
- @@api_key = api_key
27
+ @api_key = api_key
28
28
  proxy = ENV['http_proxy'] ? URI.parse(ENV['http_proxy']) : Struct.new(:host, :port, :user, :password).new
29
29
  http = Net::HTTP::Proxy(proxy.host, proxy.port, proxy.user, proxy.password).new('webtranslateit.com', 443)
30
30
  http.use_ssl = true
31
31
  http.open_timeout = http.read_timeout = 60
32
- http.set_debug_output($stderr) if @@debug
32
+ http.set_debug_output($stderr) if self.class.debug
33
33
  begin
34
34
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
35
- @@http_connection = http.start
36
- yield @@http_connection if block_given?
35
+ @http_connection = http.start
36
+ yield self if block_given?
37
37
  rescue OpenSSL::SSL::SSLError
38
38
  puts 'Error: Unable to verify SSL certificate.'
39
39
  exit 1
@@ -43,15 +43,7 @@ module WebTranslateIt
43
43
  end
44
44
 
45
45
  def self.turn_debug_on
46
- @@debug = true
47
- end
48
-
49
- def self.api_key
50
- @@api_key
51
- end
52
-
53
- def self.http_connection
54
- @@http_connection
46
+ @debug = true
55
47
  end
56
48
 
57
49
  end
@@ -8,10 +8,10 @@ module WebTranslateIt
8
8
  success = true
9
9
  tries ||= 3
10
10
  begin
11
- WebTranslateIt::Connection.new(api_key) do |http|
11
+ WebTranslateIt::Connection.new(api_key) do |conn|
12
12
  request = Net::HTTP::Get.new("/api/projects/#{api_key}")
13
13
  WebTranslateIt::Util.add_fields(request)
14
- response = http.request(request)
14
+ response = conn.http_connection.request(request)
15
15
  return response.body if response.is_a?(Net::HTTPSuccess)
16
16
 
17
17
  puts 'An error occured while fetching the project information:'
@@ -37,10 +37,10 @@ module WebTranslateIt
37
37
  success = true
38
38
  tries ||= 3
39
39
  begin
40
- WebTranslateIt::Connection.new(api_key) do |http|
40
+ WebTranslateIt::Connection.new(api_key) do |conn|
41
41
  request = Net::HTTP::Get.new(url)
42
42
  WebTranslateIt::Util.add_fields(request)
43
- return Util.handle_response(http.request(request), true)
43
+ return Util.handle_response(conn.http_connection.request(request), true)
44
44
  end
45
45
  rescue Timeout::Error
46
46
  puts 'Request timeout. Will retry in 5 seconds.'
@@ -54,14 +54,14 @@ module WebTranslateIt
54
54
  success
55
55
  end
56
56
 
57
- def self.create_locale(locale_code) # rubocop:todo Metrics/MethodLength
57
+ def self.create_locale(connection, locale_code) # rubocop:todo Metrics/MethodLength
58
58
  success = true
59
59
  tries ||= 3
60
60
  begin
61
- request = Net::HTTP::Post.new("/api/projects/#{Connection.api_key}/locales")
61
+ request = Net::HTTP::Post.new("/api/projects/#{connection.api_key}/locales")
62
62
  WebTranslateIt::Util.add_fields(request)
63
63
  request.set_form_data({'id' => locale_code}, ';')
64
- Util.handle_response(Connection.http_connection.request(request), true)
64
+ Util.handle_response(connection.http_connection.request(request), true)
65
65
  rescue Timeout::Error
66
66
  puts 'Request timeout. Will retry in 5 seconds.'
67
67
  if (tries -= 1).positive?
@@ -74,13 +74,13 @@ module WebTranslateIt
74
74
  success
75
75
  end
76
76
 
77
- def self.delete_locale(locale_code) # rubocop:todo Metrics/MethodLength
77
+ def self.delete_locale(connection, locale_code) # rubocop:todo Metrics/MethodLength
78
78
  success = true
79
79
  tries ||= 3
80
80
  begin
81
- request = Net::HTTP::Delete.new("/api/projects/#{Connection.api_key}/locales/#{locale_code}")
81
+ request = Net::HTTP::Delete.new("/api/projects/#{connection.api_key}/locales/#{locale_code}")
82
82
  WebTranslateIt::Util.add_fields(request)
83
- Util.handle_response(Connection.http_connection.request(request), true)
83
+ Util.handle_response(connection.http_connection.request(request), true)
84
84
  rescue Timeout::Error
85
85
  puts 'Request timeout. Will retry in 5 seconds.'
86
86
  if (tries -= 1).positive?
@@ -5,7 +5,7 @@ module WebTranslateIt
5
5
  class String # rubocop:todo Metrics/ClassLength
6
6
 
7
7
  attr_accessor :id, :key, :plural, :type, :dev_comment, :word_count, :status, :category, :labels, :file,
8
- :created_at, :updated_at, :translations, :new_record
8
+ :created_at, :updated_at, :translations, :new_record, :connection
9
9
 
10
10
  # Initialize a new WebTranslateIt::String
11
11
  #
@@ -21,8 +21,9 @@ module WebTranslateIt
21
21
  #
22
22
  # to instantiate a new String with a source and target translation.
23
23
 
24
- def initialize(params = {}) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
24
+ def initialize(params = {}, connection: nil) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
25
25
  params.stringify_keys!
26
+ self.connection = connection
26
27
  self.id = params['id'] || nil
27
28
  self.key = params['key'] || nil
28
29
  self.plural = params['plural'] || nil
@@ -51,11 +52,11 @@ module WebTranslateIt
51
52
  #
52
53
  # to find and instantiate an array of String which key is like `product_name_123`.
53
54
 
54
- def self.find_all(params = {}) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
55
+ def self.find_all(connection, params = {}) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
55
56
  success = true
56
57
  tries ||= 3
57
58
  params.stringify_keys!
58
- url = "/api/projects/#{Connection.api_key}/strings"
59
+ url = "/api/projects/#{connection.api_key}/strings"
59
60
  url += "?#{HashUtil.to_params('filters' => params)}" unless params.empty?
60
61
 
61
62
  request = Net::HTTP::Get.new(url)
@@ -63,9 +64,11 @@ module WebTranslateIt
63
64
  begin
64
65
  strings = []
65
66
  while request
66
- response = Connection.http_connection.request(request)
67
+ response = connection.http_connection.request(request)
68
+ return [] unless response.code.to_i < 400
69
+
67
70
  JSON.parse(response.body).each do |string_response|
68
- string = WebTranslateIt::String.new(string_response)
71
+ string = WebTranslateIt::String.new(string_response, connection: connection)
69
72
  string.new_record = false
70
73
  strings.push(string)
71
74
  end
@@ -104,16 +107,16 @@ module WebTranslateIt
104
107
  # to find and instantiate the String which ID is `1234`.
105
108
  #
106
109
 
107
- def self.find(id) # rubocop:todo Metrics/MethodLength, Metrics/AbcSize
110
+ def self.find(connection, id) # rubocop:todo Metrics/MethodLength, Metrics/AbcSize
108
111
  success = true
109
112
  tries ||= 3
110
- request = Net::HTTP::Get.new("/api/projects/#{Connection.api_key}/strings/#{id}")
113
+ request = Net::HTTP::Get.new("/api/projects/#{connection.api_key}/strings/#{id}")
111
114
  WebTranslateIt::Util.add_fields(request)
112
115
  begin
113
- response = Connection.http_connection.request(request)
116
+ response = connection.http_connection.request(request)
114
117
  return nil if response.code.to_i == 404
115
118
 
116
- string = WebTranslateIt::String.new(JSON.parse(response.body))
119
+ string = WebTranslateIt::String.new(JSON.parse(response.body), connection: connection)
117
120
  string.new_record = false
118
121
  return string
119
122
  rescue Timeout::Error
@@ -156,10 +159,10 @@ module WebTranslateIt
156
159
  def delete # rubocop:todo Metrics/MethodLength
157
160
  success = true
158
161
  tries ||= 3
159
- request = Net::HTTP::Delete.new("/api/projects/#{Connection.api_key}/strings/#{id}")
162
+ request = Net::HTTP::Delete.new("/api/projects/#{connection.api_key}/strings/#{id}")
160
163
  WebTranslateIt::Util.add_fields(request)
161
164
  begin
162
- Util.handle_response(Connection.http_connection.request(request), true, true)
165
+ Util.handle_response(connection.http_connection.request(request), true, true)
163
166
  rescue Timeout::Error
164
167
  puts 'Request timeout. Will retry in 5 seconds.'
165
168
  if (tries -= 1).positive?
@@ -189,14 +192,15 @@ module WebTranslateIt
189
192
  return translation if translation
190
193
  return nil if new_record
191
194
 
192
- request = Net::HTTP::Get.new("/api/projects/#{Connection.api_key}/strings/#{id}/locales/#{locale}/translations")
195
+ request = Net::HTTP::Get.new("/api/projects/#{connection.api_key}/strings/#{id}/locales/#{locale}/translations")
193
196
  WebTranslateIt::Util.add_fields(request)
194
197
  begin
195
- response = Util.handle_response(Connection.http_connection.request(request), true, true)
198
+ response = Util.handle_response(connection.http_connection.request(request), true, true)
196
199
  hash = JSON.parse(response)
197
200
  return nil if hash.empty?
198
201
 
199
202
  translation = WebTranslateIt::Translation.new(hash)
203
+ translation.connection = connection
200
204
  return translation
201
205
  rescue Timeout::Error
202
206
  puts 'Request timeout. Will retry in 5 seconds.'
@@ -218,17 +222,18 @@ module WebTranslateIt
218
222
  def update # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
219
223
  success = true
220
224
  tries ||= 3
221
- request = Net::HTTP::Put.new("/api/projects/#{Connection.api_key}/strings/#{id}")
225
+ request = Net::HTTP::Put.new("/api/projects/#{connection.api_key}/strings/#{id}")
222
226
  WebTranslateIt::Util.add_fields(request)
223
227
  request.body = to_json
224
228
 
225
229
  translations.each do |translation|
226
230
  translation.string_id = id
231
+ translation.connection = connection
227
232
  translation.save
228
233
  end
229
234
 
230
235
  begin
231
- Util.handle_response(Connection.http_connection.request(request), true, true)
236
+ Util.handle_response(connection.http_connection.request(request), true, true)
232
237
  rescue Timeout::Error
233
238
  puts 'Request timeout. Will retry in 5 seconds.'
234
239
  if (tries -= 1).positive?
@@ -247,11 +252,11 @@ module WebTranslateIt
247
252
  def create # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
248
253
  success = true
249
254
  tries ||= 3
250
- request = Net::HTTP::Post.new("/api/projects/#{Connection.api_key}/strings")
255
+ request = Net::HTTP::Post.new("/api/projects/#{connection.api_key}/strings")
251
256
  WebTranslateIt::Util.add_fields(request)
252
257
  request.body = to_json(true)
253
258
  begin
254
- response = JSON.parse(Util.handle_response(Connection.http_connection.request(request), true, true))
259
+ response = JSON.parse(Util.handle_response(connection.http_connection.request(request), true, true))
255
260
  self.id = response['id']
256
261
  self.new_record = false
257
262
  return true
@@ -4,7 +4,7 @@ module WebTranslateIt
4
4
 
5
5
  class Term # rubocop:todo Metrics/ClassLength
6
6
 
7
- attr_accessor :id, :text, :description, :created_at, :updated_at, :translations, :new_record
7
+ attr_accessor :id, :text, :description, :created_at, :updated_at, :translations, :new_record, :connection
8
8
 
9
9
  # Initialize a new WebTranslateIt::Term
10
10
  #
@@ -20,8 +20,9 @@ module WebTranslateIt
20
20
  #
21
21
  # to instantiate a new Term with a Term Translations in Spanish and French.
22
22
 
23
- def initialize(params = {})
23
+ def initialize(params = {}, connection: nil) # rubocop:todo Metrics/AbcSize
24
24
  params.stringify_keys!
25
+ self.connection = connection
25
26
  self.id = params['id'] || nil
26
27
  self.text = params['text'] || nil
27
28
  self.description = params['description'] || nil
@@ -41,11 +42,11 @@ module WebTranslateIt
41
42
  #
42
43
  # puts terms.inspect #=> An array of WebTranslateIt::Term objects
43
44
 
44
- def self.find_all(params = {}) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
45
+ def self.find_all(connection, params = {}) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
45
46
  success = true
46
47
  tries ||= 3
47
48
  params.stringify_keys!
48
- url = "/api/projects/#{Connection.api_key}/terms"
49
+ url = "/api/projects/#{connection.api_key}/terms"
49
50
  url += "?#{HashUtil.to_params(params)}" unless params.empty?
50
51
 
51
52
  request = Net::HTTP::Get.new(url)
@@ -53,9 +54,11 @@ module WebTranslateIt
53
54
  begin
54
55
  terms = []
55
56
  while request
56
- response = Connection.http_connection.request(request)
57
+ response = connection.http_connection.request(request)
58
+ return [] unless response.code.to_i < 400
59
+
57
60
  JSON.parse(response.body).each do |term_response|
58
- term = WebTranslateIt::Term.new(term_response)
61
+ term = WebTranslateIt::Term.new(term_response, connection: connection)
59
62
  term.new_record = false
60
63
  terms.push(term)
61
64
  end
@@ -94,16 +97,16 @@ module WebTranslateIt
94
97
  # to find and instantiate the Term which ID is `1234`.
95
98
  #
96
99
 
97
- def self.find(term_id) # rubocop:todo Metrics/MethodLength, Metrics/AbcSize
100
+ def self.find(connection, term_id) # rubocop:todo Metrics/MethodLength, Metrics/AbcSize
98
101
  success = true
99
102
  tries ||= 3
100
- request = Net::HTTP::Get.new("/api/projects/#{Connection.api_key}/terms/#{term_id}")
103
+ request = Net::HTTP::Get.new("/api/projects/#{connection.api_key}/terms/#{term_id}")
101
104
  WebTranslateIt::Util.add_fields(request)
102
105
  begin
103
- response = Connection.http_connection.request(request)
106
+ response = connection.http_connection.request(request)
104
107
  return nil if response.code.to_i == 404
105
108
 
106
- term = WebTranslateIt::Term.new(JSON.parse(response.body))
109
+ term = WebTranslateIt::Term.new(JSON.parse(response.body), connection: connection)
107
110
  term.new_record = false
108
111
  return term
109
112
  rescue Timeout::Error
@@ -146,10 +149,10 @@ module WebTranslateIt
146
149
  def delete # rubocop:todo Metrics/MethodLength
147
150
  success = true
148
151
  tries ||= 3
149
- request = Net::HTTP::Delete.new("/api/projects/#{Connection.api_key}/terms/#{id}")
152
+ request = Net::HTTP::Delete.new("/api/projects/#{connection.api_key}/terms/#{id}")
150
153
  WebTranslateIt::Util.add_fields(request)
151
154
  begin
152
- Util.handle_response(Connection.http_connection.request(request), true, true)
155
+ Util.handle_response(connection.http_connection.request(request), true, true)
153
156
  rescue Timeout::Error
154
157
  puts 'Request timeout. Will retry in 5 seconds.'
155
158
  if (tries -= 1).positive?
@@ -179,10 +182,10 @@ module WebTranslateIt
179
182
  return translation if translation
180
183
  return nil if new_record
181
184
 
182
- request = Net::HTTP::Get.new("/api/projects/#{Connection.api_key}/terms/#{id}/locales/#{locale}/translations")
185
+ request = Net::HTTP::Get.new("/api/projects/#{connection.api_key}/terms/#{id}/locales/#{locale}/translations")
183
186
  WebTranslateIt::Util.add_fields(request)
184
187
  begin
185
- response = Util.handle_response(Connection.http_connection.request(request), true, true)
188
+ response = Util.handle_response(connection.http_connection.request(request), true, true)
186
189
  array = JSON.parse(response)
187
190
  return nil if array.empty?
188
191
 
@@ -209,17 +212,18 @@ module WebTranslateIt
209
212
  def update # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
210
213
  success = true
211
214
  tries ||= 3
212
- request = Net::HTTP::Put.new("/api/projects/#{Connection.api_key}/terms/#{id}")
215
+ request = Net::HTTP::Put.new("/api/projects/#{connection.api_key}/terms/#{id}")
213
216
  WebTranslateIt::Util.add_fields(request)
214
217
  request.body = to_json
215
218
 
216
219
  translations.each do |translation|
217
220
  translation.term_id = id
221
+ translation.connection = connection
218
222
  translation.save
219
223
  end
220
224
 
221
225
  begin
222
- Util.handle_response(Connection.http_connection.request(request), true, true)
226
+ Util.handle_response(connection.http_connection.request(request), true, true)
223
227
  rescue Timeout::Error
224
228
  puts 'Request timeout. Will retry in 5 seconds.'
225
229
  if (tries -= 1).positive?
@@ -235,12 +239,12 @@ module WebTranslateIt
235
239
  def create # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
236
240
  success = true
237
241
  tries ||= 3
238
- request = Net::HTTP::Post.new("/api/projects/#{Connection.api_key}/terms")
242
+ request = Net::HTTP::Post.new("/api/projects/#{connection.api_key}/terms")
239
243
  WebTranslateIt::Util.add_fields(request)
240
244
  request.body = to_json(true)
241
245
 
242
246
  begin
243
- response = JSON.parse(Util.handle_response(Connection.http_connection.request(request), true, true))
247
+ response = JSON.parse(Util.handle_response(connection.http_connection.request(request), true, true))
244
248
  self.id = response['id']
245
249
  self.new_record = false
246
250
  return true
@@ -4,7 +4,7 @@ module WebTranslateIt
4
4
 
5
5
  class TermTranslation
6
6
 
7
- attr_accessor :id, :locale, :text, :description, :status, :new_record, :term_id
7
+ attr_accessor :id, :locale, :text, :description, :status, :new_record, :term_id, :connection
8
8
 
9
9
  # Initialize a new WebTranslateIt::TermTranslation
10
10
  #
@@ -59,12 +59,12 @@ module WebTranslateIt
59
59
  def create # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
60
60
  success = true
61
61
  tries ||= 3
62
- request = Net::HTTP::Post.new("/api/projects/#{Connection.api_key}/terms/#{term_id}/locales/#{locale}/translations")
62
+ request = Net::HTTP::Post.new("/api/projects/#{connection.api_key}/terms/#{term_id}/locales/#{locale}/translations")
63
63
  WebTranslateIt::Util.add_fields(request)
64
64
  request.body = to_json
65
65
 
66
66
  begin
67
- response = JSON.parse(Util.handle_response(Connection.http_connection.request(request), true, true))
67
+ response = JSON.parse(Util.handle_response(connection.http_connection.request(request), true, true))
68
68
  self.id = response['id']
69
69
  self.new_record = false
70
70
  return true
@@ -80,14 +80,14 @@ module WebTranslateIt
80
80
  success
81
81
  end
82
82
 
83
- def update # rubocop:todo Metrics/MethodLength
83
+ def update # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
84
84
  success = true
85
85
  tries ||= 3
86
- request = Net::HTTP::Put.new("/api/projects/#{Connection.api_key}/terms/#{id}/locales/#{locale}/translations/#{id}")
86
+ request = Net::HTTP::Put.new("/api/projects/#{connection.api_key}/terms/#{id}/locales/#{locale}/translations/#{id}")
87
87
  WebTranslateIt::Util.add_fields(request)
88
88
  request.body = to_json
89
89
  begin
90
- Util.handle_response(Connection.http_connection.request(request), true, true)
90
+ Util.handle_response(connection.http_connection.request(request), true, true)
91
91
  rescue Timeout::Error
92
92
  puts 'Request timeout. Will retry in 5 seconds.'
93
93
  if (tries -= 1).positive?
@@ -4,7 +4,7 @@ module WebTranslateIt
4
4
 
5
5
  class Translation
6
6
 
7
- attr_accessor :id, :locale, :text, :status, :created_at, :updated_at, :version, :string_id
7
+ attr_accessor :id, :locale, :text, :status, :created_at, :updated_at, :version, :string_id, :connection
8
8
 
9
9
  # Initialize a new WebTranslateIt::Translation
10
10
  #
@@ -39,11 +39,11 @@ module WebTranslateIt
39
39
 
40
40
  def save # rubocop:todo Metrics/MethodLength
41
41
  tries ||= 3
42
- request = Net::HTTP::Post.new("/api/projects/#{Connection.api_key}/strings/#{string_id}/locales/#{locale}/translations")
42
+ request = Net::HTTP::Post.new("/api/projects/#{connection.api_key}/strings/#{string_id}/locales/#{locale}/translations")
43
43
  WebTranslateIt::Util.add_fields(request)
44
44
  request.body = to_json
45
45
  begin
46
- Util.handle_response(Connection.http_connection.request(request), true, true)
46
+ Util.handle_response(connection.http_connection.request(request), true, true)
47
47
  rescue Timeout::Error
48
48
  puts 'Request timeout. Will retry in 5 seconds.'
49
49
  if (tries -= 1).positive?
@@ -46,27 +46,27 @@ module WebTranslateIt
46
46
  end
47
47
  display.push "#{StringUtil.checksumify(local_checksum.to_s)}..#{StringUtil.checksumify(remote_checksum.to_s)}"
48
48
  if !File.exist?(file_path) || force || (remote_checksum != local_checksum)
49
+
50
+ request = Net::HTTP::Get.new(api_url)
51
+ WebTranslateIt::Util.add_fields(request)
52
+ FileUtils.mkpath(file_path.split('/')[0..-2].join('/')) unless File.exist?(file_path) || (file_path.split('/')[0..-2].join('/') == '')
49
53
  begin
50
- request = Net::HTTP::Get.new(api_url)
51
- WebTranslateIt::Util.add_fields(request)
52
- FileUtils.mkpath(file_path.split('/')[0..-2].join('/')) unless File.exist?(file_path) || (file_path.split('/')[0..-2].join('/') == '')
53
- begin
54
- response = http_connection.request(request)
55
- File.open(file_path, 'wb') { |file| file << response.body } if response.code.to_i == 200
56
- display.push Util.handle_response(response)
57
- rescue Timeout::Error
58
- puts StringUtil.failure('Request timeout. Will retry in 5 seconds.')
59
- if (tries -= 1).positive?
60
- sleep(5)
61
- retry
62
- else
63
- success = false
64
- end
65
- rescue StandardError
66
- display.push StringUtil.failure("An error occured: #{$ERROR_INFO}")
54
+ response = http_connection.request(request)
55
+ File.open(file_path, 'wb') { |file| file << response.body } if response.code.to_i == 200
56
+ display.push Util.handle_response(response)
57
+ rescue Timeout::Error
58
+ puts StringUtil.failure('Request timeout. Will retry in 5 seconds.')
59
+ if (tries -= 1).positive?
60
+ sleep(5)
61
+ retry
62
+ else
67
63
  success = false
68
64
  end
65
+ rescue StandardError
66
+ display.push StringUtil.failure("An error occured: #{$ERROR_INFO}")
67
+ success = false
69
68
  end
69
+
70
70
  else
71
71
  display.push StringUtil.success('Skipped')
72
72
  end
@@ -74,6 +74,13 @@ module WebTranslateIt
74
74
  success
75
75
  end
76
76
 
77
+ def fetch_remote_content(http_connection)
78
+ request = Net::HTTP::Get.new(api_url)
79
+ WebTranslateIt::Util.add_fields(request)
80
+ response = http_connection.request(request)
81
+ response.body if response.code.to_i == 200
82
+ end
83
+
77
84
  # Update a language file to Web Translate It by performing a PUT Request.
78
85
  #
79
86
  # Example of implementation:
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+
5
+ # Destructively convert all keys to strings.
6
+ def stringify_keys!
7
+ keys.each do |key|
8
+ self[key.to_s] = delete(key)
9
+ end
10
+ self
11
+ end
12
+
13
+ end
@@ -3,7 +3,7 @@
3
3
  class HashUtil
4
4
 
5
5
  def self.to_params(hash) # rubocop:todo Metrics/MethodLength
6
- params = ''
6
+ params = +''
7
7
  stack = []
8
8
 
9
9
  hash.each do |k, v|
@@ -30,14 +30,4 @@ class HashUtil
30
30
 
31
31
  end
32
32
 
33
- class Hash
34
-
35
- # Destructively convert all keys to strings.
36
- def stringify_keys!
37
- keys.each do |key|
38
- self[key.to_s] = delete(key)
39
- end
40
- self
41
- end
42
-
43
- end
33
+ require_relative 'hash_extensions'
@@ -3,7 +3,7 @@
3
3
  class StringUtil
4
4
 
5
5
  def self.backward_truncate(str)
6
- return "...#{str[str.length - 50 + 3..str.length]}" if str.length > 50
6
+ return "...#{str[(str.length - 50 + 3)..str.length]}" if str.length > 50
7
7
 
8
8
  spaces = ''
9
9
  (50 - str.length).times { spaces += ' ' }
@@ -34,9 +34,9 @@ module WebTranslateIt
34
34
  return if config.ignore_locales.include?(locale)
35
35
 
36
36
  config.logger&.debug { " Fetching #{locale} language file(s) from WebTranslateIt" }
37
- WebTranslateIt::Connection.new(config.api_key) do |http|
37
+ WebTranslateIt::Connection.new(config.api_key) do |conn|
38
38
  config.files.find_all { |file| file.locale.in?([locale, I18n.locale]) }.each do |file|
39
- file.fetch(http)
39
+ file.fetch(conn.http_connection)
40
40
  end
41
41
  end
42
42
  end
data/man/wti.1 CHANGED
@@ -15,6 +15,9 @@
15
15
  .P
16
16
  \fBwti pull\fR [\fB\-l\fR] \fIOPTIONS\fR
17
17
  .
18
+ .P
19
+ \fBwti diff\fR \fIOPTIONS\fR
20
+ .
18
21
  .SH "DESCRIPTION"
19
22
  \fBwti\fR is an utility to help you sync language files between the WebTranslateIt\.com service and your computer/server\.
20
23
  .
@@ -25,6 +28,9 @@
25
28
  \fBwti pull\fR will pull the target language files from Web Translate It\. It will download and update your file with the latest translations from Web Translate It\.
26
29
  .
27
30
  .P
31
+ \fBwti diff\fR will show a difference between your local file and the file hosted at Web Translate It\.
32
+ .
33
+ .P
28
34
  \fBwti status\fR fetch and display translation statistics from Web Translate It\.
29
35
  .
30
36
  .SH "OPTIONS"
data/man/wti.1.html CHANGED
@@ -93,6 +93,8 @@ update the strings hosted at Web Translate It by the strings from the file you p
93
93
  <p><code>wti pull</code> will pull the target language files from Web Translate It. It will download
94
94
  and update your file with the latest translations from Web Translate It.</p>
95
95
 
96
+ <p><code>wti diff</code> will display a diff between local and remote language files.</p>
97
+
96
98
  <p><code>wti status</code> fetch and display translation statistics from Web Translate It.</p>
97
99
 
98
100
  <h2 id="OPTIONS">OPTIONS</h2>
data/man/wti.1.ron CHANGED
@@ -9,6 +9,8 @@ wti(1) -- WebTranslateIt.com from the command line
9
9
 
10
10
  `wti pull` [`-l`] <OPTIONS>
11
11
 
12
+ `wti diff` <OPTIONS>
13
+
12
14
  ## DESCRIPTION
13
15
 
14
16
  `wti` is an utility to help you sync language files between the
@@ -20,6 +22,8 @@ update the strings hosted at Web Translate It by the strings from the file you p
20
22
  `wti pull` will pull the target language files from Web Translate It. It will download
21
23
  and update your file with the latest translations from Web Translate It.
22
24
 
25
+ `wti diff` will show a difference between your local file and the file hosted at Web Translate It.
26
+
23
27
  `wti status` fetch and display translation statistics from Web Translate It.
24
28
 
25
29
  ## OPTIONS
data/readme.md CHANGED
@@ -12,7 +12,7 @@ wti lets you easily sync your language files with [WebTranslateIt.com](https://w
12
12
 
13
13
  ### wti...
14
14
 
15
- * wti is a **command-line tool**. It works on all operating systems: Windows, Linux, MacOS X, ... It is also available as a [Docker package](https://github.com/webtranslateit/wti-docker/pkgs/container/wti-docker).
15
+ * wti is a **command-line tool**. It works on all operating systems: Windows, Linux, macOS, ... It is also available as a [Docker package](https://github.com/webtranslateit/wti-docker/pkgs/container/wti-docker).
16
16
  * wti is really easy to use. It was inspired by git. Use `wti push` and `wti pull` to sync your language files with WebTranslateIt.com.
17
17
 
18
18
  ### Optionally, wti does...
@@ -29,8 +29,8 @@ You will also need ruby to run `wti`. We require ruby version 3.0 or newer. On L
29
29
 
30
30
  ``` bash
31
31
  $ gem install web_translate_it
32
- Fetching: web_translate_it-3.0.2.gem (100%)
33
- Successfully installed web_translate_it-3.0.2
32
+ Fetching: web_translate_it-3.2.0.gem (100%)
33
+ Successfully installed web_translate_it-3.2.0
34
34
  1 gem installed
35
35
  ```
36
36
 
@@ -38,7 +38,7 @@ At this point you should have the `wti` executable working:
38
38
 
39
39
  ``` bash
40
40
  $ wti -v
41
- wti version 3.0.2
41
+ wti version 3.2.0
42
42
  ```
43
43
 
44
44
  We also provide `wti` as a Docker packages. [See our packages and instructions to install](https://github.com/webtranslateit/wti-docker/pkgs/container/wti-docker).
@@ -78,6 +78,7 @@ Execute `wti --help` to see the usage:
78
78
  pull Pull target language file(s)
79
79
  push Push master language file(s)
80
80
  match Display matching of local files with File Manager
81
+ diff Display a diff between local and remote files
81
82
  add Create and push a new master language file
82
83
  addlocale Add a new locale to the project
83
84
  server Start a synchronisation server
@@ -196,6 +197,10 @@ Append `--help` for each command for more information. For instance:
196
197
  <td>wti match</td>
197
198
  <td>Show matching between files on local computer and the ones in WebTranslateIt’s File Manager</td>
198
199
  </tr>
200
+ <tr>
201
+ <td>wti diff config/locales/app/en.yml</td>
202
+ <td>View diff between local and remote file config/locales/app/en.yml</td>
203
+ </tr>
199
204
  </table>
200
205
 
201
206
  ## Hooks
@@ -272,4 +277,4 @@ fr: 100% translated, 100% completed.
272
277
 
273
278
  # License
274
279
 
275
- Copyright (c) 2009-2024 [WebTranslateIt Software S.L](https://webtranslateit.com), released under the MIT License.
280
+ Copyright (c) 2009-2026 [WebTranslateIt Software S.L](https://webtranslateit.com), released under the MIT License.
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: web_translate_it
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.2
4
+ version: 3.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Edouard Briere
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-06-06 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: multi_json
@@ -61,6 +61,7 @@ files:
61
61
  - lib/web_translate_it/translation.rb
62
62
  - lib/web_translate_it/translation_file.rb
63
63
  - lib/web_translate_it/util.rb
64
+ - lib/web_translate_it/util/hash_extensions.rb
64
65
  - lib/web_translate_it/util/hash_util.rb
65
66
  - lib/web_translate_it/util/string_util.rb
66
67
  - license
@@ -95,7 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
95
96
  - !ruby/object:Gem::Version
96
97
  version: '0'
97
98
  requirements: []
98
- rubygems_version: 3.6.2
99
+ rubygems_version: 3.6.9
99
100
  specification_version: 4
100
101
  summary: A CLI tool to sync locale files with WebTranslateIt.com.
101
102
  test_files: []