i18n-tasks 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cec4fddc37a4bbc56edf707c49e247e8418a8199
4
- data.tar.gz: 38edd490aaa36f481f2c0ae7868649c87ebad8ef
3
+ metadata.gz: d6e30b4e85fe299dbf8f89391c84f5dea2d242b2
4
+ data.tar.gz: 9f6d31de1c84187fbad5e929c36416857f66f6e5
5
5
  SHA512:
6
- metadata.gz: 2a727430cb2f8ca4ad602db64766da00f6eb9711be9a1425096c18dff6906c60b8af52defdecb67a54521ec7edd18bb7a7487d093aebabbebf5f3e8cc6a58dfc
7
- data.tar.gz: 2ec48ffcff555fbb597deed2270a0b0c5d2a859d29069751ff681429292c6652be5c57106a9a5ab22326bce32183cfb1ea36aaeaf70f20ea4303e74330a7fbcf
6
+ metadata.gz: a3602fac64546ce66b2b500c3f2e010f01458e1cbd0ff708cbd5e329cca144574a47003ccb8533441e033de579147fbd00c6cb84f90c509720228d2a5e407f53
7
+ data.tar.gz: b32c4925376a24e28cf1882d1e10168374e1c8770e3e7b43028c9820a11a2b2e59515b2b260fe4fdd03462789b0710528c779c7316155df214e11bfe75d1c8ee
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', '~> 0.9.7'
27
+ gem 'i18n-tasks', '~> 0.9.8'
28
28
  ```
29
29
 
30
30
  Copy the default [configuration file](#configuration):
@@ -122,6 +122,50 @@ Sort the keys, and move them to the respective files as defined by [`config.writ
122
122
  $ i18n-tasks normalize -p
