web_translate_it 3.2.1 → 3.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/bin/wti +8 -10
  3. data/history.md +35 -0
  4. data/lib/web_translate_it/api_resource.rb +137 -0
  5. data/lib/web_translate_it/auto_fetch.rb +1 -1
  6. data/lib/web_translate_it/commands/add.rb +58 -0
  7. data/lib/web_translate_it/commands/addlocale.rb +39 -0
  8. data/lib/web_translate_it/commands/base.rb +58 -0
  9. data/lib/web_translate_it/commands/diff.rb +71 -0
  10. data/lib/web_translate_it/commands/init.rb +112 -0
  11. data/lib/web_translate_it/commands/match.rb +30 -0
  12. data/lib/web_translate_it/commands/mv.rb +67 -0
  13. data/lib/web_translate_it/commands/pull.rb +62 -0
  14. data/lib/web_translate_it/commands/push.rb +50 -0
  15. data/lib/web_translate_it/commands/rm.rb +67 -0
  16. data/lib/web_translate_it/commands/rmlocale.rb +43 -0
  17. data/lib/web_translate_it/commands/status.rb +52 -0
  18. data/lib/web_translate_it/configuration.rb +31 -21
  19. data/lib/web_translate_it/connection.rb +30 -3
  20. data/lib/web_translate_it/project.rb +13 -72
  21. data/lib/web_translate_it/runner.rb +75 -0
  22. data/lib/web_translate_it/string.rb +26 -265
  23. data/lib/web_translate_it/term.rb +15 -255
  24. data/lib/web_translate_it/term_translation.rb +16 -69
  25. data/lib/web_translate_it/translation.rb +12 -50
  26. data/lib/web_translate_it/translation_base.rb +38 -0
  27. data/lib/web_translate_it/translation_file.rb +58 -109
  28. data/lib/web_translate_it/util/concurrency.rb +46 -0
  29. data/lib/web_translate_it/util/hash_util.rb +0 -2
  30. data/lib/web_translate_it/util/http_response.rb +66 -0
  31. data/lib/web_translate_it/util/prompt.rb +49 -0
  32. data/lib/web_translate_it/util/spinner.rb +51 -0
  33. data/lib/web_translate_it/util/string_util.rb +4 -10
  34. data/lib/web_translate_it/util.rb +0 -75
  35. data/lib/web_translate_it.rb +21 -3
  36. metadata +21 -4
  37. data/lib/web_translate_it/command_line.rb +0 -521
  38. data/lib/web_translate_it/util/hash_extensions.rb +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d9a027a46383d8932b3776d7c614592e3bb186bed328954f0a39bd2e168f2ba3
4
- data.tar.gz: 75bd8ab7c9129e6fb4f6c3c982fee30b1793a01ce2ba8219aa4e2480cb491246
3
+ metadata.gz: 660b650bae69f2f4a4282acb69b7abc72296b7e352660adaf3c1047a3bac04ce
4
+ data.tar.gz: acf8cc2ef71f6a897d400cd99793b86c33d28672b8aa6049b49d1f3b3a2f3c16
5
5
  SHA512:
6
- metadata.gz: 20ce007c03f2a00b5eb2c4ba019f37b814ad5184792a1d14a6231351402f0c5988d470a6f64e1b732a2409c74a8f9696b542b3b12aa7ab9c267f0f1c94c5f3ef
7
- data.tar.gz: 6aafb08ddff729b498093150eddafd55410f45a1f8d0239d7a11a5c1a2a06ccff802bd53996d442ef89da955ba38b290b25aad6e0f8bb7182e15527faec2d418
6
+ metadata.gz: dc29fee26eb5eb394705c81975adcf21f03dbe3ca7918d0e9a622a791ef0163ee9c7aa00f88d9c608eea462b5a75e8b9e4c7d530af276cfa3449ab7824ef53ec
7
+ data.tar.gz: 148e6238f00cb1cd2030a8a9f13c1b155ed82c26baac67f6933d86da68463998a8f91f144339f8d538512fe7eee0ec47cab15b23a2de8bdab27df48f77176b76
data/bin/wti CHANGED
@@ -28,7 +28,7 @@ show_commands = <<~COMMANDS
28
28
  COMMANDS
