rails_translation_manager 0.0.2 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -1
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +20 -0
  5. data/Jenkinsfile +9 -0
  6. data/README.md +1 -1
  7. data/Rakefile +12 -13
  8. data/config/locales/plurals.rb +49 -0
  9. data/lib/rails_translation_manager/cleaner.rb +14 -0
  10. data/lib/rails_translation_manager/i18n_tasks_option_parser.rb +10 -0
  11. data/lib/rails_translation_manager/importer.rb +32 -14
  12. data/lib/rails_translation_manager/locale_checker/all_locales.rb +61 -0
  13. data/lib/rails_translation_manager/locale_checker/base_checker.rb +13 -0
  14. data/lib/rails_translation_manager/locale_checker/incompatible_plurals.rb +79 -0
  15. data/lib/rails_translation_manager/locale_checker/locale_checker_helper.rb +23 -0
  16. data/lib/rails_translation_manager/locale_checker/missing_english_locales.rb +31 -0
  17. data/lib/rails_translation_manager/locale_checker/missing_foreign_locales.rb +31 -0
  18. data/lib/rails_translation_manager/locale_checker/plural_forms.rb +16 -0
  19. data/lib/rails_translation_manager/locale_checker.rb +50 -0
  20. data/lib/rails_translation_manager/version.rb +1 -1
  21. data/lib/rails_translation_manager.rb +21 -3
  22. data/lib/tasks/translation.rake +43 -43
  23. data/rails_translation_manager.gemspec +4 -2
  24. data/spec/locales/cleaner/clean.yml +5 -0
  25. data/spec/locales/cleaner/with_whitespace.yml +5 -0
  26. data/spec/locales/importer/fr.csv +8 -0
  27. data/spec/locales/in_sync/cy/browse.yml +12 -0
  28. data/spec/locales/in_sync/en/browse.yml +8 -0
  29. data/spec/locales/out_of_sync/cy.yml +3 -0
  30. data/spec/locales/out_of_sync/en.yml +6 -0
  31. data/spec/rails_translation_manager/cleaner_spec.rb +13 -0
  32. data/spec/rails_translation_manager/importer_spec.rb +81 -0
  33. data/spec/rails_translation_manager/locale_checker/all_locales_spec.rb +24 -0
  34. data/spec/rails_translation_manager/locale_checker/incompatible_plurals_spec.rb +94 -0
  35. data/spec/rails_translation_manager/locale_checker/locale_checker_helper_spec.rb +61 -0
  36. data/spec/rails_translation_manager/locale_checker/missing_english_locales_spec.rb +72 -0
  37. data/spec/rails_translation_manager/locale_checker/missing_foreign_locales_spec.rb +80 -0
  38. data/spec/rails_translation_manager/locale_checker/plural_forms_spec.rb +27 -0
  39. data/spec/rails_translation_manager/locale_checker_spec.rb +68 -0
  40. data/spec/spec_helper.rb +19 -0
  41. data/spec/support/tasks.rb +7 -0
  42. data/spec/tasks/translation_spec.rb +123 -0
  43. data/test/rails_translation_manager/yaml_writer_test.rb +2 -0
  44. data/tmp/.gitkeep +0 -0
  45. metadata +93 -24
  46. data/jenkins.sh +0 -9
  47. data/lib/rails_translation_manager/stealer.rb +0 -85
  48. data/lib/rails_translation_manager/validator.rb +0 -92
  49. data/test/rails_translation_manager/importer_test.rb +0 -132
  50. data/test/rails_translation_manager/stealer_test.rb +0 -251
  51. data/test/rails_translation_manager/validator_test.rb +0 -51
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe RailsTranslationManager::LocaleChecker do
6
+ context "when the locales are valid" do
7
+ it "calls each checker class" do
8
+ described_class::CHECKER_CLASSES.each do |checker|
9
+ expect_any_instance_of(checker).to receive(:report)
10
+ end
11
+
12
+ described_class.new("spec/locales/in_sync/**/*.yml").validate_locales
13
+ end
14
+
15
+ it "outputs a confirmation" do
16
+ expect { described_class.new("spec/locales/in_sync/**/*.yml").validate_locales }
17
+ .to output("Locale files are in sync, nice job!\n").to_stdout
18
+ end
19
+
20
+ it "returns true" do
21
+ expect(described_class.new("spec/locales/in_sync/**/*.yml").validate_locales)
22
+ .to eq(true)
23
+ end
24
+ end
25
+
26
+ context "when the locales are not valid" do
27
+ it "calls each checker class" do
28
+ described_class::CHECKER_CLASSES.each do |checker|
29
+ expect_any_instance_of(checker).to receive(:report)
30
+ end
31
+
32
+ described_class.new("spec/locales/out_of_sync/*.yml").validate_locales
33
+ end
34
+
35
+ it "outputs the report" do
36
+ printed = capture_stdout do
37
+ described_class.new("spec/locales/out_of_sync/*.yml").validate_locales
38
+ end
39
+
40
+ expect(printed.scan(/\[ERROR\]/).count).to eq(3)
41
+ end
42
+
43
+ it "returns false" do
44
+ expect(described_class.new("spec/locales/out_of_sync/*.yml").validate_locales)
45
+ .to eq(false)
46
+ end
47
+ end
48
+
49
+ context "when the locale path doesn't relate to any YAML files" do
50
+ it "doesn't call any checker classes" do
51
+ described_class::CHECKER_CLASSES.each do |checker|
52
+ expect_any_instance_of(checker).to_not receive(:report)
53
+ end
54
+
55
+ described_class.new("some/random/path").validate_locales
56
+ end
57
+
58
+ it "outputs an error message" do
59
+ expect { described_class.new("some/random/path").validate_locales }
60
+ .to output("No locale files found for the supplied path\n").to_stdout
61
+ end
62
+
63
+ it "returns false" do
64
+ expect(described_class.new("some/random/path").validate_locales)
65
+ .to eq(false)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails_translation_manager"
4
+
5
+ RSpec.configure do |config|
6
+ config.before do
7
+ I18n.available_locales = %i[en cy]
8
+ config.before { allow($stdout).to receive(:puts) }
9
+ end
10
+
11
+ def capture_stdout(&blk)
12
+ old = $stdout
13
+ $stdout = fake = StringIO.new
14
+ blk.call
15
+ fake.string
16
+ ensure
17
+ $stdout = old
18
+ end
19
+ end
@@ -0,0 +1,7 @@
1
+ require 'rake'
2
+
3
+ RSpec.configure do |config|
4
+ config.before(:suite) do
5
+ Dir.glob('lib/tasks/*.rake').each { |r| Rake::DefaultLoader.new.load r }
6
+ end
7
+ end
@@ -0,0 +1,123 @@
1
+ require "spec_helper"
2
+ require_relative "../../spec/support/tasks"
3
+
4
+ describe "rake tasks" do
5
+ before do
6
+ fake_rails = double()
7
+ fake_rails.stub(:root) { Pathname.new("spec") }
8
+ stub_const("Rails", fake_rails)
9
+ end
10
+
11
+ describe "translation:import", type: :task do
12
+ let(:task) { Rake::Task["translation:import"] }
13
+ let(:csv_path) { "path/to/import/fr.csv" }
14
+ let!(:importer_instance) { stub_importer }
15
+
16
+ it "outputs to stdout" do
17
+ expect { task.execute(csv_path: csv_path) }
18
+ .to output("Imported CSV from: #{csv_path} to #{Rails.root.join("config", "locales")}\n")
19
+ .to_stdout
20
+ end
21
+
22
+ it "calls the Importer class with the csv and import paths" do
23
+ task.execute(csv_path: csv_path)
24
+
25
+ expect(RailsTranslationManager::Importer)
26
+ .to have_received(:new)
27
+ .with(locale: "fr",
28
+ csv_path: csv_path,
29
+ import_directory: Rails.root.join("config", "locales"),
30
+ multiple_files_per_language: false)
31
+ expect(importer_instance).to have_received(:import)
32
+ end
33
+ end
34
+
35
+ describe "translation:import:all", type: :task do
36
+ let(:task) { Rake::Task["translation:import:all"] }
37
+ let(:csv_directory) { "locales/importer" }
38
+ let!(:importer_instance) { stub_importer }
39
+
40
+ it "outputs to stdout" do
41
+ expect { task.execute(csv_directory: csv_directory) }
42
+ .to output("Imported all CSVs from: #{csv_directory} to #{Rails.root.join("config", "locales")}\n")
43
+ .to_stdout
44
+ end
45
+
46
+ it "calls the importer class for each target path" do
47
+ task.execute(csv_directory: csv_directory, multiple_files_per_language: true)
48
+
49
+ expect(RailsTranslationManager::Importer)
50
+ .to have_received(:new)
51
+ .with(locale: "fr",
52
+ csv_path: "spec/locales/importer/fr.csv",
53
+ import_directory: Rails.root.join("config", "locales"),
54
+ multiple_files_per_language: true)
55
+ expect(importer_instance).to have_received(:import)
56
+ end
57
+ end
58
+
59
+ describe "translation:add_missing", type: :task do
60
+ let(:task) { Rake::Task["translation:add_missing"] }
61
+ let!(:cleaner_instance) { stub_cleaner }
62
+
63
+ before do
64
+ allow(I18n::Tasks::CLI).to receive(:start)
65
+ end
66
+
67
+ it "triggers Cleaner and allows to receive the right arguments" do
68
+ task.execute
69
+ expect(RailsTranslationManager::Cleaner)
70
+ .to have_received(:new)
71
+ .with(Rails.root.join("config", "locales"))
72
+ expect(cleaner_instance).to have_received(:clean)
73
+ end
74
+
75
+ it "triggers i18n task and allows to receive the right arguments" do
76
+ task.execute(locale: "fr")
77
+ expect(I18n::Tasks::CLI).to have_received(:start).with(
78
+ ["add-missing", "--nil-value", ["-l", "fr"]]
79
+ )
80
+ end
81
+ end
82
+
83
+ describe "translation:normalize", type: :task do
84
+ let(:task) { Rake::Task["translation:normalize"] }
85
+ let!(:cleaner_instance) { stub_cleaner }
86
+
87
+ before do
88
+ allow(I18n::Tasks::CLI).to receive(:start)
89
+ end
90
+
91
+ it "triggers Cleaner and allows to receive the right arguments" do
92
+ task.execute(locale_directory: "config/locales")
93
+ expect(RailsTranslationManager::Cleaner)
94
+ .to have_received(:new)
95
+ .with(Rails.root.join("config", "locales"))
96
+ expect(cleaner_instance).to have_received(:clean)
97
+ end
98
+
99
+ it "triggers i18n task and allows to receive the right arguments" do
100
+ task.execute
101
+ expect(I18n::Tasks::CLI).to have_received(:start).with(["normalize"])
102
+ end
103
+ end
104
+
105
+ def stub_importer
106
+ importer_instance = instance_double(RailsTranslationManager::Importer)
107
+ allow(RailsTranslationManager::Importer).to receive(:new)
108
+ .and_return(importer_instance)
109
+ allow(importer_instance).to receive(:import)
110
+
111
+ importer_instance
112
+ end
113
+
114
+ def stub_cleaner
115
+ cleaner_instance = instance_double(RailsTranslationManager::Cleaner)
116
+ allow(RailsTranslationManager::Cleaner)
117
+ .to receive(:new)
118
+ .and_return(cleaner_instance)
119
+ allow(cleaner_instance).to receive(:clean)
120
+
121
+ cleaner_instance
122
+ end
123
+ end
@@ -1,3 +1,5 @@
1
+ require "test_helper"
2
+ require "rails_translation_manager/yaml_writer"
1
3
  module RailsTranslationManager
