i18n-migrations 1.2.4 → 2.0.0

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
  SHA256:
3
- metadata.gz: 0b8b7ac35780cf4cf39728ec9c140324a1df5b21868fbeff0d8082eb2b612e1e
4
- data.tar.gz: c8c7f5867dc9d8485d527d0b9286a3925eaa69eea40e82ae5ee0a6ca2240f89e
3
+ metadata.gz: 155eb3f6fe33497d8988ba301c6535df404f0d02c59cfaac034a77a169508d62
4
+ data.tar.gz: 04a5b6dcc152e3ad7b7b88bc898acae8fc2fed122947a3ae1609edcdb6023e64
5
5
  SHA512:
6
- metadata.gz: 3ebecbc35805df21ae0db20ac14931517fb6e55126a3a3b853d1486ab59264f38ea58e66077f665ed226b66afb828544866dae8810fd6c6c93c5ce52f9367d89
7
- data.tar.gz: 5a449c05dd1f4d2a2a5492cf0e0ff6fb016344fc1db735e51eaeff4bc9466f62cfb1979c381ad8d35fa503e58d8964fbe044438e9ec1ac51a09fb1483d4356bc
6
+ metadata.gz: 324c96c71807c3fb331a25742f84d82242a0c3ea0bd12f0df7cebe9a6bdd5e0261d7830cfd843e0debe50475a948347603a6a23d93efd2d610b054d251ecc782
7
+ data.tar.gz: cb47a3ffd0fc1eae8a5b1b2e6996857c1b092f705112252818c9cb3d939246bc5711fa1357ef20e32c4243091fd59793544a7cd52c0cd295d9aca5a859585d58
@@ -30,17 +30,17 @@ module I18n
30
30
 
31
31
  # this will replace everything about a locale, it will create a locale that does not yet exist
32
32
  def force_push(locale)
33
- data, notes = locale.read_data_and_notes(parse: false)
33
+ data, metadata = locale.read_data_and_metadata(parse: false)
34
34
  client.put_locale(locale.name,
35
35
  name: locale.name,
36
36
  yaml_file: data,
37
- yaml_notes_file: notes)
37
+ yaml_metadata_file: metadata)
38
38
 
39
39
  end
40
40
 
41
41
  def pull_from_crowd_translate(locale)
42
42
  data = client.get_locale_file(locale.name)
43
- locale.write_raw_data("#{locale.name}.yml", data)
43
+ locale.data_file.write(data)
44
44
  locale.write_remote_version(YAML::load(data)[locale.name])
45
45
  end
46
46
 
@@ -28,9 +28,9 @@ module I18n
28
28
  put("migrations/#{version}.json", migration: { ruby_file: ruby_file })
29
29
  end
30
30
 
31
- def put_locale(locale_code, name:, yaml_file:, yaml_notes_file:)
31
+ def put_locale(locale_code, name:, yaml_file:, yaml_metadata_file:)
32
32
  put("locales/#{locale_code}",
33
- locale: { name: name, yaml_file: yaml_file, yaml_notes_file: yaml_notes_file })
33
+ locale: { name: name, yaml_file: yaml_file, yaml_metadata_file: yaml_metadata_file })
34
34
  end
35
35
 
36
36
  private
@@ -1,4 +1,5 @@
1
1
  require_relative './google_spreadsheet'
2
+ require_relative '../metadata'
2
3
 
3
4
  module I18n
4
5
  module Migrations
@@ -36,7 +37,7 @@ module I18n
36
37
  def pull_from_sheet(sheet, locale)
37
38
  puts "Pulling #{locale.name}"
38
39
  data = {}
39
- notes = {}
40
+ metadata = Metadata.new
40
41
  count = 0
41
42
 
42
43
  (2..sheet.num_rows).each do |row|
@@ -44,14 +45,14 @@ module I18n
44
45
  if key.present?
45
46
  locale.assign_complex_key(data, key.split('.'), value.present? ? value : '')