29
29
 
30
30
  SUB_COMMANDS = %w[pull push match diff add rm mv addlocale rmlocale status st init].freeze
31
- global_options = Optimist.options do
31
+ Optimist.options do
32
32
  stop_on SUB_COMMANDS
33
33
  banner show_commands
34
34
  version "wti version #{WebTranslateIt::Util.version}"
@@ -42,11 +42,12 @@ when 'pull'
42
42
  wti pull [filename] - Pull target language file(s)
43
43
  [options] are:
44
44
  BANNER
45
- opt :locale, 'ISO code of locale(s) to pull, space-separated', type: :string
46
- opt :all, 'Pull all files'
47
- opt :force, 'Force pull (bypass conditional requests to WTI)'
48
- opt :config, 'Path to a configuration file', short: '-c', default: '.wti'
49
- opt :debug, 'Display debug information'
45
+ opt :locale, 'ISO code of locale(s) to pull, space-separated', type: :string
46
+ opt :all, 'Pull all files'
47
+ opt :force, 'Force pull (bypass conditional requests to WTI)'
48
+ opt :threads, 'Number of threads for parallel downloads', type: :integer, default: 10
49
+ opt :config, 'Path to a configuration file', short: '-c', default: '.wti'
50
+ opt :debug, 'Display debug information'
50
51
  end
51
52
  when 'push'
52
53
  Optimist.options do
@@ -57,13 +58,11 @@ when 'push'
57
58
  opt :locale, 'ISO code of locale(s) to push, space-separated', type: :string
58
59
  opt :target, 'Upload all target files'
59
60
  opt :force, 'Force push (bypass conditional requests to WTI)'
60
- opt :low_priority, 'Deprecated: option to process this file with a low priority'
61
61
  opt :merge, 'Force WTI to merge this file'
62
62
  opt :ignore_missing, 'Force WTI to not obsolete missing strings'
63
63
  opt :minor, 'Minor Changes. When pushing a master file, prevents target translations to be flagged as `to_verify`.'
64
64
  opt :label, 'Apply a label to the changes', type: :string
65
65
  opt :config, 'Path to a configuration file', short: '-c', default: '.wti'
66
- opt :all, 'DEPRECATED -- See `wti push --target` instead'
67
66
  opt :debug, 'Display debug information'
68
67
  end
69
68
  when 'diff'
@@ -78,7 +77,6 @@ when 'diff'
78
77
  when 'add'
79
78
  Optimist.options do
80
79
  banner 'wti add filename - Create and push a new master language file'
81
- opt :low_priority, 'Deprecated: option to process this file with a low priority'
82
80
  opt :config, 'Path to a configuration file', short: '-c', default: '.wti'
83
81
  opt :debug, 'Display debug information'
84
82
  end
@@ -135,7 +133,7 @@ end
135
133
 
136
134
  begin
137
135
  WebTranslateIt::Connection.turn_debug_on if command_options.debug
138
- WebTranslateIt::CommandLine.new(command, command_options, global_options, ARGV, File.expand_path('.'))
136
+ WebTranslateIt::Runner.new(command, command_options, ARGV, File.expand_path('.'))
139
137
  rescue Interrupt
140
138
  puts StringUtil.failure("\nQuitting...")
141
139
  exit 1