2
4
  class DummyWriter
3
5
  include YAMLWriter
data/tmp/.gitkeep ADDED
File without changes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_translation_manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Edd Sowden
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-22 00:00:00.000000000 Z
11
+ date: 2021-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails-i18n
@@ -39,33 +39,33 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: bundler
42
+ name: i18n-tasks
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '1.7'
48
- type: :development
47
+ version: '0'
48
+ type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '1.7'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: gem_publisher
56
+ name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 1.1.1
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 1.1.1
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +94,34 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: byebug
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
97
125
  description: ''
98
126
  email:
99
127
  - edd.sowden@digital.cabinet-office.gov.uk
@@ -107,26 +135,52 @@ files:
107
135
  - CHANGELOG.md
108
136
  - CONTRIBUTING.md
109
137
  - Gemfile
138
+ - Jenkinsfile
110
139
  - LICENSE.txt
111
140
  - README.md
112
141
  - Rakefile
113
- - jenkins.sh
142
+ - config/locales/plurals.rb
114
143
  - lib/rails_translation_manager.rb
144
+ - lib/rails_translation_manager/cleaner.rb
115
145
  - lib/rails_translation_manager/exporter.rb
146
+ - lib/rails_translation_manager/i18n_tasks_option_parser.rb
116
147
  - lib/rails_translation_manager/importer.rb
