i18n-tasks 0.3.6 → 0.3.7
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/CHANGES.md +5 -0
- data/README.md +13 -8
- data/bin/i18n-tasks +13 -9
- data/i18n-tasks.gemspec +2 -7
- data/lib/i18n/tasks.rb +1 -12
- data/lib/i18n/tasks/base_task.rb +6 -9
- data/lib/i18n/tasks/commands.rb +14 -15
- data/lib/i18n/tasks/commands_base.rb +2 -2
- data/lib/i18n/tasks/configuration.rb +20 -7
- data/lib/i18n/tasks/data.rb +78 -0
- data/lib/i18n/tasks/data/file_formats.rb +41 -0
- data/lib/i18n/tasks/data/file_system.rb +2 -3
- data/lib/i18n/tasks/data/file_system_base.rb +90 -0
- data/lib/i18n/tasks/data/locale_tree.rb +85 -0
- data/lib/i18n/tasks/data/router.rb +47 -0
- data/lib/i18n/tasks/key.rb +3 -0
- data/lib/i18n/tasks/key_group.rb +1 -0
- data/lib/i18n/tasks/logging.rb +4 -0
- data/lib/i18n/tasks/missing_keys.rb +18 -14
- data/lib/i18n/tasks/reports/terminal.rb +1 -1
- data/lib/i18n/tasks/scanners/base_scanner.rb +38 -36
- data/lib/i18n/tasks/scanners/pattern_scanner.rb +2 -2
- data/lib/i18n/tasks/unused_keys.rb +11 -8
- data/lib/i18n/tasks/used_keys.rb +15 -6
- data/lib/i18n/tasks/version.rb +1 -1
- data/spec/file_system_data_spec.rb +2 -2
- data/spec/google_translate_spec.rb +1 -1
- data/spec/pattern_scanner_spec.rb +2 -2
- data/spec/relative_keys_spec.rb +3 -3
- data/spec/used_keys_spec.rb +4 -6
- metadata +39 -42
- data/lib/i18n/tasks/data/storage/file_storage.rb +0 -127
- data/lib/i18n/tasks/data_traversal.rb +0 -51
- data/lib/i18n/tasks/translation_data.rb +0 -60
@@ -1,127 +0,0 @@
|
|
1
|
-
require 'i18n/tasks/data_traversal'
|
2
|
-
require 'i18n/tasks/key_pattern_matching'
|
3
|
-
|
4
|
-
module I18n::Tasks
|
5
|
-
module Data
|
6
|
-
module Storage
|
7
|
-
module FileStorage
|
8
|
-
|
9
|
-
def self.included(base)
|
10
|
-
base.extend KlassMethods
|
11
|
-
end
|
12
|
-
|
13
|
-
include ::I18n::Tasks::DataTraversal
|
14
|
-
include ::I18n::Tasks::KeyPatternMatching
|
15
|
-
attr_reader :config
|
16
|
-
|
17
|
-
DEFAULTS = {
|
18
|
-
read: ['config/locales/%{locale}.yml'],
|
19
|
-
write: ['config/locales/%{locale}.yml']
|
20
|
-
}.with_indifferent_access
|
21
|
-
|
22
|
-
def initialize(config = {})
|
23
|
-
self.config = config
|
24
|
-
end
|
25
|
-
|
26
|
-
def config=(config)
|
27
|
-
opt = DEFAULTS.deep_merge((config || {}).with_indifferent_access)
|
28
|
-
@read = opt[:read]
|
29
|
-
@write = opt[:write].map { |x| x.is_a?(String) ? ['*', x] : x }.map { |x|
|
30
|
-
[compile_key_pattern(x[0]), x[1]]
|
31
|
-
}
|
32
|
-
@locale_data = {}
|
33
|
-
end
|
34
|
-
|
35
|
-
# get locale tree
|
36
|
-
def get(locale)
|
37
|
-
locale = locale.to_s
|
38
|
-
@locale_data[locale] ||= begin
|
39
|
-
@read.map do |path|
|
40
|
-
Dir.glob path % {locale: locale}
|
41
|
-
end.flatten.map do |locale_file|
|
42
|
-
load_file locale_file
|
43
|
-
end.inject({}) do |hash, locale_data|
|
44
|
-
hash.deep_merge! locale_data || {}
|
45
|
-
hash
|
46
|
-
end[locale.to_s] || {}
|
47
|
-
end.with_indifferent_access
|
48
|
-
end
|
49
|
-
|
50
|
-
alias [] get
|
51
|
-
|
52
|
-
# set locale tree
|
53
|
-
def set(locale, value_tree)
|
54
|
-
locale = locale.to_s
|
55
|
-
out = {}
|
56
|
-
traverse value_tree do |key, value|
|
57
|
-
route = @write.detect { |route| route[0] =~ key }
|
58
|
-
key_match = $~
|
59
|
-
path = route[1] % {locale: locale}
|
60
|
-
path.gsub!(/[\\]\d+/) { |m| key_match[m[1..-1].to_i] }
|
61
|
-
(out[path] ||= []) << [key, value]
|
62
|
-
end
|
63
|
-
out.each do |path, data|
|
64
|
-
tree = {locale => list_to_tree(data)}
|
65
|
-
write_tree(path, tree)
|
66
|
-
end
|
67
|
-
@locale_data[locale] = nil
|
68
|
-
end
|
69
|
-
|
70
|
-
alias []= set
|
71
|
-
|
72
|
-
def reload
|
73
|
-
@locale_data = {}
|
74
|
-
@available_locales = nil
|
75
|
-
self
|
76
|
-
end
|
77
|
-
|
78
|
-
# Get available locales from the list of file names to read
|
79
|
-
def available_locales
|
80
|
-
@available_locales ||= begin
|
81
|
-
locales = Set.new
|
82
|
-
@read.map do |pattern|
|
83
|
-
[pattern, Dir.glob(pattern % {locale: '*'})] if pattern.include?('%{locale}')
|
84
|
-
end.compact.each do |pattern, paths|
|
85
|
-
p = pattern.gsub('\\', '\\\\').gsub('/', '\/').gsub('.', '\.')
|
86
|
-
p = p.gsub(/(\*+)/) { $1 == '**' ? '.*' : '[^/]*?' }.gsub('%{locale}', '([^/.]+)')
|
87
|
-
re = /\A#{p}\z/
|
88
|
-
paths.each do |path|
|
89
|
-
if re =~ path
|
90
|
-
locales << $1
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
locales
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
protected
|
99
|
-
|
100
|
-
def load_file(file)
|
101
|
-
adapter_for(file).parse ::File.read(file)
|
102
|
-
end
|
103
|
-
|
104
|
-
def write_tree(path, tree)
|
105
|
-
::File.open(path, 'w') { |f| f.write(adapter_for(path).dump(tree)) }
|
106
|
-
end
|
107
|
-
|
108
|
-
def adapter_for(file)
|
109
|
-
self.class.adapter_for(file)
|
110
|
-
end
|
111
|
-
|
112
|
-
module KlassMethods
|
113
|
-
# @param pattern [String] File.fnmatch pattern
|
114
|
-
# @param adapter [responds to parse(string)->hash and dump(hash)->string]
|
115
|
-
def register_adapter(pattern, adapter)
|
116
|
-
(@fn_patterns ||= {})[pattern] = adapter
|
117
|
-
end
|
118
|
-
|
119
|
-
def adapter_for(path)
|
120
|
-
@fn_patterns.detect { |pattern, adapter| ::File.fnmatch(pattern, path) }[1] or
|
121
|
-
raise "Adapter not found for #{path}. Registered adapters: #{@fn_patterns.inspect}"
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
module I18n::Tasks::DataTraversal
|
2
|
-
# translation of the key found in the passed hash or nil
|
3
|
-
# @return [String,nil]
|
4
|
-
def t(key, locale = base_locale)
|
5
|
-
key.to_s.split('.').inject(self.data[locale]) { |r, seg| r[seg] if r }
|
6
|
-
end
|
7
|
-
|
8
|
-
def t_proc(locale = base_locale)
|
9
|
-
proc { |k| t(k, locale) }
|
10
|
-
end
|
11
|
-
|
12
|
-
# traverse => map if yield(k, v)
|
13
|
-
def traverse_map_if(hash)
|
14
|
-
list = []
|
15
|
-
traverse hash do |k, v|
|
16
|
-
mapped = yield(k, v)
|
17
|
-
list << mapped if mapped
|
18
|
-
end
|
19
|
-
list
|
20
|
-
end
|
21
|
-
|
22
|
-
# traverse hash, yielding with full key and value
|
23
|
-
# @param hash [Hash{String => String,Hash}] translation data to traverse
|
24
|
-
# @yield [full_key, value] yields full key and value for every translation in #hash
|
25
|
-
# @return [nil]
|
26
|
-
def traverse(path = '', hash)
|
27
|
-
q = [[path, hash]]
|
28
|
-
until q.empty?
|
29
|
-
path, value = q.pop
|
30
|
-
if value.is_a?(Hash)
|
31
|
-
value.each { |k, v| q << ["#{path}.#{k}", v] }
|
32
|
-
else
|
33
|
-
yield path[1..-1], value
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# [[key, value], ...] list to tree
|
39
|
-
def list_to_tree(list)
|
40
|
-
list = list.sort
|
41
|
-
tree = {}
|
42
|
-
list.each do |key, value|
|
43
|
-
key_segments = key.to_s.split('.')
|
44
|
-
node = key_segments[0..-2].inject(tree) do |r, segment|
|
45
|
-
r[segment] ||= {}
|
46
|
-
end
|
47
|
-
node[key_segments.last] = value
|
48
|
-
end
|
49
|
-
tree
|
50
|
-
end
|
51
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'i18n/tasks/data/file_system'
|
2
|
-
|
3
|
-
module I18n::Tasks::TranslationData
|
4
|
-
|
5
|
-
# I18n data provider
|
6
|
-
# @see I18n::Tasks::Data::Yaml
|
7
|
-
def data
|
8
|
-
@data ||= data_config[:adapter].constantize.new(data_config[:options])
|
9
|
-
end
|
10
|
-
|
11
|
-
# whether the value for key exists in locale (defaults: base_locale)
|
12
|
-
def key_value?(key, locale = base_locale)
|
13
|
-
t(key, locale).present?
|
14
|
-
end
|
15
|
-
|
16
|
-
def non_base_locales(from = nil)
|
17
|
-
from = self.locales unless from
|
18
|
-
Array(from) - [base_locale]
|
19
|
-
end
|
20
|
-
|
21
|
-
# write to store, normalizing all data
|
22
|
-
def normalize_store!(from = nil)
|
23
|
-
from = self.locales unless from
|
24
|
-
Array(from).each do |target_locale|
|
25
|
-
# the store itself handles normalization
|
26
|
-
data[target_locale] = data[target_locale]
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
# @param locales
|
31
|
-
# @param locale
|
32
|
-
# @param keys
|
33
|
-
# @param value
|
34
|
-
# @param values
|
35
|
-
def update_data(opts = {})
|
36
|
-
if opts.key?(:locales)
|
37
|
-
locales = (Array(opts[:locales]).presence || self.locales).map(&:to_s)
|
38
|
-
# make sure base_locale always comes first if present
|
39
|
-
locales = [base_locale] + (locales - [base_locale]) if locales.include?(base_locale)
|
40
|
-
opts = opts.except(:locales)
|
41
|
-
locales.each { |locale| update_data(opts.merge(locale: locale)) }
|
42
|
-
return
|
43
|
-
end
|
44
|
-
locale = opts[:locale] || base_locale
|
45
|
-
keys = opts[:keys]
|
46
|
-
keys = keys.call(locale) if keys.respond_to?(:call)
|
47
|
-
return if keys.empty?
|
48
|
-
values = opts[:values]
|
49
|
-
values = values.call(keys, locale) if values.respond_to?(:call)
|
50
|
-
unless values
|
51
|
-
value = opts[:value]
|
52
|
-
values = if value.respond_to?(:call)
|
53
|
-
keys.map { |key| value.call(key, locale) }
|
54
|
-
else
|
55
|
-
[value] * keys.size
|
56
|
-
end
|
57
|
-
end
|
58
|
-
data[locale] = data[locale].deep_merge(list_to_tree keys.map(&:to_s).zip(values))
|
59
|
-
end
|
60
|
-
end
|