data/history.md CHANGED
@@ -1,3 +1,38 @@
1
+ ## Version 3.2.3 / 2026-04-09
2
+
3
+ * Handle HTTP 429 (rate limit) errors: add `RateLimitError` class, retry with backoff respecting the `Retry-After` header, and fix garbled error messages when the response body is not JSON.
4
+ * Add `--threads N` option to `wti pull` to control the number of concurrent download threads. Defaults to 10. Use `--threads 1` for sequential pulls.
5
+ * Modernize code for Ruby 3.0+: use `match?` instead of `!~`, `start_with?`/`delete_prefix` instead of index slicing, array difference instead of `reject`, and remove redundant `|| nil` fallbacks.
6
+
7
+ ## Version 3.2.2 / 2026-03-03
8
+
9
+ * Replace O(n²) string concatenation loop in `StringUtil#backward_truncate` with `String#ljust`.
10
+ * Move `$stdout.sync = true` and parameter validation into `Base`. Add `Base#require_parameters!` helper, replacing 5 duplicate `validate_parameters!` methods. Drop `Metrics/MethodLength` `rubocop:todo` from Pull.
11
+ * Refactor all command classes for consistency: extract small private methods, use guard clauses, and drop all `rubocop:todo` annotations for `Metrics/AbcSize`, `Metrics/MethodLength`, `Metrics/CyclomaticComplexity`, and `Metrics/PerceivedComplexity` across Add, Addlocale, Diff, Init, Match, Mv, Rm, Rmlocale, and Status. Add `Configuration#target_files_for` to centralize `master_id` lookups.
12
+ * Ensure `Addlocale#call` and `Rmlocale#call` return `true` on success. Previously they returned `nil`, causing `Runner` to `exit 1` even after successful operations.
13
+ * Remove dead code: commented-out `ignore_files` method in `Configuration`, unused `last_modification` in `TranslationFile`, unused `titleize` in `StringUtil`.
14
+ * Replace `Object#in?` (ActiveSupport) with `Array#include?` in `fetch_translations`. #435
15
+ * `Configuration#initialize` now defaults to `Dir.pwd` instead of `Rails.root`, removing the hard Rails dependency. #435
16
+ * Add `Configuration#files_for` to centralize locale and path filtering. Replaces duplicated `find_all`/`sort` logic in Pull, Push, Diff, and Match commands. #436
17
+ * Split `Util` class into focused modules: `HttpResponse`, `Concurrency`, and `Prompt`. `Util` retains only `version`, `calculate_percentage`, and `can_display_colors?`. #434
18
+ * Extract `Configuration#load_project_data` to eliminate duplicated logic between `initialize` and `reload`. #433
19
+ * Refactor `Util.handle_response` to return response body consistently and let callers decide what to print. Extract `status_label` for display formatting. #423
20
+ * Remove `Hash#stringify_keys!` monkey-patch in favour of `Hash#transform_keys(&:to_s)`. #432
21
+ * Extract `Spinner` class from `Runner#throb`. Thread management, ANSI codes, and frame animation are now testable and reusable. #426
22
+ * Add `Connection#get`, `#post`, `#put`, `#delete` wrappers to eliminate repeated `Net::HTTP::*.new` / `Util.add_fields` / `http_connection.request` boilerplate across all API call sites. #424
23
+ * Simplify `fetch_locales` in `Pull` and `Push` commands. Extract `warn_unknown_locales` helper. Remove deprecated `--all` and `--low-priority` options from `push` and `add` commands. #422
24
+ * Extract `TranslationBase` base class from `Translation` and `TermTranslation` to share `initialize`, `save`, `to_json`, and API path logic. #425
25
+ * `Util.with_retries` now re-raises `Timeout::Error` after exhausting retries instead of returning `false`. Methods like `find_all`, `find`, `create`, and `update` now return consistent types. #411
26
+ * Standardize `to_hash`/`to_json` pattern across all model classes. Make `to_hash` private in `ApiResource`, `String`, and `Term`. Convert positional boolean to keyword argument. #410
27
+ * Extract threading logic into `Util.concurrent_batch`. Simplify `Pull#pull_files` and fix thread-safety bug with shared mutable state. Use `Thread#value` for error propagation. #409
28
+ * Separate display logic from business methods in `TranslationFile`. `fetch`, `upload`, `create`, and `delete` now return a `Result` struct instead of printing to stdout, enabling programmatic use without terminal side-effects. Remove broken `modified_remotely?` dead code. #407
29
+ * Refactor long parameter lists to use keyword arguments in `TranslationFile#upload` and `TranslationFile#initialize`. Extract `TranslationFile.from_api` factory method. Remove unused `_global_options` parameter from `Runner#initialize`. #405
30
+ * Replace fragile path splitting with `File.dirname` in `TranslationFile#fetch`. Add specs. #408
31
+ * Decompose `CommandLine` god class into 11 focused command classes under `Commands::` namespace, rename to `Runner`. #404
32
+ * Extract `ApiResource` base class from `String` and `Term` to remove duplicated CRUD logic. #403
33
+ * Fix generic `rescue` blocks to capture and re-raise `StandardError`. #406
34
+ * Extract `Util.with_retries` helper to deduplicate retry logic. #402
35
+
1
36
  ## Version 3.2.1 / 2026-03-02