123
123
  ```
124
124
 
125
+ ### Move / rename / merge keys
126
+
127
+ `i18n-tasks mv <pattern> <target>` is a versatile task to move or delete keys matching the given pattern.
128
+
129
+ All nodes (leafs or subtrees) matching [`<pattern>`](#key-pattern-syntax) are merged together and moved to `<target>`.
130
+
131
+ Rename a node (leaf or subtree):
132
+
133
+ ``` console
134
+ $ i18n-tasks mv user account
135
+ ```
136
+
137
+ Move a node:
138
+
139
+ ``` console
140
+ $ i18n-tasks mv user_alerts user.alerts
141
+ ```
142
+
143
+ Move the children one level up:
144
+
145
+ ``` console
146
+ $ i18n-tasks mv 'alerts.{:}' '\1'
147
+ ```
148
+
149
+ Merge-move multiple nodes:
150
+
151
+ ``` console
152
+ $ i18n-tasks mv '{user,profile}' account
153
+ ```
154
+
155
+ Merge (non-leaf) nodes into parent:
156
+
157
+ ``` console
158
+ $ i18n-tasks mv '{pages}.{a,b}' '\1'
159
+ ```
160
+
161
+ ### Delete keys
162
+
163
+ Delete the keys by using the `rm` task:
164
+
165
+ ```console
166
+ $ i18n-tasks rm 'user.{old_profile,old_title}' another_key
167
+ ```
168
+
125
169
  ### Compose tasks
126
170
 
127
171
  `i18n-tasks` also provides composable tasks for reading, writing and manipulating locale data. Examples below.
@@ -40,12 +40,15 @@ en:
40
40
  health: is everything OK?
41
41
  irb: start REPL session within i18n-tasks context
42
42
  missing: show missing translations
43
+ mv: rename/merge the keys in locale data that match the given pattern
43
44
  normalize: 'normalize translation data: sort and move to the right files'
44
45
  remove_unused: remove unused keys
46
+ rm: remove the keys in locale data that match the given pattern
45
47
  translate_missing: translate missing keys with Google Translate
46
48
  tree_convert: convert tree between formats
47
49
  tree_filter: filter tree by key pattern
48
50
  tree_merge: merge trees
51
+ tree_mv_key: rename/merge/remove the keys matching the given pattern
49
52
  tree_rename_key: rename tree node
50
53
  tree_set_value: set values of keys, optionally match a pattern
51
54
  tree_subtract: tree A minus the keys in tree B
@@ -38,12 +38,15 @@ ru:
38
38
  health: Всё ОК?
39
39
  irb: начать REPL сессию в контексте i18n-tasks
40
40
  missing: показать недостающие переводы
41
+ mv: переименовать / объединить ключи, которые соответствуют заданному шаблону
41
42
  normalize: нормализовать файлы переводов (сортировка и распределение)
42
43
  remove_unused: удалить неиспользуемые ключи
44
+ rm: удалить ключи, которые соответствуют заданному шаблону
43
45
  translate_missing: перевести недостающие переводы с Google Translate
44
46
  tree_convert: преобразовать дерево между форматами
45
47
  tree_filter: фильтровать дерево по ключу
46
48
  tree_merge: объединенить деревья
49
+ tree_mv_key: переименованить / объединить / удалить ключи соответствующие заданному шаблону
47
50
  tree_rename_key: переименовать узел дерева
48
51
  tree_set_value: заменить значения ключей
49
52
  tree_subtract: дерево A минус ключи в дереве B
@@ -19,6 +19,32 @@ module I18n::Tasks
19
19
  i18n.normalize_store! opt[:locales], opt[:pattern_router]
20
20
  end
21
21
 
22
+ cmd :mv,
23
+ pos: 'FROM_KEY_PATTERN TO_KEY_PATTERN',
24
+ desc: t('i18n_tasks.cmd.desc.mv')
25
+ def mv(opt = {})
26
+ fail CommandError, 'requires FROM_KEY_PATTERN and TO_KEY_PATTERN' if opt[:arguments].size < 2
27
+ from_pattern = opt[:arguments].shift
28
+ to_pattern = opt[:arguments].shift
29
+ forest = i18n.data_forest
30
+ results = forest.mv_key!(compile_key_pattern(from_pattern), to_pattern, root: false)
31
+ i18n.data.write forest
32
+ terminal_report.mv_results results
33
+ end
34
+
35
+ cmd :rm,
36
+ pos: 'KEY_PATTERN [KEY_PATTERN...]',
37
+ desc: t('i18n_tasks.cmd.desc.rm')
38
+ def rm(opt = {})
39
+ fail CommandError, 'requires KEY_PATTERN' if opt[:arguments].empty?
40
+ forest = i18n.data_forest
41
+ results = opt[:arguments].each_with_object({}) do |key_pattern, h|
42
+ h.merge! forest.mv_key!(compile_key_pattern(key_pattern), '', root: false)
43
+ end
44
+ i18n.data.write forest
45
+ terminal_report.mv_results results
46
+ end
47
+
22
48
  cmd :data,
23
49
  pos: '[locale ...]',
24
50
  desc: t('i18n_tasks.cmd.desc.data'),
@@ -4,6 +4,7 @@ module I18n::Tasks
4
4
  module Commands
5
5
  module Tree
6
6
  include Command::Collection
7
+ include I18n::Tasks::KeyPatternMatching
7
8
 
8
9
  cmd :tree_translate,
9
10
  pos: '[tree (or stdin)]',
@@ -47,6 +48,7 @@ module I18n::Tasks
47
48
  :data_format]
48
49
 
49
50
  def tree_rename_key(opt = {})
51
+ warn_deprecated 'Use tree-mv instead.'
50
52
  key = arg_or_pos! :key, opt
51
53
  name = arg_or_pos! :name, opt
52
54
  forest = forest_pos_or_stdin! opt
@@ -56,6 +58,19 @@ module I18n::Tasks
56
58
  print_forest forest, opt
57
59
  end
58
60
 
61
+ cmd :tree_mv,
62
+ pos: 'FROM_KEY_PATTERN TO_KEY_PATTERN [tree (or stdin)]',
63
+ desc: t('i18n_tasks.cmd.desc.tree_mv_key'),
64
+ args: [:data_format]
65
+ def tree_mv(opt = {})
66
+ fail CommandError, 'requires FROM_KEY_PATTERN and TO_KEY_PATTERN' if opt[:arguments].size < 2
67
+ from_pattern = opt[:arguments].shift
68
+ to_pattern = opt[:arguments].shift
69
+ forest = forest_pos_or_stdin!(opt)
70
+ forest.mv_key!(compile_key_pattern(from_pattern), to_pattern, root: false)
71
+ print_forest forest, opt
72
+ end
73
+
59
74
  cmd :tree_subtract,
60
75
  pos: '[[tree] [tree] ... (or stdin)]',
61
76
  desc: t('i18n_tasks.cmd.desc.tree_subtract'),
@@ -31,6 +31,7 @@ module I18n::Tasks
31
31
  # i18n-tasks-use t('i18n_tasks.cmd.args.desc.out_format')
32
32
  format_arg.call(:out_format, OUT_FORMATS)
33
33
 
34
+ # @return [I18n::Tasks::Data::Tree::Siblings]
34
35
  def forest_pos_or_stdin!(opt, format = opt[:format])
35
36
  parse_forest(pos_or_stdin!(opt), format)
36
37
  end
@@ -59,6 +60,7 @@ module I18n::Tasks
59
60
  end
60
61
  end
61
62
 
63
+ # @return [I18n::Tasks::Data::Tree::Siblings]
62
64
  def parse_forest(src, format)
63
65
  unless src
64
66
  fail CommandError, I18n.t('i18n_tasks.cmd.errors.pass_forest')
@@ -98,8 +98,7 @@ module I18n::Tasks::Data::Tree
98
98
  derive.append!(nodes)
99
99
  end
100
100
 
101
- def full_key(opts = {})
102
- root = opts.key?(:root) ? opts[:root] : true
101
+ def full_key(root: true)
103
102
  @full_key ||= {}
104
103
  @full_key[root] ||= "#{"#{parent.full_key(root: root)}." if parent? && (root || parent.parent?)}#{key}"
105
104
  end
@@ -44,6 +44,43 @@ module I18n::Tasks::Data::Tree
44
44
  self
45
45
  end
46
46
 
47
+ # @param from_pattern [Regexp]
48
+ # @param to_pattern [Regexp]
49
+ # @param root [Boolean]
50
+ # @return {old key => new key}
51
+ def mv_key!(from_pattern, to_pattern, root: false) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
52
+ moved_forest = Siblings.new
53
+ moved_nodes = []
54
+ old_key_to_new_key = {}
55
+ nodes do |node|
56
+ full_key = node.full_key(root: root)
57
+ if from_pattern =~ full_key
58
+ moved_nodes << node
59
+ if to_pattern.empty?
60
+ old_key_to_new_key[full_key] = nil
61
+ next
62
+ end
63
+ match = $~
64
+ new_key = to_pattern.gsub(/\\\d+/) { |m| match[m[1..-1].to_i] }
65
+ old_key_to_new_key[full_key] = new_key
66
+ moved_forest.merge!(Siblings.new.tap do |forest|
67
+ forest[[(node.root.try(:key) unless root), new_key].compact.join('.')] =
68
+ node.derive(key: split_key(new_key).last)
69
+ end)
70
+ end
71
+ end
72
+ # Adjust references
73
+ # TODO: support nested references better
74
+ nodes do |node|
75
+ next unless node.reference?
76
+ new_target = old_key_to_new_key[node.value.to_s]
77
+ node.value = new_target.to_sym if new_target
78
+ end
79
+ remove_nodes_and_emptied_ancestors! moved_nodes
80
+ merge! moved_forest
81
+ old_key_to_new_key
82
+ end
83
+
47
84
  def replace_node!(node, new_node)
48
85
  @list[@list.index(node)] = new_node
49
86
  key_to_node[new_node.key] = new_node
@@ -1,4 +1,6 @@
1
1
  # frozen_string_literal: true
2
+ require 'set'
3
+
2
4
  module I18n::Tasks
3
5
  module Data::Tree
4
6
  # Any Enumerable that yields nodes can mix in this module
@@ -51,10 +53,9 @@ module I18n::Tasks
51
53
  end
52
54
 
53
55
  # @option root include root in full key
54
- def keys(key_opts = {}, &visitor)
55
- key_opts[:root] = false unless key_opts.key?(:root)
56
- return to_enum(:keys, key_opts) unless visitor
57
- leaves { |node| visitor.yield(node.full_key(key_opts), node) }
56
+ def keys(root: false, &visitor)
57
+ return to_enum(:keys, root: root) unless visitor
58
+ leaves { |node| visitor.yield(node.full_key(root: root), node) }
58
59
  self
59
60
  end
60
61
 
@@ -112,24 +113,36 @@ module I18n::Tasks
112
113
  self
113
114
  end
114
115
 
115
- # @return Siblings
116
- def select_keys(opts = {}, &block)
117
- root = opts.key?(:root) ? opts[:root] : false
118
- ok = {}
116
+ # @return [Siblings]
117
+ def select_keys(root: false, &block)
118
+ matches = get_nodes_by_key_filter(root: root, &block)
119
+ select_nodes do |node|
120
+ matches.include?(node)
121
+ end
122
+ end
123
+
124
+ # @return [Siblings]
125
+ def select_keys!(root: false, &block)
126
+ matches = get_nodes_by_key_filter(root: root, &block)
127
+ select_nodes! do |node|
128
+ matches.include?(node)
129
+ end
130
+ end
131
+
132
+ # @return [Set<I18n::Tasks::Data::Tree::Node>]
133
+ def get_nodes_by_key_filter(root: false, &block)
134
+ matches = Set.new
119
135
  keys(root: root) do |full_key, node|
120
136
  if block.yield(full_key, node)
121
137
  node.walk_to_root do |p|
122
- break if ok[p]
123
- ok[p] = true
138
+ break unless matches.add?(p)
124
139
  end
125
140
  end
126
141
  end
127
- select_nodes do |node|
128
- ok[node]
129
- end
142
+ matches
130
143
  end
131
144
 
132
- # @return Siblings
145
+ # @return [Siblings]
133
146
  def intersect_keys(other_tree, key_opts = {}, &block)
134
147
  if block
135
148
  select_keys(key_opts) do |key, node|
@@ -80,6 +80,16 @@ module I18n
80
80
  print_info "#{cyan title} #{cyan text}"
81
81
  end
82
82
 
83
+ def mv_results(results)
84
+ results.each do |(from, to)|
85
+ if to
86
+ print_info "#{cyan from} #{bold(yellow('⮕'))} #{cyan to}"
87
+ else
88
+ print_info "#{red from}#{bold(red(' 🗑'))}"
89
+ end
90
+ end
91
+ end
92
+
83
93
  private
84
94
 
85
95
  def missing_key_info(leaf)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module I18n
3
3
  module Tasks
4
- VERSION = '0.9.7'
4
+ VERSION = '0.9.8'
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: i18n-tasks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
4
+ version: 0.9.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - glebm