148
+ - lib/rails_translation_manager/locale_checker.rb
149
+ - lib/rails_translation_manager/locale_checker/all_locales.rb
150
+ - lib/rails_translation_manager/locale_checker/base_checker.rb
151
+ - lib/rails_translation_manager/locale_checker/incompatible_plurals.rb
152
+ - lib/rails_translation_manager/locale_checker/locale_checker_helper.rb
153
+ - lib/rails_translation_manager/locale_checker/missing_english_locales.rb
154
+ - lib/rails_translation_manager/locale_checker/missing_foreign_locales.rb
155
+ - lib/rails_translation_manager/locale_checker/plural_forms.rb
117
156
  - lib/rails_translation_manager/railtie.rb
118
- - lib/rails_translation_manager/stealer.rb
119
- - lib/rails_translation_manager/validator.rb
120
157
  - lib/rails_translation_manager/version.rb
121
158
  - lib/rails_translation_manager/yaml_writer.rb
122
159
  - lib/tasks/translation.rake
123
160
  - rails_translation_manager.gemspec
161
+ - spec/locales/cleaner/clean.yml
162
+ - spec/locales/cleaner/with_whitespace.yml
163
+ - spec/locales/importer/fr.csv
164
+ - spec/locales/in_sync/cy/browse.yml
165
+ - spec/locales/in_sync/en/browse.yml
166
+ - spec/locales/out_of_sync/cy.yml
167
+ - spec/locales/out_of_sync/en.yml
168
+ - spec/rails_translation_manager/cleaner_spec.rb
169
+ - spec/rails_translation_manager/importer_spec.rb
170
+ - spec/rails_translation_manager/locale_checker/all_locales_spec.rb
171
+ - spec/rails_translation_manager/locale_checker/incompatible_plurals_spec.rb
172
+ - spec/rails_translation_manager/locale_checker/locale_checker_helper_spec.rb
173
+ - spec/rails_translation_manager/locale_checker/missing_english_locales_spec.rb
174
+ - spec/rails_translation_manager/locale_checker/missing_foreign_locales_spec.rb
175
+ - spec/rails_translation_manager/locale_checker/plural_forms_spec.rb
176
+ - spec/rails_translation_manager/locale_checker_spec.rb
177
+ - spec/spec_helper.rb
178
+ - spec/support/tasks.rb
179
+ - spec/tasks/translation_spec.rb
124
180
  - test/rails_translation_manager/exporter_test.rb