2
37
 
3
38
  * Refactor `Connection` class to eliminate class variables. #254
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebTranslateIt
4
+
5
+ class ApiResource # rubocop:todo Metrics/ClassLength
6
+
7
+ attr_accessor :id, :created_at, :updated_at, :translations, :new_record, :connection
8
+
9
+ def initialize(params = {}, connection: nil)
10
+ params = params.transform_keys(&:to_s)
11
+ self.connection = connection
12
+ self.id = params['id']
13
+ self.created_at = params['created_at']
14
+ self.updated_at = params['updated_at']
15
+ self.translations = params['translations'] || []
16
+ self.new_record = true
17
+ assign_attributes(params)
18
+ end
19
+
20
+ def self.find_all(connection, params = {}) # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
21
+ params = params.transform_keys(&:to_s)
22
+ url = "/api/projects/#{connection.api_key}/#{resource_path}"
23
+ url += "?#{HashUtil.to_params(filter_params(params))}" unless params.empty?
24
+
25
+ Concurrency.with_retries do
26
+ records = []
27
+ loop do
28
+ response = connection.get(url)
29
+ return [] unless response.code.to_i < 400
30
+
31
+ JSON.parse(response.body).each do |record_response|
32
+ record = new(record_response, connection: connection)
33
+ record.new_record = false
34
+ records.push(record)
35
+ end
36
+ break unless response['Link']&.include?('rel="next"')
37
+
38
+ url = response['Link'].match(/<(.*)>; rel="next"/)[1]
39
+ end
40
+ records
41
+ end
42
+ end
43
+
44
+ def self.find(connection, id)
45
+ Concurrency.with_retries do
46
+ response = connection.get("/api/projects/#{connection.api_key}/#{resource_path}/#{id}")
47
+ return nil if response.code.to_i == 404
48
+
49
+ record = new(JSON.parse(response.body), connection: connection)
50
+ record.new_record = false
51
+ return record
52
+ end
53
+ end
54
+
55
+ def self.resource_path
56
+ raise NotImplementedError, "#{name} must implement self.resource_path"
57
+ end
58
+
59
+ def self.filter_params(params)
60
+ params
61
+ end
62
+
63
+ def save
64
+ new_record ? create : update
65
+ end
66
+
67
+ def delete
68
+ Concurrency.with_retries do
69
+ HttpResponse.handle_response(connection.delete("/api/projects/#{connection.api_key}/#{self.class.resource_path}/#{id}"))
70
+ end
71
+ end
72
+
73
+ def translation_for(locale) # rubocop:todo Metrics/AbcSize
74
+ translation = translations.detect { |t| t.locale == locale }
75
+ return translation if translation
76
+ return nil if new_record
77
+
78
+ Concurrency.with_retries do
79
+ response = HttpResponse.handle_response(connection.get("/api/projects/#{connection.api_key}/#{self.class.resource_path}/#{id}/locales/#{locale}/translations"))
80
+ json = JSON.parse(response)
81
+ return nil if json.empty?
82
+
83
+ parse_translation_response(json)
84
+ end
85
+ end
86
+
87
+ protected
88
+
89
+ def assign_attributes(_params)
90
+ # Override in subclasses to set resource-specific attributes
91
+ end
92
+
93
+ def parse_translation_response(_json)
94
+ raise NotImplementedError, "#{self.class.name} must implement parse_translation_response"
95
+ end
96
+
97
+ def assign_translation_parent_id(_translation)
98
+ raise NotImplementedError, "#{self.class.name} must implement assign_translation_parent_id"
99
+ end
100
+
101
+ def update
102
+ translations.each do |translation|
103
+ assign_translation_parent_id(translation)
104
+ translation.connection = connection
105
+ translation.save
106
+ end
107
+
108
+ Concurrency.with_retries do
109
+ HttpResponse.handle_response(connection.put("/api/projects/#{connection.api_key}/#{self.class.resource_path}/#{id}", body: to_json))
110
+ end
111
+ end
112
+
113
+ def create
114
+ Concurrency.with_retries do
115
+ raw = connection.post("/api/projects/#{connection.api_key}/#{self.class.resource_path}", body: to_json(with_translations: true))
116
+ response = JSON.parse(HttpResponse.handle_response(raw))
117
+ self.id = response['id']
118
+ self.new_record = false
119
+ return true
120
+ end
121
+ end
122
+
123
+ def to_json(*_args, with_translations: false)
124
+ hash = to_hash
125
+ hash['translations'] = translations.map(&:to_hash) if translations.any? && with_translations
126
+ MultiJson.dump(hash)
127
+ end
128
+
129
+ private
130
+
131
+ def to_hash
132
+ {'id' => id}
133
+ end
134
+
135
+ end
136
+
137
+ end
@@ -29,7 +29,7 @@ module WebTranslateIt
29
29
  end