46
47
  if note.present?
47
- locale.assign_complex_key(notes, key.split('.'), note)
48
+ metadata[key] = parse_metadatum(note)
48
49
  end
49
50
  count += 1
50
- print '.'
51
+ #print '.'
51
52
  end
52
53
  end
53
54
 
54
- locale.write_data_and_notes(data, notes)
55
+ locale.write_data_and_metadata(data, metadata)
55
56
  locale.write_remote_version(data)
56
57
 
57
58
  puts "\n#{count} keys"
@@ -59,7 +60,7 @@ module I18n
59
60
 
60
61
  def push_to_sheet(sheet, locale)
61
62
  main_data = locale.main_locale.read_data
62
- data, notes = locale.read_data_and_notes
63
+ data, metadata = locale.read_data_and_metadata
63
64
  row = 2
64
65
 
65
66
  puts "Pushing #{locale.name}"
@@ -68,9 +69,9 @@ module I18n
68
69
  sheet[row, 1] = key
69
70
  sheet[row, 2] = value
70
71
  sheet[row, 3] = data[key]
71
- sheet[row, 4] = notes[key]
72
+ sheet[row, 4] = unparse_metadatum(metadata[key])
72
73
  row += 1
73
- print '.'
74
+ #print '.'
74
75
  end
75
76
 
76
77
  sheet.synchronize
@@ -78,6 +79,28 @@ module I18n
78
79
 
79
80
  puts "\n#{main_data.keys.length} keys"
80
81
  end
82
+
83
+ def parse_metadatum(text)
84
+ m = Metadata::Metadatum.new({})
85
+ m.notes = text.gsub("[autotranslated]") do
86
+ m.autotranslated = true
87
+ ''
88
+ end.gsub(/\[error: ([^\]]+)\]/) do
89
+ m.errors << $1
90
+ ''
91
+ end.strip
92
+ m
93
+ end
94
+
95
+ def unparse_metadatum(metadatum)
96
+ string = []
97
+ string << '[autotranslated]' if metadatum.autotranslated
98
+ metadatum.errors.each do |error|
99
+ string << "[error: #{error}]"
100
+ end
101
+ string << metadatum.notes unless metadatum.notes.blank?
102
+ string.join("\n")
103
+ end
81
104
  end
82
105
  end
83
106
  end
@@ -9,7 +9,7 @@ module I18n
9
9
  end
10
10
 
11
11
  # key is provided so we can figure out if this is text or html
12
- # returns [translated term, notes]
12
+ # returns [translated term, errors || []]
13
13
  def lookup(term, key: nil)
14
14
  return [term, ''] if @from_locale == @to_locale
15
15
 
@@ -19,11 +19,7 @@ module I18n
19
19
  format: format(key),
20
20
  q: term)
21
21
  translated_term = JSON.parse(response.body)['data']['translations'].first['translatedText']
22
- translated_term, errors = fix(term, translated_term, key: key)
23
- unless errors.empty?
24
- STDERR.puts "'#{term}' => '#{translated_term}'\n#{errors.join(', ').red}"
25
- end
26
- [translated_term, (errors.map { |e| "[error: #{e}]" } + ['[autotranslated]']).join("\n")]
22
+ fix(term, translated_term, key: key)
27
23
  end
28
24
 
29
25
  VARIABLE_STRING_REGEX = /%\{[^\}]+\}/
@@ -42,7 +38,7 @@ module I18n
42
38
  # returns updated after term, errors
43
39
  def fix(before, after, key: nil)
44
40
  is_html = format(key) == :html
45
- errors = ["#{@to_locale}: #{key}"]
41
+ errors = []
46
42
 
47
43
  # do not translate
48
44
  @do_not_translate.each do |term, bad_translations|
@@ -114,7 +110,7 @@ module I18n
114
110
  end
115
111
 
116
112
 
117
- [after, errors.length > 1 ? errors : []]
113
+ [after, errors]
118
114
  end
