i18n-tasks 0.8.7 → 0.9.0.rc1
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/.travis.yml +6 -5
- data/CHANGES.md +3 -3
- data/Gemfile +1 -1
- data/README.md +4 -4
- data/bin/i18n-tasks +0 -1
- data/config/locales/en.yml +103 -102
- data/config/locales/ru.yml +1 -1
- data/i18n-tasks.gemspec +1 -2
- data/lib/i18n/tasks.rb +0 -1
- data/lib/i18n/tasks/base_task.rb +0 -1
- data/lib/i18n/tasks/cli.rb +1 -1
- data/lib/i18n/tasks/command/commander.rb +0 -1
- data/lib/i18n/tasks/command/commands/missing.rb +3 -15
- data/lib/i18n/tasks/command/commands/usages.rb +5 -6
- data/lib/i18n/tasks/command/option_parsers/locale.rb +1 -8
- data/lib/i18n/tasks/command_error.rb +5 -1
- data/lib/i18n/tasks/commands.rb +0 -1
- data/lib/i18n/tasks/configuration.rb +1 -9
- data/lib/i18n/tasks/console_context.rb +2 -2
- data/lib/i18n/tasks/data.rb +0 -1
- data/lib/i18n/tasks/data/adapter/json_adapter.rb +0 -1
- data/lib/i18n/tasks/data/adapter/yaml_adapter.rb +0 -1
- data/lib/i18n/tasks/data/file_formats.rb +0 -1
- data/lib/i18n/tasks/data/file_system.rb +0 -1
- data/lib/i18n/tasks/data/file_system_base.rb +0 -1
- data/lib/i18n/tasks/data/router/conservative_router.rb +0 -1
- data/lib/i18n/tasks/data/router/pattern_router.rb +0 -1
- data/lib/i18n/tasks/data/tree/node.rb +6 -7
- data/lib/i18n/tasks/data/tree/nodes.rb +0 -1
- data/lib/i18n/tasks/data/tree/siblings.rb +29 -10
- data/lib/i18n/tasks/data/tree/traversal.rb +0 -3
- data/lib/i18n/tasks/google_translation.rb +0 -1
- data/lib/i18n/tasks/ignore_keys.rb +0 -1
- data/lib/i18n/tasks/key_pattern_matching.rb +0 -1
- data/lib/i18n/tasks/logging.rb +0 -1
- data/lib/i18n/tasks/missing_keys.rb +0 -1
- data/lib/i18n/tasks/plural_keys.rb +0 -1
- data/lib/i18n/tasks/reports/base.rb +1 -2
- data/lib/i18n/tasks/reports/spreadsheet.rb +0 -1
- data/lib/i18n/tasks/reports/terminal.rb +41 -17
- data/lib/i18n/tasks/scanners/files/caching_file_finder.rb +32 -0
- data/lib/i18n/tasks/scanners/files/caching_file_finder_provider.rb +24 -0
- data/lib/i18n/tasks/scanners/files/caching_file_reader.rb +27 -0
- data/lib/i18n/tasks/scanners/files/file_finder.rb +61 -0
- data/lib/i18n/tasks/scanners/files/file_reader.rb +18 -0
- data/lib/i18n/tasks/scanners/key_occurrences.rb +35 -0
- data/lib/i18n/tasks/scanners/occurence.rb +50 -0
- data/lib/i18n/tasks/scanners/pattern_scanner.rb +97 -38
- data/lib/i18n/tasks/scanners/pattern_with_scope_scanner.rb +2 -3
- data/lib/i18n/tasks/scanners/relative_keys.rb +3 -4
- data/lib/i18n/tasks/scanners/scanner.rb +15 -0
- data/lib/i18n/tasks/scanners/scanner_multiplexer.rb +43 -0
- data/lib/i18n/tasks/unused_keys.rb +4 -5
- data/lib/i18n/tasks/used_keys.rb +76 -23
- data/lib/i18n/tasks/version.rb +1 -2
- data/spec/conservative_router_spec.rb +0 -1
- data/spec/file_system_data_spec.rb +0 -1
- data/spec/fixtures/app/controllers/events_controller.rb +1 -2
- data/spec/google_translate_spec.rb +0 -1
- data/spec/i18n_tasks_spec.rb +4 -15
- data/spec/key_pattern_matching_spec.rb +0 -1
- data/spec/locale_tree/siblings_spec.rb +0 -1
- data/spec/pattern_scanner_spec.rb +34 -36
- data/spec/plural_keys_spec.rb +0 -1
- data/spec/readme_spec.rb +0 -1
- data/spec/relative_keys_spec.rb +15 -10
- data/spec/scanners/files/caching_file_finder_provider_spec.rb +18 -0
- data/spec/scanners/files/caching_file_finder_spec.rb +39 -0
- data/spec/scanners/files/caching_file_reader_spec.rb +18 -0
- data/spec/scanners/files/file_finder_spec.rb +52 -0
- data/spec/scanners/files/file_reader_spec.rb +15 -0
- data/spec/scanners/scanner_multiplexer_spec.rb +26 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/support/capture_std.rb +0 -1
- data/spec/support/fixtures.rb +0 -1
- data/spec/support/i18n_tasks_output_matcher.rb +0 -1
- data/spec/support/key_pattern_matcher.rb +0 -1
- data/spec/support/keys_and_occurrences.rb +27 -0
- data/spec/support/test_codebase.rb +0 -1
- data/spec/support/trees.rb +1 -7
- data/spec/used_keys_spec.rb +15 -16
- data/templates/config/i18n-tasks.yml +9 -2
- metadata +29 -9
- data/lib/i18n/tasks/scanners/base_scanner.rb +0 -149
- data/spec/commands/missing_commands_spec.rb +0 -23
data/lib/i18n/tasks/commands.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
module I18n::Tasks::Configuration
|
3
2
|
# i18n-tasks config (defaults + config/i18n-tasks.yml)
|
4
3
|
# @return [Hash{String => String,Hash,Array}]
|
@@ -53,13 +52,6 @@ module I18n::Tasks::Configuration
|
|
53
52
|
end
|
54
53
|
end
|
55
54
|
|
56
|
-
def search_config
|
57
|
-
@config_sections[:search] ||= {
|
58
|
-
scanner: scanner.class.name,
|
59
|
-
config: scanner.config
|
60
|
-
}
|
61
|
-
end
|
62
|
-
|
63
55
|
# @return [Array<String>] all available locales, base_locale is always first
|
64
56
|
def locales
|
65
57
|
@config_sections[:locales] ||= data.locales
|
@@ -87,7 +79,7 @@ module I18n::Tasks::Configuration
|
|
87
79
|
internal_locale
|
88
80
|
locales
|
89
81
|
data_config
|
90
|
-
search_config
|
82
|
+
@config_sections[:search] ||= search_config
|
91
83
|
translation_config
|
92
84
|
IGNORE_TYPES.each do |ignore_type|
|
93
85
|
ignore_config ignore_type
|
@@ -36,8 +36,8 @@ module I18n::Tasks
|
|
36
36
|
green(bold "i18n-tasks IRB Quick Start guide") + "\n" + <<-TEXT
|
37
37
|
#{yellow 'Data as trees'}
|
38
38
|
tree(locale)
|
39
|
-
used_tree(
|
40
|
-
unused_tree(locale)
|
39
|
+
used_tree(key_filter: nil, strict: nil)
|
40
|
+
unused_tree(locale: base_locale, strict: nil)
|
41
41
|
build_tree('es' => {'hello' => 'Hola'})
|
42
42
|
|
43
43
|
#{yellow 'Traversal'}
|
data/lib/i18n/tasks/data.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
|
3
2
|
require 'i18n/tasks/data/tree/traversal'
|
4
3
|
require 'i18n/tasks/data/tree/siblings'
|
@@ -10,13 +9,13 @@ module I18n::Tasks::Data::Tree
|
|
10
9
|
attr_accessor :value
|
11
10
|
attr_reader :key, :children, :parent
|
12
11
|
|
13
|
-
def initialize(
|
14
|
-
@key =
|
12
|
+
def initialize(key:, value: nil, data: nil, parent: nil, children: nil)
|
13
|
+
@key = key
|
15
14
|
@key = @key.to_s.freeze if @key
|
16
|
-
@value =
|
17
|
-
@data =
|
18
|
-
@parent =
|
19
|
-
self.children = (
|
15
|
+
@value = value
|
16
|
+
@data = data
|
17
|
+
@parent = parent
|
18
|
+
self.children = (children if children)
|
20
19
|
end
|
21
20
|
|
22
21
|
def attributes
|
@@ -1,8 +1,8 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
1
|
require 'set'
|
4
2
|
require 'i18n/tasks/split_key'
|
5
3
|
require 'i18n/tasks/data/tree/nodes'
|
4
|
+
require 'i18n/tasks/data/tree/node'
|
5
|
+
|
6
6
|
module I18n::Tasks::Data::Tree
|
7
7
|
# Siblings represents a subtree sharing a common parent
|
8
8
|
# in case of an empty parent (nil) it represents a forest
|
@@ -44,7 +44,7 @@ module I18n::Tasks::Data::Tree
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def replace_node!(node, new_node)
|
47
|
-
@list[@list.index(node)]
|
47
|
+
@list[@list.index(node)] = new_node
|
48
48
|
key_to_node[new_node.key] = new_node
|
49
49
|
end
|
50
50
|
|
@@ -64,7 +64,7 @@ module I18n::Tasks::Data::Tree
|
|
64
64
|
def set(full_key, node)
|
65
65
|
raise 'value should be a I18n::Tasks::Data::Tree::Node' unless node.is_a?(Node)
|
66
66
|
key_part, rest = split_key(full_key, 2)
|
67
|
-
child
|
67
|
+
child = key_to_node[key_part]
|
68
68
|
|
69
69
|
if rest
|
70
70
|
unless child
|
@@ -202,11 +202,23 @@ module I18n::Tasks::Data::Tree
|
|
202
202
|
forest
|
203
203
|
end
|
204
204
|
|
205
|
+
# @param key_occurrences [I18n::Tasks::Scanners::KeyOccurrences]
|
206
|
+
# @return [Siblings]
|
207
|
+
def from_key_occurrences(key_occurrences)
|
208
|
+
build_forest do |forest|
|
209
|
+
key_occurrences.each do |key_occurrence|
|
210
|
+
forest[key_occurrence.key] = ::I18n::Tasks::Data::Tree::Node.new(
|
211
|
+
key: split_key(key_occurrence.key).last,
|
212
|
+
data: {occurrences: key_occurrence.occurrences})
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
205
217
|
def from_key_attr(key_attrs, opts = {}, &block)
|
206
218
|
build_forest(opts) { |forest|
|
207
219
|
key_attrs.each { |(full_key, attr)|
|
208
220
|
raise "Invalid key #{full_key.inspect}" if full_key.end_with?('.')
|
209
|
-
node = Node.new(attr.merge(key: split_key(full_key).last))
|
221
|
+
node = ::I18n::Tasks::Data::Tree::Node.new(attr.merge(key: split_key(full_key).last))
|
210
222
|
block.call(full_key, node) if block
|
211
223
|
forest[full_key] = node
|
212
224
|
}
|
@@ -216,7 +228,7 @@ module I18n::Tasks::Data::Tree
|
|
216
228
|
def from_key_names(keys, opts = {}, &block)
|
217
229
|
build_forest(opts) { |forest|
|
218
230
|
keys.each { |full_key|
|
219
|
-
node = Node.new(key: split_key(full_key).last)
|
231
|
+
node = ::I18n::Tasks::Data::Tree::Node.new(key: split_key(full_key).last)
|
220
232
|
block.call(full_key, node) if block
|
221
233
|
forest[full_key] = node
|
222
234
|
}
|
@@ -238,16 +250,23 @@ module I18n::Tasks::Data::Tree
|
|
238
250
|
def from_flat_pairs(pairs)
|
239
251
|
Siblings.new.tap do |siblings|
|
240
252
|
pairs.each { |full_key, value|
|
241
|
-
siblings[full_key] = Node.new(key: split_key(full_key).last, value: value)
|
253
|
+
siblings[full_key] = ::I18n::Tasks::Data::Tree::Node.new(key: split_key(full_key).last, value: value)
|
242
254
|
}
|
243
255
|
end
|
244
256
|
end
|
245
257
|
|
246
258
|
private
|
247
259
|
def parse_parent_opt!(opts)
|
248
|
-
|
249
|
-
|
250
|
-
|
260
|
+
if opts[:parent_key]
|
261
|
+
opts[:parent] = ::I18n::Tasks::Data::Tree::Node.new(key: opts[:parent_key])
|
262
|
+
end
|
263
|
+
if opts[:parent_attr]
|
264
|
+
opts[:parent] = ::I18n::Tasks::Data::Tree::Node.new(opts[:parent_attr])
|
265
|
+
end
|
266
|
+
if opts[:parent_locale]
|
267
|
+
opts[:parent] = ::I18n::Tasks::Data::Tree::Node.new(
|
268
|
+
key: opts[:parent_locale], data: {locale: opts[:parent_locale]})
|
269
|
+
end
|
251
270
|
end
|
252
271
|
end
|
253
272
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
module I18n::Tasks
|
3
2
|
module Data::Tree
|
4
3
|
# Any Enumerable that yields nodes can mix in this module
|
@@ -147,12 +146,10 @@ module I18n::Tasks
|
|
147
146
|
value_proc ||= proc { |node|
|
148
147
|
node_value = node.value
|
149
148
|
human_key = ActiveSupport::Inflector.humanize(node.key.to_s)
|
150
|
-
full_key = node.full_key
|
151
149
|
StringInterpolation.interpolate_soft(
|
152
150
|
val_pattern,
|
153
151
|
value: node_value,
|
154
152
|
human_key: human_key,
|
155
|
-
key: full_key,
|
156
153
|
value_or_human_key: node_value.presence || human_key
|
157
154
|
)
|
158
155
|
}
|
data/lib/i18n/tasks/logging.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
module I18n::Tasks::Reports
|
3
2
|
class Base
|
4
3
|
include I18n::Tasks::Logging
|
@@ -31,7 +30,7 @@ module I18n::Tasks::Reports
|
|
31
30
|
def used_title(used_tree)
|
32
31
|
leaves = used_tree.leaves.to_a
|
33
32
|
filter = used_tree.first.root.data[:key_filter]
|
34
|
-
used_n = leaves.map { |node| node.data[:
|
33
|
+
used_n = leaves.map { |node| node.data[:occurrences].size }.reduce(:+).to_i
|
35
34
|
"#{leaves.length} key#{'s' if leaves.size != 1}#{" matching '#{filter}'" if filter}#{" (#{used_n} usage#{'s' if used_n != 1})" if used_n > 0}"
|
36
35
|
end
|
37
36
|
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
require 'i18n/tasks/reports/base'
|
3
2
|
require 'terminal-table'
|
4
3
|
module I18n
|
@@ -29,7 +28,7 @@ module I18n
|
|
29
28
|
{missing_used: red(glyph), missing_diff: yellow(glyph)}[type]
|
30
29
|
end
|
31
30
|
|
32
|
-
def used_keys(used_tree = task.used_tree
|
31
|
+
def used_keys(used_tree = task.used_tree)
|
33
32
|
print_title used_title(used_tree)
|
34
33
|
keys_nodes = used_tree.keys.to_a
|
35
34
|
if keys_nodes.present?
|
@@ -66,11 +65,11 @@ module I18n
|
|
66
65
|
end
|
67
66
|
|
68
67
|
def forest_stats(forest, stats = task.forest_stats(forest))
|
69
|
-
text
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
68
|
+
text = if stats[:locale_count] == 1
|
69
|
+
I18n.t('i18n_tasks.data_stats.text_single_locale', stats)
|
70
|
+
else
|
71
|
+
I18n.t('i18n_tasks.data_stats.text', stats)
|
72
|
+
end
|
74
73
|
title = bold(I18n.t('i18n_tasks.data_stats.title', stats.slice(:locales)))
|
75
74
|
print_info "#{cyan title} #{cyan text}"
|
76
75
|
end
|
@@ -86,7 +85,7 @@ module I18n
|
|
86
85
|
end
|
87
86
|
|
88
87
|
def print_occurrences(node, full_key = node.full_key)
|
89
|
-
occurrences = node.data[:
|
88
|
+
occurrences = node.data[:occurrences]
|
90
89
|
puts "#{bold "#{full_key}"} #{green(occurrences.size.to_s) if occurrences.size > 1}"
|
91
90
|
occurrences.each do |occurrence|
|
92
91
|
puts " #{key_occurrence full_key, occurrence}"
|
@@ -132,21 +131,46 @@ module I18n
|
|
132
131
|
puts ::Terminal::Table.new(opts, &block)
|
133
132
|
end
|
134
133
|
|
135
|
-
def key_occurrence(full_key,
|
136
|
-
location = green "#{
|
137
|
-
source = highlight_key(full_key,
|
134
|
+
def key_occurrence(full_key, occurrence)
|
135
|
+
location = green "#{occurrence.path}:#{occurrence.line_num}"
|
136
|
+
source = highlight_key(full_key, occurrence.line, occurrence.line_pos..-1).strip
|
138
137
|
"#{location} #{source}"
|
139
138
|
end
|
140
139
|
|
140
|
+
def first_occurrence(leaf)
|
141
|
+
# @type [I18n::Tasks::Scanners::KeyOccurrences]
|
142
|
+
occurrences = leaf[:data][:occurrences]
|
143
|
+
# @type [I18n::Tasks::Scanners::Occurrence]
|
144
|
+
first = occurrences.first
|
145
|
+
[green("#{first.path}:#{first.line_num}"),
|
146
|
+
("(#{I18n.t 'i18n_tasks.common.n_more', count: occurrences.length - 1})" if occurrences.length > 1)
|
147
|
+
].compact.join(' ')
|
148
|
+
end
|
149
|
+
|
141
150
|
def highlight_key(full_key, line, range = (0..-1))
|
142
|
-
line.dup.tap { |s|
|
151
|
+
line.dup.tap { |s|
|
152
|
+
s[range] = s[range].sub(full_key) { |m|
|
153
|
+
highlight_string m
|
154
|
+
}
|
155
|
+
}
|
143
156
|
end
|
144
157
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
158
|
+
module HighlightUnderline
|
159
|
+
def highlight_string(s)
|
160
|
+
underline s
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
module HighlightOther
|
165
|
+
def highlight_string(s)
|
166
|
+
yellow s
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
if Gem.win_platform?
|
171
|
+
include HighlightOther
|
172
|
+
else
|
173
|
+
include HighlightUnderline
|
150
174
|
end
|
151
175
|
end
|
152
176
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'i18n/tasks/scanners/files/file_finder'
|
2
|
+
module I18n::Tasks::Scanners::Files
|
3
|
+
# Finds the files in the specified search paths with support for exclusion / inclusion patterns.
|
4
|
+
# Wraps a {FileFinder} and caches the results.
|
5
|
+
#
|
6
|
+
# @note This class is thread-safe. All methods are cached.
|
7
|
+
# @since 0.9.0
|
8
|
+
class CachingFileFinder < FileFinder
|
9
|
+
# @param (see FileFinder#initialize)
|
10
|
+
def initialize(**args)
|
11
|
+
super
|
12
|
+
@mutex = Mutex.new
|
13
|
+
@cached_paths = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
# Traverse the paths and yield the matching ones.
|
17
|
+
#
|
18
|
+
# @note This method is cached, it will only access the filesystem on the first invocation.
|
19
|
+
# @param (see FileFinder#traverse_files)
|
20
|
+
# @yieldparam (see FileFinder#traverse_files)
|
21
|
+
# @return (see FileFinder#traverse_files)
|
22
|
+
def traverse_files
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
# @note This method is cached, it will only access the filesystem on the first invocation.
|
27
|
+
# @return (see FileFinder#find_files)
|
28
|
+
def find_files
|
29
|
+
@cached_paths || @mutex.synchronize { @cached_paths ||= super }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'i18n/tasks/scanners/files/caching_file_finder'
|
2
|
+
|
3
|
+
module I18n::Tasks::Scanners::Files
|
4
|
+
# Finds the files and provides their contents.
|
5
|
+
#
|
6
|
+
# @note This class is thread-safe. All methods are cached.
|
7
|
+
# @since 0.9.0
|
8
|
+
class CachingFileFinderProvider
|
9
|
+
def initialize
|
10
|
+
@cache = {}
|
11
|
+
@mutex = Mutex.new
|
12
|
+
end
|
13
|
+
|
14
|
+
# Initialize a {CachingFileFinder} or get one from cache based on the constructor arguments.
|
15
|
+
#
|
16
|
+
# @param (see FileFinder#initialize)
|
17
|
+
# @return [CachingFileFinder]
|
18
|
+
def get(**file_finder_args)
|
19
|
+
@cache[file_finder_args] || @mutex.synchronize do
|
20
|
+
@cache[file_finder_args] ||= CachingFileFinder.new(**file_finder_args)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|