30
30
 
31
31
  def valid_request?(env)
32
- env['PATH_INFO'] !~ /\.(js|css|jpeg|jpg|gif|png|woff)$/
32
+ !env['PATH_INFO'].match?(/\.(js|css|jpeg|jpg|gif|png|woff)$/)
33
33
  end
34
34
 
35
35
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebTranslateIt
4
+
5
+ module Commands
6
+
7
+ class Add < Base
8
+
9
+ def call
10
+ require_parameters!(
11
+ min: 1,
12
+ error: 'Error: You must provide the path to the master file to add.',
13
+ usage: 'wti add path/to/master_file_1 path/to/master_file_2 ...'
14
+ )
15
+ complete_success = true
16
+ with_connection do |conn|
17
+ complete_success = add_files(conn)
18
+ end
19
+ complete_success
20
+ end
21
+
22
+ private
23
+
24
+ def validate_parameters!
25
+ return unless parameters == []
26
+
27
+ puts StringUtil.failure('Error: You must provide the path to the master file to add.')
28
+ puts 'Usage: wti add path/to/master_file_1 path/to/master_file_2 ...'
29
+ exit
30
+ end
31
+
32
+ def add_files(conn)
33
+ to_add = new_master_files
34
+ if to_add.empty?
35
+ puts 'No new master file to add.'
36
+ return true
37
+ end
38
+ to_add.all? { |param| create_file(param, conn) }
39
+ end
40
+
41
+ def create_file(param, conn)
42
+ file = TranslationFile.new(nil, param.gsub(/ /, '\\ '), nil, configuration.api_key)
43
+ result = file.create(conn)
44
+ puts StringUtil.array_to_columns(result.output)
45
+ result.success
46
+ end
47
+
48
+ def new_master_files
49
+ existing = configuration.files_for(locale: configuration.source_locale)
50
+ .to_set { |file| File.expand_path(file.file_path) }
51
+ parameters.reject { |param| existing.include?(File.expand_path(param)) }
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebTranslateIt
4
+
5
+ module Commands
6
+
7
+ class Addlocale < Base
8
+
9
+ def call
10
+ require_parameters!(
11
+ min: 1,
12
+ error: 'Locale code missing.',
13
+ usage: 'wti addlocale fr es ...'
14
+ )
15
+ parameters.each do |param|
16
+ print StringUtil.success("Adding locale #{param.upcase}... ")
17
+ with_connection do |conn|
18
+ WebTranslateIt::Project.create_locale(conn, param)
19
+ end
20
+ puts 'Done.'
21
+ end
22
+ true
23
+ end
24
+
25
+ private
26
+
27
+ def validate_parameters!
28
+ return unless parameters == []
29
+
30
+ puts StringUtil.failure('Locale code missing.')
31
+ puts 'Usage: wti addlocale fr es ...'
32
+ exit 1
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebTranslateIt
4
+
5
+ module Commands
6
+
7
+ class Base
8
+
9
+ attr_accessor :configuration, :command_options, :parameters
10
+
11
+ def initialize(configuration, command_options, parameters)
12
+ self.configuration = configuration
13
+ self.command_options = command_options
14
+ self.parameters = parameters
15
+ $stdout.sync = true
16
+ end
17
+
18
+ def call
19
+ raise NotImplementedError, "#{self.class.name} must implement #call"
20
+ end
21
+
22
+ protected
23
+
24
+ def require_parameters!(error:, usage:, min: 0, max: nil)
25
+ return if parameters.size >= min && (max.nil? || parameters.size <= max)
26
+
27
+ puts StringUtil.failure(error)
28
+ puts "Usage: #{usage}"
29
+ exit 1
30
+ end
31
+
32
+ def with_connection(&block)
33
+ WebTranslateIt::Connection.new(configuration.api_key, &block)
34
+ end
35
+
36
+ def run_hook(hook_command, label)
37
+ return unless hook_command
38
+
39
+ output = `#{hook_command}`
40
+ if $CHILD_STATUS.success?
41
+ puts output
42
+ else
43
+ abort "Error: #{label} command exited with: #{output}"
44
+ end
45
+ end
46
+
47
+ def warn_unknown_locales(locales)
48
+ locales.each do |locale|
49
+ puts "Locale #{locale} doesn't exist -- `wti addlocale #{locale}` to add it." unless configuration.target_locales.include?(locale)
50
+ end
51
+ locales
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tempfile'
4
+
5
+ module WebTranslateIt
6
+
7
+ module Commands
8
+
9
+ class Diff < Base
10
+
11
+ def call
12
+ complete_success = true
13
+ with_connection do |conn|
14
+ complete_success = diff_all_files(conn)
15
+ end
16
+ complete_success
17
+ end
18
+
19
+ private
20
+
21
+ def diff_all_files(conn)
22
+ files = select_files
23
+ if files.empty?
24
+ puts "Couldn't find any local files registered on WebTranslateIt to diff."
25
+ return true
26
+ end
27
+ files.all? { |file| diff_file(file, conn) }
28
+ end
29
+
30
+ def select_files
31
+ if parameters.any?
32
+ configuration.files_for(paths: parameters)
33
+ else
34
+ configuration.files_for(locale: configuration.source_locale)
35
+ end
36
+ end
37
+
38
+ def diff_file(file, conn)
39
+ return local_missing(file) unless File.exist?(file.file_path)
40
+
41
+ remote_content = file.fetch_remote_content(conn)
42
+ return remote_missing(file) unless remote_content
43
+
44
+ run_diff(file, remote_content)
45
+ end
46
+
47
+ def local_missing(file)
48
+ puts StringUtil.failure("Can't diff #{file.file_path}. File doesn't exist locally.")
49
+ false
50
+ end
51
+
52
+ def remote_missing(file)
53
+ puts StringUtil.failure("Couldn't fetch remote file #{file.file_path}")
54
+ false
55
+ end
56
+
57
+ def run_diff(file, remote_content)
58
+ Tempfile.create('wti') do |temp_file|
59
+ temp_file.write(remote_content)
60
+ temp_file.close
61
+ puts "Diff for #{file.file_path}:"
62
+ system "diff #{temp_file.path} #{file.file_path}"
63
+ end
64
+ true
65
+ end
66
+
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebTranslateIt
4
+
5
+ module Commands
6
+
7
+ class Init < Base
8
+
9
+ def call
10
+ puts '# Initializing project'
11
+ api_key, path = read_parameters
12
+ ensure_directory_exists(path)
13
+ project_info = JSON.parse(WebTranslateIt::Project.fetch_info(api_key))['project']
14
+ write_configuration(path, api_key, project_info)
15
+ print_success(project_info)
16
+ true
17
+ end
18
+
19
+ private
20
+
21
+ def read_parameters
22
+ if parameters.any?
23
+ [parameters[0], '.wti']
24
+ else
25
+ [Prompt.ask(' Project API Key:'), Prompt.ask(' Path to configuration file:', '.wti')]
26
+ end
27
+ end
28
+
29
+ def print_success(project_info)
30
+ puts ''
31
+ puts " The project #{project_info['name']} was successfully initialized."
32
+ puts ''
33
+ print_setup_hints(project_info)
34
+ puts 'You can now use `wti` to push and pull your language files.'
35
+ puts 'Check `wti --help` for help.'
36
+ end
37
+
38
+ def ensure_directory_exists(path)
39
+ dir = File.dirname(path)
40
+ FileUtils.mkpath(dir) unless dir == '.'
41
+ end
42
+
43
+ def write_configuration(path, api_key, project_info)
44
+ if File.exist?(path) && !File.writable?(path)
45
+ puts StringUtil.failure("Error: `#{path}` file is not writable.")
46
+ exit 1
47
+ end
48
+ File.open(path, 'w') { |file| file << generate_configuration(api_key, project_info) }
49
+ end
50
+
51
+ def print_setup_hints(project_info) # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
52
+ if project_info['source_locale']['code'].nil? || project_info['target_locales'].size <= 1 || project_info['project_files'].none?
53
+ puts ''
54
+ puts ' There are a few more things to set up:'
55
+ puts ''
56
+ end
57
+ if project_info['source_locale']['code'].nil?
58
+ puts " *) You don't have a source locale setup."
59
+ puts ' Add the source locale with: `wti addlocale <locale_code>`'
60
+ puts ''
61
+ end
62
+ if project_info['target_locales'].size <= 1
63
+ puts " *) You don't have a target locale setup."
64
+ puts ' Add the first target locale with: `wti addlocale <locale_code>`'
65
+ puts ''
66
+ end
67
+ return unless project_info['project_files'].none?
68
+
69
+ puts " *) You don't have linguistic files setup."
70
+ puts ' Add a master file with: `wti add <path/to/file.xml>`'
71
+ puts ''
72
+ end
73
+
74
+ def generate_configuration(api_key, project_info)
75
+ <<~FILE
76
+ # Required - The Project API Token from WebTranslateIt.com
77
+ # More information: https://github.com/webtranslateit/webtranslateit/wiki#configuration-file
78
+
79
+ api_key: #{api_key}
80
+
81
+ # Optional - Locales not to sync with WebTranslateIt.
82
+ # Takes a string, a symbol, or an array of string or symbol.
83
+
84
+ # ignore_locales: [#{project_info['source_locale']['code']}]
85
+
86
+ # Optional - Locales to sync with WebTranslateIt.
87
+ # Takes a string, a symbol, or an array of string or symbol.
88
+
89
+ # needed_locales: #{project_info['target_locales'].map { |locale| locale['code'] }}
90
+
91
+ # Optional: files not to sync with WebTranslateIt.
92
+ # Takes an array of globs.
93
+
94
+ # ignore_files: ['somefile*.csv']
95
+
96
+ # Optional - Hooks
97
+ # Takes a string containing a command to run.
98
+
99
+ # before_pull: "echo 'some unix command'" # Command executed before pulling files
100
+ # after_pull: "touch tmp/restart.txt" # Command executed after pulling files
101
+
102
+ # before_push: "echo 'some unix command'" # Command executed before pushing files
103
+ # after_push: "touch tmp/restart.txt" # Command executed after pushing files
104
+
105
+ FILE
106
+ end
107
+
108
+ end
109
+
110
+ end
111
+
112
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module WebTranslateIt
4
+
5
+ module Commands
6
+
7
+ class Match < Base
8
+
9
+ def call
10
+ configuration.files_for(locale: configuration.source_locale).each do |master_file|
11
+ print_file_status(master_file)
12
+ configuration.target_files_for(master_file).each do |file|
13
+ print_file_status(file, prefix: '- ')
14
+ end
15
+ end
16
+ true
17
+ end
18
+
19
+ private
20
+
21
+ def print_file_status(file, prefix: '')
22
+ label = "#{prefix}#{file.file_path} (#{file.locale})"
23
+ puts File.exist?(file.file_path) ? "#{prefix}#{StringUtil.important(file.file_path)} (#{file.locale})" : StringUtil.failure(label)
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+
30
+ end