125
- - test/rails_translation_manager/importer_test.rb
126
- - test/rails_translation_manager/stealer_test.rb
127
- - test/rails_translation_manager/validator_test.rb
128
181
  - test/rails_translation_manager/yaml_writer_test.rb
129
182
  - test/test_helper.rb
183
+ - tmp/.gitkeep
130
184
  homepage: ''
131
185
  licenses:
132
186
  - MIT
@@ -146,15 +200,30 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
200
  - !ruby/object:Gem::Version
147
201
  version: '0'
148
202
  requirements: []
149
- rubyforge_project:
150
- rubygems_version: 2.2.2
203
+ rubygems_version: 3.0.3
151
204
  signing_key:
152
205
  specification_version: 4
153
206
  summary: Tasks to manage translation files
154
207
  test_files:
208
+ - spec/locales/cleaner/clean.yml
209
+ - spec/locales/cleaner/with_whitespace.yml
210
+ - spec/locales/importer/fr.csv
211
+ - spec/locales/in_sync/cy/browse.yml
212
+ - spec/locales/in_sync/en/browse.yml
213
+ - spec/locales/out_of_sync/cy.yml
214
+ - spec/locales/out_of_sync/en.yml
215
+ - spec/rails_translation_manager/cleaner_spec.rb
216
+ - spec/rails_translation_manager/importer_spec.rb
217
+ - spec/rails_translation_manager/locale_checker/all_locales_spec.rb
218
+ - spec/rails_translation_manager/locale_checker/incompatible_plurals_spec.rb
219
+ - spec/rails_translation_manager/locale_checker/locale_checker_helper_spec.rb
220
+ - spec/rails_translation_manager/locale_checker/missing_english_locales_spec.rb
221
+ - spec/rails_translation_manager/locale_checker/missing_foreign_locales_spec.rb
222
+ - spec/rails_translation_manager/locale_checker/plural_forms_spec.rb
223
+ - spec/rails_translation_manager/locale_checker_spec.rb
224
+ - spec/spec_helper.rb
225
+ - spec/support/tasks.rb
226
+ - spec/tasks/translation_spec.rb
155
227
  - test/rails_translation_manager/exporter_test.rb