119
115
 
120
116
  private
@@ -3,6 +3,7 @@ require 'yaml'
3
3
  require 'active_support'
4
4
  require 'colorize'
5
5
  require 'active_support/core_ext/object'
6
+ require_relative './metadata'
6
7
 
7
8
  # this class does all the work, but doesn't hold config or do more than one locale
8
9
  module I18n
@@ -16,7 +17,7 @@ module I18n
16
17
  name, locales_dir, main_locale_name, migrations, dictionary
17
18
  end
18
19
 
19
- def validate(data, notes)
20
+ def validate(data, metadata)
20
21
  fix_count, error_count = 0, 0
21
22
  main_data = main_locale.read_data
22
23
  main_data.each do |key, main_term|
@@ -31,7 +32,7 @@ module I18n
31
32
  puts
32
33
  fix_count += 1
33
34
  end
34
- replace_errors_in_notes(notes, key, errors)
35
+ metadata[key].errors = errors
35
36
  if errors.length > 0
36
37
  puts "Error #{errors.join(', ').red} #{key.yellow}"
37
38
  puts "#{@main_locale_name.bold}: #{main_term}"
@@ -46,18 +47,18 @@ module I18n
46
47
  end
47
48
 
48
49
  def update_info
49
- data, notes = read_data_and_notes
50
- yield data, notes
51
- write_data_and_notes(data, notes)
50
+ data, metadata = read_data_and_metadata
51
+ yield data, metadata
52
+ write_data_and_metadata(data, metadata)
52
53
  end
53
54
 
54
55
  def migrate!
55
- update_info do |data, notes|
56
- migrate(data, notes)
56
+ update_info do |data, metadata|
57
+ migrate(data, metadata)
57
58
  end
58
59
  end
59
60
 
60
- def migrate(data, notes)
61
+ def migrate(data, metadata)
61
62
  missing_versions = (@migrations.all_versions - read_versions(data)).sort
62
63
  if missing_versions.empty?
63
64
  puts "#{@name}: up-to-date"
@@ -65,11 +66,11 @@ module I18n
65
66
  end
66
67
  puts "#{@name}: Migrating #{missing_versions.join(', ')}"
67
68
  missing_versions.each do |version|
68
- migrate_to_version(data, notes, version, :up)
69
+ migrate_to_version(data, metadata, version, :up)
69
70
  end
70
71
  end
71
72
 
72
- def rollback(data, notes)
73
+ def rollback(data, metadata)
73
74
  last_version = read_versions(data).last
74
75
  if last_version == nil
75
76
  puts "#{@name}: no more migrations to roll back"
@@ -78,24 +79,25 @@ module I18n
78
79
  puts "#{@name}: Rolling back #{last_version}"
79
80
  raise "Can't find #{last_version}.rb to rollback" unless @migrations.all_versions.include?(last_version)
80
81
 
81
- migrate_to_version(data, notes, last_version, :down)
82
+ migrate_to_version(data, metadata, last_version, :down)
82
83
  end
83
84
 
84
85
  def create(limit = nil)
85
- new_data, new_notes = {}, {}
86
+ new_data, new_metadata = {}, Metadata.new
86
87
  count = 0
87
88
  main_data = main_locale.read_data
88
89
  main_data.each do |key, term|
89
90
  if key == 'VERSION'
90
91
  new_data['VERSION'] = main_data['VERSION']
91
92
  else
92
- new_data[key], new_notes[key] = @dictionary.lookup(term, key: key)
93
+ new_data[key], errors = @dictionary.lookup(term, key: key)
94
+ new_metadata[key].errors = errors
93
95
  end
94
96
  print '.'.green
95
97
  break if limit && limit < (count += 1)
96
98
  end
97
99
  puts
98
- write_data_and_notes(new_data, new_notes)
100
+ write_data_and_metadata(new_data, new_metadata)
99
101
  end
100
102
 
101
103
  def main_locale?
