rails_translation_manager 0.0.2 → 1.1.1

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.
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