156
- - test/rails_translation_manager/importer_test.rb
157
- - test/rails_translation_manager/stealer_test.rb
158
- - test/rails_translation_manager/validator_test.rb
159
228
  - test/rails_translation_manager/yaml_writer_test.rb
160
229
  - test/test_helper.rb
data/jenkins.sh DELETED
@@ -1,9 +0,0 @@
1
- #!/bin/bash -x
2
- set -e
3
- rm -f Gemfile.lock
4
- bundle install --path "${HOME}/bundles/${JOB_NAME}"
5
- export GOVUK_APP_DOMAIN=dev.gov.uk
6
- bundle exec rake test
7
- if [[ -n "$PUBLISH_GEM" ]]; then
8
- bundle exec rake publish_gem --trace
9
- fi
@@ -1,85 +0,0 @@
1
- require "yaml"
2
- require "i18n"
3
- require_relative "yaml_writer"
4
-
5
- class RailsTranslationManager::Stealer
6
- include YAMLWriter
7
-
8
- # locale is the locale name as a string.
9
- # source_app_path is the path to the root of the app to steal from.
10
- # mapping_file_path is the path to a YAML file mapping translation keys in
11
- # the source app to those in the target app. For example:
12
- # document.type: content_item.format
13
- # document.published: content_item.metadata.published
14
- # which will import everything under "document.type" and "document.published"
15
- # in the source app, and write it to "content_item.format" and
16
- # "content_item.metadata.published" in the target app.
17
- # locales_path is the path to the locale files to output, which is usually
18
- # Rails.root.join('config/locales').
19
- # The process will preserve data already in the output file if it is not
20
- # referenced in the mapping, but will always override data belonging to keys
21
- # that are in the mapping.
22
- def initialize(locale, source_app_path, mapping_file_path, locales_path)
23
- @locale = locale
24
- @source_app_path = source_app_path
25
- @mapping_file_path = mapping_file_path
26
- @locales_path = locales_path
27
- end
28
-
29
- def steal_locale
30
- target_data = convert_locale(get_target_data)
31
- write_yaml(target_locale_path, target_data)
32
- end
33
-
34
- def convert_locale(target_data)
35
- mapping_data.each do |source, target|
36
- data = source_data[@locale]
37
- source.split('.').each { |key| data = data.fetch(key, {}) }
38
- set_recursive(target_data[@locale], target.split("."), data)
39
- end
40
- target_data
41
- end
42
-
43
- private
44
-
45
- def set_recursive(hash, keys, data)
46
- if keys.empty?
47
- data
48
- else
49
- key = keys.shift
50
- hash.tap do |h|
51
- h.merge!({ key => set_recursive(hash.fetch(key, {}), keys, data)})
52
- end
53
- end
54
- end
55
-
56
- def source_locale_path
57
- File.join(@source_app_path, 'config', 'locales', "#{@locale}.yml")
58
- end
59
-
60
- def source_data
61
- @source_data ||= YAML.load_file(source_locale_path)
62
- end
63
-
64
- def target_locale_path
65
- File.join(@locales_path, "#{@locale}.yml")
66
- end
67
-
68
- def default_target_data
69
- { @locale => {} }
70
- end
71
-
72
- def get_target_data
73
- if File.exist?(target_locale_path)
74
- YAML.load_file(target_locale_path) || default_target_data
75
- else
76
- default_target_data
77
- end
78
- end
79
-
80
- def mapping_data
81
- @mapping_data ||= YAML.load_file(@mapping_file_path)
82
- end
83
-
84
- end
85
-
@@ -1,92 +0,0 @@
1
- require 'yaml'
2
- require 'logger'
3
-
4
- class RailsTranslationManager::Validator
5
- def initialize(translation_file_path, logger = Logger.new(nil))
6
- @translation_file_path = translation_file_path
7
- @logger = logger
8
- end
9
-
10
- def check!
11
- @logger.info "Checking translation files in '#{@translation_file_path}' for unexpected interpolation keys"
12
- @logger.info "Loading reference file (#{reference_file_name})"
13
- @logger.info "Checking..."
14
- reference = load_translation_file("#{@translation_file_path}/#{reference_file_name}")
15
- Dir["#{@translation_file_path}/*.yml"].reject do |entry|
16
- File.basename(entry) == reference_file_name
17
- end.inject([]) do |errors, entry|
18
- translation_file = load_translation_file(entry)
19
- errors + unexpected_substitution_keys(reference, translation_file)
20
- end
21
- end
22
-
23
- def unexpected_substitution_keys(reference, translation_file)
24
- reference_substitutions = substitutions_in(reference)
25
- target_substitutions = substitutions_in(translation_file)
26
-
27
- targets_by_path = target_substitutions.each_with_object({}) do |target, hash|
28
- hash[exclude_locale_from_path(target.path)] = target
29
- end
30
-
31
- reference_substitutions.each_with_object([]) do |reference, unexpected_substitutions|
32
- target = targets_by_path[exclude_locale_from_path(reference.path)]
33
- next if target.nil? || reference.has_all_substitutions?(target)
34
- unexpected_substitutions << UnexpectedSubstition.new(target, reference)
35
- end
36
- end
37
-
38
- def substitutions_in(translation_file)
39
- flatten(translation_file).reject do |translation|
40
- translation.substitutions.empty?
41
- end
42
- end
43
-
44
- class TranslationEntry < Struct.new(:path, :value)
45
- def substitutions
46
- @substitutions ||= self.value.scan(/%{([^}]*)}/)
47
- end
48
-
49
- def has_all_substitutions?(other)
50
- (other.substitutions - self.substitutions).empty?
51
- end
52
- end
53
-
54
- class UnexpectedSubstition < Struct.new(:target, :reference)
55
- def to_s
56
- missing = (self.reference.substitutions - self.target.substitutions)
57
- extras = (self.target.substitutions - self.reference.substitutions)
58
- message = %Q{Key "#{target.path.join('.')}":}
59
- if extras.any?
60
- message << %Q{ Extra substitutions: ["#{extras.join('", "')}"].}
61
- end
62
- if missing.any?
63
- message << %Q{ Missing substitutions: ["#{missing.join('", "')}"].}
64
- end
65
- message
66
- end
67
- end
68
-
69
- def flatten(translation_file, path = [])
70
- translation_file.map do |key, value|
71
- case value
72
- when Hash
73
- flatten(value, path + [key])
74
- else
75
- TranslationEntry.new(path + [key], value || "")
76
- end
77
- end.flatten
78
- end
79
-
80
- def load_translation_file(filename)
81
- YAML.load_file(filename)
82
- end
83
-
84
- def reference_file_name
85
- "en.yml"
86
- end
87
-
88
- private
89
- def exclude_locale_from_path(path)
90
- path[1..-1]
91
- end
92
- end