@@ -107,29 +109,27 @@ module I18n
107
109
  end
108
110
 
109
111
  def read_data(parse: true)
110
- read_from_file("#{@name}.yml", parse: parse)
112
+ contents = data_file.read
113
+ return contents unless parse
114
+
115
+ hash = {}
116
+ add_to_hash(hash, parse_yaml(contents)[@name.to_s])
117
+ hash
111
118
  end
112
119
 
113
- def read_data_and_notes(parse: true)
120
+ def read_data_and_metadata(parse: true)
114
121
  data = read_data(parse: parse)
115
- notes = main_locale? ? (parse ? {} : '--- {}') : read_from_file("../#{@name}_notes.yml", parse: parse)
116
- [data, notes]
122
+ metadata = read_metadata(parse: parse)
123
+ [data, metadata]
117
124
  end
118
125
 
119
- def write_data_and_notes(data, notes)
126
+ def write_data_and_metadata(data, metadata)
120
127
  write_data(data)
121
- write_to_file("../#{@name}_notes.yml", notes) unless main_locale?
122
- end
123
-
124
- def write_raw_data(filename, data)
125
- File.open(File.join(@locales_dir, filename), 'w') do |file|
126
- file << data
127
- end
128
+ write_metadata(metadata)
128
129
  end
129
130
 
130
131
  def write_remote_version(data)
131
- write_to_file("../#{@name}_remote_version.yml",
132
- { 'VERSION' => read_versions(data) })
132
+ remote_version_file.write({ 'VERSION' => read_versions(data) }.to_yaml)
133
133
  end
134
134
 
135
135
  def main_locale
@@ -151,26 +151,48 @@ module I18n
151
151
  end
152
152
  end
153
153
 
154
- private
154
+ def data_file
155
+ file("#{name}.yml")
156
+ end
155
157
 
156
- def replace_errors_in_notes(all_notes, key, errors)
157
- return if all_notes[key].blank? && errors.empty?
158
+ def metadata_file
159
+ file("../#{name}_metadata.yml")
160
+ end
158
161
 
159
- notes = all_notes[key]
160
- notes = notes.present? ? notes.split("\n") : []
161
- notes = notes.reject { |n| n.start_with?("[error:") }
162
- all_notes[key] = (errors.map { |e| "[error: #{e}]" } + notes).join("\n")
162
+ def remote_version_file
163
+ file("../#{@name}_remote_version.yml")
163
164
  end
164
165
 
166
+ private
167
+
165
168
  def write_data(data)
166
- write_to_file("#{@name}.yml", data)
169
+ # we have to go from flat keys -> values to a hash that contains other hashes
170
+ complex_hash = {}
171
+ data.keys.sort.each do |key|
172
+ value = data[key]
173
+ assign_complex_key(complex_hash, key.split('.'), value.present? ? value : '')
174
+ end
175
+ data_file.write({ @name => complex_hash }.to_yaml)
176
+ end
177
+
178
+ def read_metadata(parse: true)
179
+ contents = if metadata_file.exist?
180
+ metadata_file.read
181
+ else
182
+ {}.to_yaml
183
+ end
184
+ parse ? Metadata.new(parse_yaml(contents)) : contents
167
185
  end
168
186
 
169
- def migrate_to_version(data, notes, version, direction)
187
+ def write_metadata(metadata)
188
+ metadata_file.write(metadata.to_yaml)
189
+ end
190
+
191
+ def migrate_to_version(data, metadata, version, direction)
170
192
  migrations.play_migration(version: version,
171
193
  locale: @name,
172
194
  data: data,
173
- notes: notes,
195
+ metadata: metadata,
174
196
  dictionary: @dictionary,
175
197
  direction: direction)
176
198
 
@@ -185,29 +207,12 @@ module I18n
185
207
  (data['VERSION'] && data['VERSION'].split("\n")) || []
186
208
  end
187
209
 
