i18n-tasks 0.6.3 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +3 -0
- data/Gemfile +2 -1
- data/README.md +80 -78
- data/bin/i18n-tasks +24 -30
- data/config/i18n-tasks.yml +87 -0
- data/config/locales/en.yml +95 -0
- data/i18n-tasks.gemspec +1 -0
- data/lib/i18n/tasks.rb +10 -0
- data/lib/i18n/tasks/base_task.rb +6 -2
- data/lib/i18n/tasks/command/collection.rb +18 -0
- data/lib/i18n/tasks/command/commander.rb +72 -0
- data/lib/i18n/tasks/command/commands/data.rb +73 -0
- data/lib/i18n/tasks/command/commands/eq_base.rb +20 -0
- data/lib/i18n/tasks/command/commands/health.rb +26 -0
- data/lib/i18n/tasks/command/commands/meta.rb +35 -0
- data/lib/i18n/tasks/command/commands/missing.rb +73 -0
- data/lib/i18n/tasks/command/commands/tree.rb +92 -0
- data/lib/i18n/tasks/command/commands/usages.rb +70 -0
- data/lib/i18n/tasks/command/commands/xlsx.rb +27 -0
- data/lib/i18n/tasks/command/dsl.rb +27 -0
- data/lib/i18n/tasks/command/dsl/cmd.rb +19 -0
- data/lib/i18n/tasks/command/dsl/cmd_opt.rb +19 -0
- data/lib/i18n/tasks/command/dsl/enum_opt.rb +26 -0
- data/lib/i18n/tasks/command/options/common.rb +48 -0
- data/lib/i18n/tasks/command/options/enum_opt.rb +44 -0
- data/lib/i18n/tasks/command/options/list_opt.rb +11 -0
- data/lib/i18n/tasks/command/options/locales.rb +47 -0
- data/lib/i18n/tasks/command/options/trees.rb +101 -0
- data/lib/i18n/tasks/command_error.rb +3 -0
- data/lib/i18n/tasks/commands.rb +22 -169
- data/lib/i18n/tasks/configuration.rb +1 -16
- data/lib/i18n/tasks/console_context.rb +1 -1
- data/lib/i18n/tasks/data.rb +13 -8
- data/lib/i18n/tasks/data/file_formats.rb +29 -18
- data/lib/i18n/tasks/data/file_system_base.rb +35 -4
- data/lib/i18n/tasks/data/router/conservative_router.rb +18 -11
- data/lib/i18n/tasks/data/tree/node.rb +5 -15
- data/lib/i18n/tasks/data/tree/nodes.rb +0 -3
- data/lib/i18n/tasks/data/tree/siblings.rb +32 -2
- data/lib/i18n/tasks/data/tree/traversal.rb +117 -96
- data/lib/i18n/tasks/google_translation.rb +25 -25
- data/lib/i18n/tasks/html_keys.rb +10 -0
- data/lib/i18n/tasks/key_pattern_matching.rb +1 -0
- data/lib/i18n/tasks/locale_list.rb +19 -0
- data/lib/i18n/tasks/missing_keys.rb +32 -33
- data/lib/i18n/tasks/plural_keys.rb +1 -1
- data/lib/i18n/tasks/reports/base.rb +4 -9
- data/lib/i18n/tasks/reports/spreadsheet.rb +5 -5
- data/lib/i18n/tasks/reports/terminal.rb +62 -38
- data/lib/i18n/tasks/scanners/base_scanner.rb +5 -4
- data/lib/i18n/tasks/slop_command.rb +27 -0
- data/lib/i18n/tasks/stats.rb +20 -0
- data/lib/i18n/tasks/string_interpolation.rb +14 -0
- data/lib/i18n/tasks/unused_keys.rb +0 -10
- data/lib/i18n/tasks/version.rb +1 -1
- data/spec/commands/data_commands_spec.rb +38 -0
- data/spec/commands/tree_commands_spec.rb +68 -0
- data/spec/fixtures/app/views/index.html.slim +1 -0
- data/spec/google_translate_spec.rb +5 -3
- data/spec/i18n_spec.rb +18 -0
- data/spec/i18n_tasks_spec.rb +8 -8
- data/spec/spec_helper.rb +3 -3
- data/spec/support/test_codebase.rb +4 -1
- data/spec/used_keys_spec.rb +7 -7
- data/templates/config/i18n-tasks.yml +2 -2
- metadata +48 -4
- data/lib/i18n/tasks/commands_base.rb +0 -107
- data/lib/i18n/tasks/fill_tasks.rb +0 -40
data/lib/i18n/tasks/commands.rb
CHANGED
@@ -1,176 +1,29 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
require 'i18n/tasks/
|
3
|
-
require 'i18n/tasks/
|
4
|
-
require 'i18n/tasks/
|
2
|
+
require 'i18n/tasks/command/dsl'
|
3
|
+
require 'i18n/tasks/command/collection'
|
4
|
+
require 'i18n/tasks/command/commands/health'
|
5
|
+
require 'i18n/tasks/command/commands/missing'
|
6
|
+
require 'i18n/tasks/command/commands/usages'
|
7
|
+
require 'i18n/tasks/command/commands/eq_base'
|
8
|
+
require 'i18n/tasks/command/commands/data'
|
9
|
+
require 'i18n/tasks/command/commands/tree'
|
10
|
+
require 'i18n/tasks/command/commands/meta'
|
11
|
+
require 'i18n/tasks/command/commands/xlsx'
|
12
|
+
require 'i18n/tasks/command/commander'
|
5
13
|
|
6
14
|
module I18n::Tasks
|
7
|
-
class Commands <
|
15
|
+
class Commands < Command::Commander
|
16
|
+
extend Command::DSL
|
17
|
+
include Command::Commands::Health
|
18
|
+
include Command::Commands::Missing
|
19
|
+
include Command::Commands::Usages
|
20
|
+
include Command::Commands::EqBase
|
21
|
+
include Command::Commands::Data
|
22
|
+
include Command::Commands::Tree
|
23
|
+
include Command::Commands::Meta
|
24
|
+
include Command::Commands::XLSX
|
25
|
+
|
8
26
|
include Term::ANSIColor
|
9
27
|
require 'highline/import'
|
10
|
-
|
11
|
-
on_locale_opt = { as: Array, delimiter: /[+:,]/, default: 'all', argument: true, optional: false }
|
12
|
-
OPT = {
|
13
|
-
locale: proc {
|
14
|
-
on '-l', :locales=,
|
15
|
-
'Filter by locale(s), comma-separated list (en,fr) or all (default), or pass arguments without -l',
|
16
|
-
on_locale_opt
|
17
|
-
},
|
18
|
-
format: proc {
|
19
|
-
on '-f', :format=,
|
20
|
-
"Output format: #{VALID_TREE_FORMATS * ', '}. Default: terminal-table.",
|
21
|
-
{default: 'terminal-table', argument: true, optional: false}
|
22
|
-
},
|
23
|
-
strict: proc {
|
24
|
-
on :s, :strict, %Q(Do not infer dynamic key usage such as `t("category.\#{category.name}")`)
|
25
|
-
}
|
26
|
-
}
|
27
|
-
desc 'show missing translations'
|
28
|
-
opts do
|
29
|
-
instance_exec &OPT[:locale]
|
30
|
-
instance_exec &OPT[:format]
|
31
|
-
on '-t', :types=, 'Filter by type (types: used, diff)', as: Array, delimiter: /[+:,]/
|
32
|
-
end
|
33
|
-
cmd :missing do |opt = {}|
|
34
|
-
parse_locales! opt
|
35
|
-
print_locale_tree i18n.missing_keys(opt), opt, :missing_keys
|
36
|
-
end
|
37
|
-
|
38
|
-
desc 'show unused translations'
|
39
|
-
opts do
|
40
|
-
instance_exec &OPT[:locale]
|
41
|
-
instance_exec &OPT[:format]
|
42
|
-
instance_exec &OPT[:strict]
|
43
|
-
end
|
44
|
-
cmd :unused do |opt = {}|
|
45
|
-
parse_locales! opt
|
46
|
-
print_locale_tree i18n.unused_keys(opt), opt, :unused_keys
|
47
|
-
end
|
48
|
-
|
49
|
-
desc 'show translations equal to base value'
|
50
|
-
opts do
|
51
|
-
instance_exec &OPT[:format]
|
52
|
-
end
|
53
|
-
cmd :eq_base do |opt = {}|
|
54
|
-
parse_locales! opt
|
55
|
-
print_locale_tree i18n.eq_base_keys(opt), opt, :eq_base_keys
|
56
|
-
end
|
57
|
-
|
58
|
-
desc 'show where the keys are used in the code'
|
59
|
-
opts do
|
60
|
-
on '-p', :pattern=, 'Show only keys matching pattern', argument: true, optional: false
|
61
|
-
instance_exec &OPT[:format]
|
62
|
-
end
|
63
|
-
cmd :find do |opt = {}|
|
64
|
-
opt[:filter] ||= opt.delete(:pattern) || opt[:arguments].try(:first)
|
65
|
-
print_locale_tree i18n.used_tree(key_filter: opt[:filter].presence, source_locations: true), opt, :used_keys
|
66
|
-
end
|
67
|
-
|
68
|
-
desc 'show locale data'
|
69
|
-
opts do
|
70
|
-
instance_exec &OPT[:locale]
|
71
|
-
instance_exec &OPT[:format]
|
72
|
-
end
|
73
|
-
cmd :data do |opt = {}|
|
74
|
-
parse_locales! opt
|
75
|
-
print_locale_tree i18n.data_forest(opt[:locales]), opt
|
76
|
-
end
|
77
|
-
|
78
|
-
desc 'translate missing keys with Google Translate'
|
79
|
-
opts do
|
80
|
-
on '-l', :locales=, 'Locales to translate (comma-separated, default: all)', on_locale_opt
|
81
|
-
on '-f', :from=, 'Locale to translate from (default: base)', default: 'base', argument: true, optional: false
|
82
|
-
end
|
83
|
-
cmd :translate_missing do |opt = {}|
|
84
|
-
opt[:from] = base_locale if opt[:from].blank? || opt[:from] == 'base'
|
85
|
-
parse_locales! opt
|
86
|
-
i18n.fill_missing_google_translate opt
|
87
|
-
end
|
88
|
-
|
89
|
-
desc 'add missing keys to the locales'
|
90
|
-
opts do
|
91
|
-
on '-l', :locales=, 'Locales to add keys into (comma-separated, default: all)', on_locale_opt
|
92
|
-
on '-p', :placeholder=, 'Value for empty keys (default: base value or key.humanize)', argument: true, optional: false
|
93
|
-
end
|
94
|
-
cmd :add_missing do |opt = {}|
|
95
|
-
parse_locales! opt
|
96
|
-
opt[:value] ||= opt.delete(:placeholder) || proc { |key, locale|
|
97
|
-
# default to base value or key.humanize
|
98
|
-
locale != base_locale && t(key, base_locale) || SplitKey.split_key(key).last.to_s.humanize
|
99
|
-
}
|
100
|
-
|
101
|
-
v = opt[:value]
|
102
|
-
if v.is_a?(String) && v.include?('%{base_value}')
|
103
|
-
opt[:value] = proc { |key, locale, node|
|
104
|
-
base_value = node.value || t(key, base_locale) || ''
|
105
|
-
v % {base_value: base_value}
|
106
|
-
}
|
107
|
-
end
|
108
|
-
|
109
|
-
i18n.fill_missing_value opt
|
110
|
-
end
|
111
|
-
|
112
|
-
desc 'normalize translation data: sort and move to the right files'
|
113
|
-
opts do
|
114
|
-
on '-l', :locales=, 'Locales to normalize (comma-separated, default: all)', on_locale_opt
|
115
|
-
on '-p', :pattern_router, 'Use pattern router, regardless of config.', argument: false, optional: true
|
116
|
-
end
|
117
|
-
cmd :normalize do |opt = {}|
|
118
|
-
parse_locales! opt
|
119
|
-
i18n.normalize_store! opt[:locales], opt[:pattern_router]
|
120
|
-
end
|
121
|
-
|
122
|
-
desc 'remove unused keys'
|
123
|
-
opts do
|
124
|
-
on '-l', :locales=, 'Locales to remove unused keys from (comma-separated, default: all)', on_locale_opt
|
125
|
-
instance_exec &OPT[:strict]
|
126
|
-
end
|
127
|
-
cmd :remove_unused do |opt = {}|
|
128
|
-
parse_locales! opt
|
129
|
-
unused_keys = i18n.unused_keys(opt)
|
130
|
-
if unused_keys.present?
|
131
|
-
terminal_report.unused_keys(unused_keys)
|
132
|
-
unless ENV['CONFIRM']
|
133
|
-
exit 1 unless agree(red "#{unused_keys.leaves.count} translations will be removed in #{bold opt[:locales] * ', '}#{red '.'} " + yellow('Continue? (yes/no)') + ' ')
|
134
|
-
end
|
135
|
-
i18n.remove_unused!(opt[:locales])
|
136
|
-
$stderr.puts "Removed #{unused_keys.leaves.count} keys"
|
137
|
-
else
|
138
|
-
$stderr.puts bold green 'No unused keys to remove'
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
desc 'display i18n-tasks configuration'
|
143
|
-
cmd :config do
|
144
|
-
cfg = i18n.config_for_inspect.to_yaml
|
145
|
-
cfg.sub! /\A---\n/, ''
|
146
|
-
cfg.gsub! /^([^\s-].+?:)/, Term::ANSIColor.cyan(Term::ANSIColor.bold('\1'))
|
147
|
-
puts cfg
|
148
|
-
end
|
149
|
-
|
150
|
-
desc 'save missing and unused translations to an Excel file'
|
151
|
-
opts do
|
152
|
-
on :path=, 'Destination path', default: 'tmp/i18n-report.xlsx'
|
153
|
-
end
|
154
|
-
cmd :xlsx_report do |opt = {}|
|
155
|
-
begin
|
156
|
-
require 'axlsx'
|
157
|
-
rescue LoadError
|
158
|
-
message = %Q(For spreadsheet report please add axlsx gem to Gemfile:\ngem 'axlsx', '~> 2.0')
|
159
|
-
log_stderr Term::ANSIColor.red Term::ANSIColor.bold message
|
160
|
-
exit 1
|
161
|
-
end
|
162
|
-
spreadsheet_report.save_report opt[:path]
|
163
|
-
end
|
164
|
-
|
165
|
-
desc 'REPL session within i18n-tasks context'
|
166
|
-
cmd :irb do
|
167
|
-
require 'i18n/tasks/console_context'
|
168
|
-
::I18n::Tasks::ConsoleContext.start
|
169
|
-
end
|
170
|
-
|
171
|
-
desc 'show path to the gem'
|
172
|
-
cmd :gem_path do
|
173
|
-
puts File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
174
|
-
end
|
175
28
|
end
|
176
29
|
end
|
@@ -62,22 +62,7 @@ module I18n::Tasks::Configuration
|
|
62
62
|
|
63
63
|
# @return [Array<String>] all available locales, base_locale is always first
|
64
64
|
def locales
|
65
|
-
@config_sections[:locales] ||=
|
66
|
-
locales = config[:locales]
|
67
|
-
locales ||= data.available_locales
|
68
|
-
locales = locales.map(&:to_s)
|
69
|
-
locales = if locales.include?(base_locale)
|
70
|
-
[base_locale] + (locales - [base_locale])
|
71
|
-
else
|
72
|
-
[base_locale] + locales
|
73
|
-
end
|
74
|
-
if config[:locales]
|
75
|
-
log_verbose "config.locales set to #{locales}"
|
76
|
-
else
|
77
|
-
log_verbose "config.locales inferred from data #{locales}"
|
78
|
-
end
|
79
|
-
locales
|
80
|
-
end
|
65
|
+
@config_sections[:locales] ||= data.locales
|
81
66
|
end
|
82
67
|
|
83
68
|
# @return [String] default i18n locale
|
@@ -37,7 +37,7 @@ module I18n::Tasks
|
|
37
37
|
#{yellow 'Data as trees'}
|
38
38
|
tree(locale)
|
39
39
|
missing_tree(locale, compared_to = base_locale)
|
40
|
-
used_tree(
|
40
|
+
used_tree(source_occurrences: false, key_filter: nil)
|
41
41
|
unused_tree(locale)
|
42
42
|
build_tree('es' => {'hello' => 'Hola'})
|
43
43
|
|
data/lib/i18n/tasks/data.rb
CHANGED
@@ -8,17 +8,22 @@ module I18n::Tasks
|
|
8
8
|
# @see I18n::Tasks::Data::FileSystem
|
9
9
|
def data
|
10
10
|
@data ||= begin
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
data_config = (config[:data] || {}).with_indifferent_access
|
12
|
+
data_config.merge!(base_locale: base_locale, locales: config[:locales])
|
13
|
+
adapter_class = data_config[:adapter].presence || data_config[:class].presence || :file_system
|
14
|
+
adapter_class = adapter_class.to_s
|
15
|
+
adapter_class = "I18n::Tasks::Data::#{adapter_class.camelize}" if adapter_class !~ /[A-Z]/
|
16
|
+
data_config.except!(:adapter, :class)
|
17
|
+
adapter_class.constantize.new data_config
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
21
|
+
def empty_forest
|
22
|
+
::I18n::Tasks::Data::Tree::Siblings.new
|
23
|
+
end
|
24
|
+
|
20
25
|
def data_forest(locales = self.locales)
|
21
|
-
locales.inject(
|
26
|
+
locales.inject(empty_forest) do |tree, locale|
|
22
27
|
tree.merge! data[locale]
|
23
28
|
end
|
24
29
|
end
|
@@ -51,7 +56,7 @@ module I18n::Tasks
|
|
51
56
|
|
52
57
|
# write to store, normalizing all data
|
53
58
|
def normalize_store!(from = nil, pattern_router = false)
|
54
|
-
from
|
59
|
+
from = self.locales unless from
|
55
60
|
router = pattern_router ? ::I18n::Tasks::Data::Router::PatternRouter.new(data, data.config) : data.router
|
56
61
|
data.with_router(router) do
|
57
62
|
Array(from).each do |target_locale|
|
@@ -9,36 +9,41 @@ module I18n
|
|
9
9
|
base.extend ClassMethods
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
self.class.adapter_for(path)
|
14
|
-
end
|
12
|
+
delegate :adapter_for_path, :adapter_by_name, :adapter_name, :adapter_names, to: :class
|
15
13
|
|
16
|
-
def
|
17
|
-
|
14
|
+
def adapter_dump(tree, format)
|
15
|
+
adapter_op :dump, format, tree, write_config(format)
|
18
16
|
end
|
19
17
|
|
20
|
-
def
|
21
|
-
|
18
|
+
def adapter_parse(tree, format)
|
19
|
+
adapter_op :parse, format, tree, read_config(format)
|
22
20
|
end
|
23
21
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
22
|
+
def adapter_op(op, format, tree, config)
|
23
|
+
adapter_by_name(format).send(op, tree, config)
|
24
|
+
rescue Exception => e
|
25
|
+
raise CommandError.new("#{format} #{op} error: #{e.message}")
|
28
26
|
end
|
29
27
|
|
30
28
|
protected
|
31
29
|
|
30
|
+
def write_config(format)
|
31
|
+
(config[format] || {})[:write]
|
32
|
+
end
|
33
|
+
|
34
|
+
def read_config(format)
|
35
|
+
(config[format] || {})[:read]
|
36
|
+
end
|
37
|
+
|
32
38
|
def load_file(path)
|
33
|
-
|
34
|
-
|
35
|
-
adapter.parse(::File.read(path), adapter_options)
|
39
|
+
adapter = adapter_for_path(path)
|
40
|
+
adapter.parse ::File.read(path), read_config(adapter_name(adapter))
|
36
41
|
end
|
37
42
|
|
38
43
|
def write_tree(path, tree)
|
39
44
|
::FileUtils.mkpath(File.dirname path)
|
40
45
|
::File.open(path, 'w') { |f|
|
41
|
-
f.write(adapter_dump(tree.to_hash,
|
46
|
+
f.write(adapter_dump(tree.to_hash, adapter_name(adapter_for_path(path))))
|
42
47
|
}
|
43
48
|
end
|
44
49
|
|
@@ -49,21 +54,27 @@ module I18n
|
|
49
54
|
(@fn_patterns ||= []) << [name, pattern, adapter]
|
50
55
|
end
|
51
56
|
|
52
|
-
def
|
57
|
+
def adapter_for_path(path)
|
53
58
|
@fn_patterns.detect { |(_name, pattern, _adapter)|
|
54
59
|
::File.fnmatch(pattern, path)
|
55
|
-
} or raise CommandError.new("Adapter not found for #{path}. Registered adapters: #{@fn_patterns.inspect}")
|
60
|
+
}.try(:last) or raise CommandError.new("Adapter not found for #{path}. Registered adapters: #{@fn_patterns.inspect}")
|
56
61
|
end
|
57
62
|
|
58
63
|
def adapter_names
|
59
64
|
@fn_patterns.map(&:first)
|
60
65
|
end
|
61
66
|
|
67
|
+
def adapter_name(adapter)
|
68
|
+
@fn_patterns.detect { |(adapter_name, _pattern, registered_adapter)|
|
69
|
+
registered_adapter == adapter
|
70
|
+
}.try(:first) or raise CommandError.new("Adapter #{adapter.inspect} is not registered. Registered adapters: #{@fn_patterns.inspect}")
|
71
|
+
end
|
72
|
+
|
62
73
|
def adapter_by_name(name)
|
63
74
|
name = name.to_s
|
64
75
|
@fn_patterns.detect { |(adapter_name, _pattern, _adapter)|
|
65
76
|
adapter_name.to_s == name
|
66
|
-
} or raise CommandError.new("Adapter with name #{name.inspect} not found. Registered adapters: #{@fn_patterns.inspect}")
|
77
|
+
}.try(:last) or raise CommandError.new("Adapter with name #{name.inspect} not found. Registered adapters: #{@fn_patterns.inspect}")
|
67
78
|
end
|
68
79
|
end
|
69
80
|
end
|
@@ -9,8 +9,10 @@ module I18n::Tasks
|
|
9
9
|
module Data
|
10
10
|
class FileSystemBase
|
11
11
|
include ::I18n::Tasks::Data::FileFormats
|
12
|
+
include ::I18n::Tasks::Logging
|
12
13
|
|
13
|
-
attr_reader :config, :base_locale
|
14
|
+
attr_reader :config, :base_locale, :locales
|
15
|
+
attr_accessor :locales
|
14
16
|
|
15
17
|
DEFAULTS = {
|
16
18
|
read: ['config/locales/%{locale}.yml'],
|
@@ -18,8 +20,15 @@ module I18n::Tasks
|
|
18
20
|
}.with_indifferent_access
|
19
21
|
|
20
22
|
def initialize(config = {})
|
23
|
+
self.config = config.except(:base_locale, :locales)
|
21
24
|
@base_locale = config[:base_locale]
|
22
|
-
|
25
|
+
locales = config[:locales].presence
|
26
|
+
@locales = LocaleList.normalize_locale_list(locales || available_locales, base_locale, true)
|
27
|
+
if locales.present?
|
28
|
+
log_verbose "data locales: #{@locales}"
|
29
|
+
else
|
30
|
+
log_verbose "data locales (inferred): #{@locales}"
|
31
|
+
end
|
23
32
|
end
|
24
33
|
|
25
34
|
# get locale tree
|
@@ -43,6 +52,28 @@ module I18n::Tasks
|
|
43
52
|
@available_locales = nil
|
44
53
|
end
|
45
54
|
|
55
|
+
def write(forest)
|
56
|
+
forest.each { |root| set(root.key, root) }
|
57
|
+
end
|
58
|
+
|
59
|
+
def merge!(forest)
|
60
|
+
forest.inject(Tree::Siblings.new) { |result, root|
|
61
|
+
locale = root.key
|
62
|
+
merged = get(locale).merge(root)
|
63
|
+
set locale, merged
|
64
|
+
result.merge! merged
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def remove_by_key!(forest)
|
69
|
+
forest.inject(Tree::Siblings.new) do |removed, root|
|
70
|
+
locale_data = get(root.key)
|
71
|
+
subtracted = locale_data.subtract_by_key(forest)
|
72
|
+
set root.key, subtracted
|
73
|
+
removed.merge! locale_data.subtract_by_key(subtracted)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
46
77
|
alias []= set
|
47
78
|
|
48
79
|
# @return self
|
@@ -56,7 +87,7 @@ module I18n::Tasks
|
|
56
87
|
def available_locales
|
57
88
|
@available_locales ||= begin
|
58
89
|
locales = Set.new
|
59
|
-
config[:read].map do |pattern|
|
90
|
+
Array(config[:read]).map do |pattern|
|
60
91
|
[pattern, Dir.glob(pattern % {locale: '*'})] if pattern.include?('%{locale}')
|
61
92
|
end.compact.each do |pattern, paths|
|
62
93
|
p = pattern.gsub('\\', '\\\\').gsub('/', '\/').gsub('.', '\.')
|
@@ -97,7 +128,7 @@ module I18n::Tasks
|
|
97
128
|
if name[0] != name[0].upcase
|
98
129
|
name = "I18n::Tasks::Data::Router::#{name.classify}"
|
99
130
|
end
|
100
|
-
name.constantize.new(self, @config.merge(base_locale: base_locale))
|
131
|
+
name.constantize.new(self, @config.merge(base_locale: base_locale, locales: locales))
|
101
132
|
end
|
102
133
|
end
|
103
134
|
attr_writer :router
|
@@ -6,8 +6,9 @@ module I18n::Tasks
|
|
6
6
|
# Keep the path, or infer from base locale
|
7
7
|
class ConservativeRouter < PatternRouter
|
8
8
|
def initialize(adapter, config)
|
9
|
-
@adapter
|
10
|
-
@base_locale
|
9
|
+
@adapter = adapter
|
10
|
+
@base_locale = config[:base_locale]
|
11
|
+
@locales = config[:locales]
|
11
12
|
super
|
12
13
|
end
|
13
14
|
|
@@ -15,18 +16,20 @@ module I18n::Tasks
|
|
15
16
|
return to_enum(:route, locale, forest) unless block
|
16
17
|
out = Hash.new { |hash, key| hash[key] = Set.new }
|
17
18
|
not_found = Set.new
|
18
|
-
forest.keys do |key,
|
19
|
-
|
20
|
-
|
21
|
-
# infer from base
|
19
|
+
forest.keys do |key, _node|
|
20
|
+
path = key_path(locale, key)
|
21
|
+
# infer from another locale
|
22
22
|
unless path
|
23
|
-
|
24
|
-
|
23
|
+
inferred_from = (locales - [locale]).detect { |loc|
|
24
|
+
path = key_path(loc, key)
|
25
|
+
}
|
26
|
+
path = LocalePathname.replace_locale(path, inferred_from, locale) if inferred_from
|
25
27
|
end
|
28
|
+
key_with_locale = "#{locale}.#{key}"
|
26
29
|
if path
|
27
|
-
out[path] <<
|
30
|
+
out[path] << key_with_locale
|
28
31
|
else
|
29
|
-
not_found <<
|
32
|
+
not_found << key_with_locale
|
30
33
|
end
|
31
34
|
end
|
32
35
|
|
@@ -49,7 +52,11 @@ module I18n::Tasks
|
|
49
52
|
adapter[base_locale]
|
50
53
|
end
|
51
54
|
|
52
|
-
|
55
|
+
def key_path(locale, key)
|
56
|
+
adapter[locale]["#{locale}.#{key}"].try(:data).try(:[], :path)
|
57
|
+
end
|
58
|
+
|
59
|
+
attr_reader :adapter, :base_locale, :locales
|
53
60
|
end
|
54
61
|
end
|
55
62
|
end
|