i18n-tasks 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/i18n/tasks/scanners/erb_ast_scanner.rb +4 -2
- data/lib/i18n/tasks/scanners/occurrence_from_position.rb +3 -2
- data/lib/i18n/tasks/scanners/prism_scanners/nodes.rb +27 -6
- data/lib/i18n/tasks/scanners/prism_scanners/visitor.rb +18 -1
- data/lib/i18n/tasks/scanners/ruby_scanner.rb +3 -1
- data/lib/i18n/tasks/scanners/scanner_multiplexer.rb +2 -23
- data/lib/i18n/tasks/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f966f43b402a668486604f98fcc372895041974193afefbdc5d7dce44c150866
|
|
4
|
+
data.tar.gz: 504084ac31093ccca43a06ebdbc2707c7111b9cc07358a62ddc46ebc89128e54
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: eecedde9f44b2f81f404d3d84e0a9496d133157b571c330e863acaf250bfa0c36e4ebf4f396fe01f8cef47a8a5cb3599a2618b00d5e78bfcae7b9ef89cb5247a
|
|
7
|
+
data.tar.gz: f45bdd3498ca49a7989a1190d56aba6fc1c14c92d1e58e410d2a3ddbbdc47d8629984095aee970e9e3304f62e2888a36581f60a18035faf19c96c1c5f355d46e
|
data/README.md
CHANGED
|
@@ -24,7 +24,7 @@ i18n-tasks can be used with any project using the ruby [i18n gem][i18n-gem] (def
|
|
|
24
24
|
Add i18n-tasks to the Gemfile:
|
|
25
25
|
|
|
26
26
|
```ruby
|
|
27
|
-
gem 'i18n-tasks', '~> 1.1.
|
|
27
|
+
gem 'i18n-tasks', '~> 1.1.2', group: :development
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
Copy the default [configuration file](#configuration):
|
|
@@ -111,7 +111,8 @@ module I18n::Tasks::Scanners
|
|
|
111
111
|
path,
|
|
112
112
|
content,
|
|
113
113
|
start + occurrence.pos,
|
|
114
|
-
raw_key: occurrence.raw_key
|
|
114
|
+
raw_key: occurrence.raw_key,
|
|
115
|
+
candidate_keys: occurrence.candidate_keys
|
|
115
116
|
)
|
|
116
117
|
]
|
|
117
118
|
end
|
|
@@ -128,7 +129,8 @@ module I18n::Tasks::Scanners
|
|
|
128
129
|
path,
|
|
129
130
|
content,
|
|
130
131
|
start + (code.index(key) || occurrence.pos),
|
|
131
|
-
raw_key: occurrence.raw_key
|
|
132
|
+
raw_key: occurrence.raw_key,
|
|
133
|
+
candidate_keys: occurrence.candidate_keys
|
|
132
134
|
)
|
|
133
135
|
]
|
|
134
136
|
end
|
|
@@ -11,7 +11,7 @@ module I18n
|
|
|
11
11
|
# @param contents [String] contents of the file at the path.
|
|
12
12
|
# @param position [Integer] position just before the beginning of the match.
|
|
13
13
|
# @return [Results::Occurrence]
|
|
14
|
-
def occurrence_from_position(path, contents, position, raw_key: nil)
|
|
14
|
+
def occurrence_from_position(path, contents, position, raw_key: nil, candidate_keys: nil)
|
|
15
15
|
line_begin = contents.rindex(/^/, position - 1)
|
|
16
16
|
line_end = contents.index(/.(?=\r?\n|$)/, position)
|
|
17
17
|
Results::Occurrence.new(
|
|
@@ -20,7 +20,8 @@ module I18n
|
|
|
20
20
|
line_num: contents[0..position].count("\n") + 1,
|
|
21
21
|
line_pos: position - line_begin + 1,
|
|
22
22
|
line: contents[line_begin..line_end],
|
|
23
|
-
raw_key: raw_key
|
|
23
|
+
raw_key: raw_key,
|
|
24
|
+
candidate_keys: candidate_keys
|
|
24
25
|
)
|
|
25
26
|
end
|
|
26
27
|
end
|
|
@@ -41,6 +41,10 @@ module I18n::Tasks::Scanners::PrismScanners
|
|
|
41
41
|
rails_view? && !partial_view?
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
def support_candidate_keys?
|
|
45
|
+
false
|
|
46
|
+
end
|
|
47
|
+
|
|
44
48
|
def path
|
|
45
49
|
if rails_view?
|
|
46
50
|
folder_path = file_path.sub(%r{app/views/}, "").split("/")
|
|
@@ -66,12 +70,13 @@ module I18n::Tasks::Scanners::PrismScanners
|
|
|
66
70
|
class ScopeError < StandardError; end
|
|
67
71
|
attr_reader(:node, :key, :receiver, :options, :parent)
|
|
68
72
|
|
|
69
|
-
def initialize(node:, key:, receiver:, options:, parent:)
|
|
73
|
+
def initialize(node:, key:, receiver:, options:, parent:, candidate_keys: nil)
|
|
70
74
|
@node = node
|
|
71
75
|
@key = key
|
|
72
76
|
@receiver = receiver
|
|
73
77
|
@options = options
|
|
74
78
|
@parent = parent
|
|
79
|
+
@candidate_keys = candidate_keys || []
|
|
75
80
|
end
|
|
76
81
|
|
|
77
82
|
def relative_key?
|
|
@@ -110,7 +115,7 @@ module I18n::Tasks::Scanners::PrismScanners
|
|
|
110
115
|
|
|
111
116
|
base_parts = [scope].compact
|
|
112
117
|
|
|
113
|
-
if relative_key?
|
|
118
|
+
if relative_key? && support_candidate_keys?
|
|
114
119
|
# For relative keys in controllers/methods, generate candidate keys by
|
|
115
120
|
# progressively stripping trailing path segments from the parent path.
|
|
116
121
|
# Example: parent.path = ["events", "create"], key = ".success"
|
|
@@ -127,8 +132,15 @@ module I18n::Tasks::Scanners::PrismScanners
|
|
|
127
132
|
end
|
|
128
133
|
|
|
129
134
|
candidates.map { |c| c.gsub("..", ".") }
|
|
135
|
+
elsif relative_key?
|
|
136
|
+
# For relative keys in views, just append to the full path
|
|
137
|
+
[base_parts + parent.path + [key[1..]]].flatten.compact.join(".").gsub("..", ".") # rubocop:disable Performance/ChainArrayAllocation
|
|
130
138
|
elsif key.start_with?(".")
|
|
131
139
|
[base_parts + [key[1..]]].flatten.compact.join(".").gsub("..", ".") # rubocop:disable Performance/ArraySemiInfiniteRangeSlice,Performance/ChainArrayAllocation
|
|
140
|
+
elsif @candidate_keys.present?
|
|
141
|
+
([key] + @candidate_keys).map do |c|
|
|
142
|
+
[base_parts + [c]].flatten.compact.join(".").gsub("..", ".") # rubocop:disable Performance/ChainArrayAllocation
|
|
143
|
+
end
|
|
132
144
|
else
|
|
133
145
|
[base_parts + [key]].flatten.compact.join(".").gsub("..", ".") # rubocop:disable Performance/ChainArrayAllocation
|
|
134
146
|
end
|
|
@@ -159,16 +171,14 @@ module I18n::Tasks::Scanners::PrismScanners
|
|
|
159
171
|
pos: location.start_offset,
|
|
160
172
|
line_pos: location.start_column,
|
|
161
173
|
line_num: location.start_line,
|
|
162
|
-
raw_key: key
|
|
174
|
+
raw_key: key,
|
|
175
|
+
candidate_keys: Array(final)
|
|
163
176
|
)
|
|
164
177
|
|
|
165
178
|
# full_key may be a single String or an Array of candidate strings
|
|
166
179
|
if final.is_a?(Array)
|
|
167
|
-
# record candidate keys on the occurrence (first candidate is the primary)
|
|
168
|
-
occurrence.instance_variable_set(:@candidate_keys, final)
|
|
169
180
|
[final.first, occurrence]
|
|
170
181
|
else
|
|
171
|
-
occurrence.instance_variable_set(:@candidate_keys, [final])
|
|
172
182
|
[final, occurrence]
|
|
173
183
|
end
|
|
174
184
|
rescue ScopeError
|
|
@@ -180,6 +190,11 @@ module I18n::Tasks::Scanners::PrismScanners
|
|
|
180
190
|
def support_relative_keys?
|
|
181
191
|
(parent.is_a?(ParsedMethod) || parent.is_a?(Root)) && parent.support_relative_keys?
|
|
182
192
|
end
|
|
193
|
+
|
|
194
|
+
# Not supported for Rails views
|
|
195
|
+
def support_candidate_keys?
|
|
196
|
+
support_relative_keys? && parent.support_candidate_keys?
|
|
197
|
+
end
|
|
183
198
|
end
|
|
184
199
|
|
|
185
200
|
class ParsedModule < Root
|
|
@@ -292,6 +307,10 @@ module I18n::Tasks::Scanners::PrismScanners
|
|
|
292
307
|
controller? || mailer?
|
|
293
308
|
end
|
|
294
309
|
|
|
310
|
+
def support_candidate_keys?
|
|
311
|
+
controller?
|
|
312
|
+
end
|
|
313
|
+
|
|
295
314
|
def path
|
|
296
315
|
(@parent&.path || []) + [path_name]
|
|
297
316
|
end
|
|
@@ -323,6 +342,8 @@ module I18n::Tasks::Scanners::PrismScanners
|
|
|
323
342
|
!@private_method && @parent&.support_relative_keys?
|
|
324
343
|
end
|
|
325
344
|
|
|
345
|
+
delegate(:support_candidate_keys?, to: :parent)
|
|
346
|
+
|
|
326
347
|
def path
|
|
327
348
|
(@parent&.path || []) + [@node.name]
|
|
328
349
|
end
|
|
@@ -95,6 +95,8 @@ module I18n::Tasks::Scanners::PrismScanners
|
|
|
95
95
|
@current_class&.private_methods!
|
|
96
96
|
when :t, :t!, :translate, :translate!
|
|
97
97
|
args, kwargs = process_arguments(node)
|
|
98
|
+
# Do not process other receivers than I18n, e.g. Service.translate(:key)
|
|
99
|
+
return if node.receiver.present? && !i18n_receiver?(node.receiver)
|
|
98
100
|
parent.add_translation_call(
|
|
99
101
|
TranslationCall.new(
|
|
100
102
|
node: node,
|
|
@@ -160,6 +162,17 @@ module I18n::Tasks::Scanners::PrismScanners
|
|
|
160
162
|
end
|
|
161
163
|
end
|
|
162
164
|
|
|
165
|
+
def i18n_receiver?(receiver)
|
|
166
|
+
case receiver.type
|
|
167
|
+
when :constant_read_node
|
|
168
|
+
receiver.name == :I18n
|
|
169
|
+
when :constant_path_node
|
|
170
|
+
receiver.parent.nil? && receiver.child&.name == :I18n
|
|
171
|
+
else
|
|
172
|
+
false
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
163
176
|
# ---- Rails specific methods ----
|
|
164
177
|
# Returns true if the node was handled
|
|
165
178
|
def handle_rails_call_node(node, &)
|
|
@@ -268,7 +281,7 @@ module I18n::Tasks::Scanners::PrismScanners
|
|
|
268
281
|
# We need to check for `node.receiver` since node is the `human` call
|
|
269
282
|
model_name = if current_class.present? && rails_model_method_called_on_current_class?(node.receiver)
|
|
270
283
|
current_class.path.flatten.map!(&:underscore).join(".")
|
|
271
|
-
elsif node.receiver
|
|
284
|
+
elsif node.receiver&.receiver&.type == :constant_read_node
|
|
272
285
|
node.receiver&.receiver&.name&.to_s&.underscore
|
|
273
286
|
end
|
|
274
287
|
|
|
@@ -289,6 +302,9 @@ module I18n::Tasks::Scanners::PrismScanners
|
|
|
289
302
|
node: node,
|
|
290
303
|
receiver: nil,
|
|
291
304
|
key: [:activerecord, :models, model_name, count_key].join("."),
|
|
305
|
+
candidate_keys: [
|
|
306
|
+
[:activerecord, :models, model_name].join(".")
|
|
307
|
+
],
|
|
292
308
|
parent: parent,
|
|
293
309
|
options: kwargs
|
|
294
310
|
)
|
|
@@ -327,6 +343,7 @@ module I18n::Tasks::Scanners::PrismScanners
|
|
|
327
343
|
TranslationCall.new(
|
|
328
344
|
node: node,
|
|
329
345
|
key: key,
|
|
346
|
+
candidate_keys: Array([:attributes, array_args.first].join(".")),
|
|
330
347
|
receiver: nil,
|
|
331
348
|
parent: parent,
|
|
332
349
|
options: {}
|
|
@@ -9,6 +9,7 @@ require "i18n/tasks/scanners/ast_matchers/default_i18n_subject_matcher"
|
|
|
9
9
|
require "i18n/tasks/scanners/ast_matchers/message_receivers_matcher"
|
|
10
10
|
require "i18n/tasks/scanners/ast_matchers/rails_model_matcher"
|
|
11
11
|
require "i18n/tasks/scanners/prism_scanners/visitor"
|
|
12
|
+
require "prism"
|
|
12
13
|
|
|
13
14
|
module I18n::Tasks::Scanners
|
|
14
15
|
# Scan for I18n.translate calls using whitequark/parser primarily and Prism if configured.
|
|
@@ -167,7 +168,8 @@ module I18n::Tasks::Scanners
|
|
|
167
168
|
# Extract all occurrences of translate calls from the file at the given path.
|
|
168
169
|
# @return [Array<[key, Results::KeyOccurrence]>] each occurrence found in the file
|
|
169
170
|
def prism_parse_file(path)
|
|
170
|
-
|
|
171
|
+
# Need File.expand_path for JRuby
|
|
172
|
+
process_prism_results(path, Prism.parse_file(File.expand_path(path)))
|
|
171
173
|
end
|
|
172
174
|
|
|
173
175
|
# This method handles only parsing to be able to test it properly.
|
|
@@ -4,8 +4,6 @@ require "i18n/tasks/scanners/scanner"
|
|
|
4
4
|
|
|
5
5
|
module I18n::Tasks::Scanners
|
|
6
6
|
# Run multiple {Scanner Scanners} and merge their results.
|
|
7
|
-
# @note The scanners are run concurrently. A thread is spawned per each scanner.
|
|
8
|
-
# @since 0.9.0
|
|
9
7
|
class ScannerMultiplexer < Scanner
|
|
10
8
|
# @param scanners [Array<Scanner>]
|
|
11
9
|
def initialize(scanners:)
|
|
@@ -15,29 +13,10 @@ module I18n::Tasks::Scanners
|
|
|
15
13
|
|
|
16
14
|
# Collect the results of all the scanners. Occurrences of a key from multiple scanners are merged.
|
|
17
15
|
#
|
|
18
|
-
# @note The scanners are run concurrently. A thread is spawned per each scanner.
|
|
19
16
|
# @return (see Scanner#keys)
|
|
20
17
|
def keys
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
private
|
|
25
|
-
|
|
26
|
-
# @return [Array<Array<Results::KeyOccurrences>>]
|
|
27
|
-
def collect_results
|
|
28
|
-
return [@scanners[0].keys] if @scanners.length == 1
|
|
29
|
-
|
|
30
|
-
Array.new(@scanners.length).tap do |results|
|
|
31
|
-
results_mutex = Mutex.new
|
|
32
|
-
@scanners.map.with_index do |scanner, i|
|
|
33
|
-
Thread.start do
|
|
34
|
-
scanner_results = scanner.keys
|
|
35
|
-
results_mutex.synchronize do
|
|
36
|
-
results[i] = scanner_results
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end.each(&:join)
|
|
40
|
-
end
|
|
18
|
+
results = @scanners.map(&:keys)
|
|
19
|
+
Results::KeyOccurrences.merge_keys results.flatten(1)
|
|
41
20
|
end
|
|
42
21
|
end
|
|
43
22
|
end
|
data/lib/i18n/tasks/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: i18n-tasks
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- glebm
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-11-
|
|
11
|
+
date: 2025-11-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|