188
- def read_from_file(filename, parse: true)
189
- filename = File.join(@locales_dir, filename)
190
- begin
191
- contents = File.read(filename)
192
- return contents unless parse
193
-
194
- hash = {}
195
- add_to_hash(hash, YAML.load(contents)[@name.to_s])
196
- hash
197
- rescue
198
- puts "Error loading #{filename}"
199
- raise
200
- end
210
+ def file(filename)
211
+ Pathname.new(File.join(@locales_dir, filename))
201
212
  end
202
213
 
203
- def write_to_file(filename, hash)
204
- # we have to go from flat keys -> values to a hash that contains other hashes
205
- complex_hash = {}
206
- hash.keys.sort.each do |key|
207
- value = hash[key]
208
- assign_complex_key(complex_hash, key.split('.'), value.present? ? value : '')
209
- end
210
- write_raw_data(filename, { @name => complex_hash }.to_yaml)
214
+ def parse_yaml(string)
215
+ YAML.load(string)
211
216
  end
212
217
 
213
218
  # flattens new_hash and adds it to hash
@@ -0,0 +1,57 @@
1
+ # this class stores metadata about terms in a locale
2
+ # specifically things like errors, notes, autotranslated
3
+ # it acts kind of like a hash where you give it a key and it returns a metadatum object
4
+ class Metadata
5
+ def initialize(hash = {})
6
+ @hash = hash
7
+ end
8
+
9
+ def [](key)
10
+ if @hash[key].is_a?(Metadatum)
11
+ @hash[key]
12
+ else
13
+ @hash[key] = Metadatum.new(@hash[key])
14
+ end
15
+ end
16
+
17
+ def []=(key, value)
18
+ raise("you may only assign a metadatum") unless value.is_a?(Metadatum)
19
+ @hash[key] = value.dup
20
+ end
21
+
22
+ def delete(key)
23
+ @hash.delete(key)
24
+ end
25
+
26
+ def to_h
27
+ compacted_hash = {}
28
+ @hash.keys.sort.each do |key|
29
+ value = @hash[key].to_h
30
+ compacted_hash[key] = value if value.present?
31
+ end
32
+ compacted_hash
33
+ end
34
+
35
+ def to_yaml
36
+ to_h.to_yaml
37
+ end
38
+
39
+ class Metadatum
40
+ attr_accessor :errors, :notes, :autotranslated
41
+
42
+ def initialize(hash)
43
+ safe_hash = hash || {}
44
+ @errors = safe_hash['errors'] || []
45
+ @notes = safe_hash['notes']
46
+ @autotranslated = !!safe_hash['autotranslated']
47
+ end
48
+
49
+ def to_h
50
+ hash = {}
51
+ hash['errors'] = @errors unless @errors.empty?
52
+ hash['notes'] = @notes unless @notes.blank?
53
+ hash['autotranslated'] = @autotranslated if autotranslated
54
+ hash
55
+ end
56
+ end
57
+ end
@@ -101,10 +101,10 @@ module I18n
101
101
 
102
102
  def assign_translation(key, term, overrides)
103
103
  if overrides[@locale_code.to_sym]
104
- @translations.set_term(key, value: overrides[@locale_code.to_sym])
104
+ @translations.set_term(key, value: overrides[@locale_code.to_sym], errors: [], autotranslated: false)
105
105
  else
106
- value, notes = @dictionary.lookup(term, key: key)
107
- @translations.set_term(key, value: value, notes: notes)
106
+ value, errors = @dictionary.lookup(term, key: key)
107
+ @translations.set_term(key, value: value, errors: errors, autotranslated: true)
108
108
  end
109
109
  end
110
110
  end
@@ -20,14 +20,14 @@ module I18n
20
20
  File.join(@migration_dir, "#{version}.rb")
21
21
  end
22
22
 
23
- def play_migration(version:, locale:, data:, notes:, dictionary:, direction:)
23
+ def play_migration(version:, locale:, data:, metadata:, dictionary:, direction:)
24
24
  filename = File.join(@migration_dir, "#{version}.rb")
25
25
  require filename
26
26
 
27
27
  raise("Can't parse version: #{version}") unless version =~ /^(\d{12})_(.*)/
28
28
  migration_class_name = "#{$2.camelcase}#{$1}"
29
29
 
30
- translations = Translations.new(data: data, notes: notes)
30
+ translations = Translations.new(data: data, metadata: metadata)
31
31
  migration = begin
32
32
  migration_class_name.constantize.new(locale_code: locale,
33
33
  translations: translations,
@@ -42,33 +42,37 @@ module I18n
42
42
 
43
43
  # This is a facade over our translations
44
44
  # data = all keys -> all translations in this locale
45
- # notes = some keys -> notes about the translation in this locale
45
+ # metadata = some keys -> metadata about the translation in this locale
46
46
  class Translations
47
- def initialize(data:, notes:)
48
- @data, @notes = data, notes
47
+ def initialize(data:, metadata:)
48
+ @data, @metadata = data, metadata
49
49
  end
50
50
 
51
51
  def get_term(key)
52
52
  @data[key]
53
53
  end
54
54
 
55
- def set_term(key, value:, notes: nil)
55
+ def set_term(key, value:, errors:, autotranslated:)
56
+ # translated_term, errors = lookup_with_errors(term, key: key)
57
+ # unless errors.empty?
58
+ # STDERR.puts "'#{term}' => '#{translated_term}'\n#{errors.join(', ').red}"
59
+ # end
60
+ # [translated_term, (errors.map { |e| "[error: #{e}]" } + ['[autotranslated]']).join("\n")]
61
+
56
62
  @data[key] = value
57
- if notes.present?
58
- @notes[key] = notes
59
- else
60
- @notes.delete(key)
61
- end
63
+ @metadata[key].errors = errors
64
+ @metadata[key].notes = nil
65
+ @metadata[key].autotranslated = autotranslated
62
66
  end
63
67
 
64
68
  def delete_term(key)
65
69
  @data.delete(key)
66
- @notes.delete(key)
70
+ @metadata.delete(key)
67
71
  end
68
72
 
69
73
  def move_term(from, to)
70
74
  @data[to] = @data.delete(from)
71
- @notes[to] = @notes.delete(from)
75
+ @metadata[to] = @metadata.delete(from)
72
76
  end
73
77
  end
74
78
  end
@@ -64,8 +64,8 @@ end
64
64
 
65
65
  def rollback(locale_or_all)
66
66
  each_locale(locale_or_all) do |locale|
67
- locale.update_info do |data, notes|
68
- locale.rollback(data, notes)
67
+ locale.update_info do |data, metadata|
68
+ locale.rollback(data, metadata)
69
69
  end
70
70
  end
71
71
  end
@@ -97,8 +97,8 @@ end
97
97
  def validate(locale_or_all)
98
98
  each_locale(locale_or_all, async: false) do |locale|
99
99
  next if locale.main_locale?
100
- locale.update_info do |data, notes|
101
- locale.validate(data, notes)
100
+ locale.update_info do |data, metadata|
101
+ locale.validate(data, metadata)
102
102
  end
103
103
  end
104
104
  end
@@ -1,5 +1,5 @@
1
1
  module I18n
2
2
  module Migrations
3
- VERSION = "1.2.4"
3
+ VERSION = "2.0.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: i18n-migrations
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.4
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Lightsmith
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-04 00:00:00.000000000 Z
11
+ date: 2020-03-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -130,6 +130,7 @@ files:
130
130
  - lib/i18n/migrations/config.rb
131
131
  - lib/i18n/migrations/google_translate_dictionary.rb
132
132
  - lib/i18n/migrations/locale.rb
133
+ - lib/i18n/migrations/metadata.rb
133
134
  - lib/i18n/migrations/migration.rb
134
135
  - lib/i18n/migrations/migration_factory.rb
135
136
  - lib/i18n/migrations/migrator.rb