rails_translation_manager 0.0.1 → 1.1.0

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 (50) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -1
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +23 -0
  5. data/Jenkinsfile +9 -0
  6. data/LICENSE.txt +1 -1
  7. data/README.md +57 -1
  8. data/Rakefile +14 -9
  9. data/config/locales/plurals.rb +49 -0
  10. data/lib/rails_translation_manager/cleaner.rb +14 -0
  11. data/lib/rails_translation_manager/importer.rb +35 -19
  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/yaml_writer.rb +17 -0
  22. data/lib/rails_translation_manager.rb +21 -2
  23. data/lib/tasks/translation.rake +37 -28
  24. data/lib/tasks/translation_helper.rb +11 -0
  25. data/rails_translation_manager.gemspec +4 -1
  26. data/spec/locales/cleaner/clean.yml +5 -0
  27. data/spec/locales/cleaner/with_whitespace.yml +5 -0
  28. data/spec/locales/importer/fr.csv +8 -0
  29. data/spec/locales/in_sync/cy/browse.yml +12 -0
  30. data/spec/locales/in_sync/en/browse.yml +8 -0
  31. data/spec/locales/out_of_sync/cy.yml +3 -0
  32. data/spec/locales/out_of_sync/en.yml +6 -0
  33. data/spec/rails_translation_manager/cleaner_spec.rb +13 -0
  34. data/spec/rails_translation_manager/importer_spec.rb +81 -0
  35. data/spec/rails_translation_manager/locale_checker/all_locales_spec.rb +24 -0
  36. data/spec/rails_translation_manager/locale_checker/incompatible_plurals_spec.rb +94 -0
  37. data/spec/rails_translation_manager/locale_checker/locale_checker_helper_spec.rb +61 -0
  38. data/spec/rails_translation_manager/locale_checker/missing_english_locales_spec.rb +72 -0
  39. data/spec/rails_translation_manager/locale_checker/missing_foreign_locales_spec.rb +80 -0
  40. data/spec/rails_translation_manager/locale_checker/plural_forms_spec.rb +27 -0
  41. data/spec/rails_translation_manager/locale_checker_spec.rb +68 -0
  42. data/spec/spec_helper.rb +19 -0
  43. data/spec/support/tasks.rb +7 -0
  44. data/spec/tasks/translation_spec.rb +123 -0
  45. data/test/rails_translation_manager/yaml_writer_test.rb +60 -0
  46. data/tmp/.gitkeep +0 -0
  47. metadata +104 -13
  48. data/lib/rails_translation_manager/validator.rb +0 -92
  49. data/test/rails_translation_manager/importer_test.rb +0 -166
  50. data/test/rails_translation_manager/validator_test.rb +0 -51
@@ -1,8 +1,27 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rails_translation_manager/version"
2
4
  require "rails_translation_manager/railtie" if defined?(Rails)
3
5
  require "rails-i18n"
4
6
 
7
+ require "rails_translation_manager/locale_checker/base_checker"
8
+ require "rails_translation_manager/locale_checker/locale_checker_helper"
9
+ require "rails_translation_manager/locale_checker/missing_foreign_locales"
10
+ require "rails_translation_manager/locale_checker/missing_english_locales"
11
+ require "rails_translation_manager/locale_checker/plural_forms"
12
+ require "rails_translation_manager/locale_checker/incompatible_plurals"
13
+ require "rails_translation_manager/locale_checker/all_locales"
14
+ require "rails_translation_manager/locale_checker"
15
+ require "rails_translation_manager/cleaner"
16
+ require "rails_translation_manager/exporter"
17
+ require "rails_translation_manager/importer"
18
+
5
19
  module RailsTranslationManager
6
- autoload :Exporter, "rails_translation_manager/exporter"
7
- autoload :Importer, "rails_translation_manager/importer"
20
+ rails_i18n_path = Gem::Specification.find_by_name("rails-i18n").gem_dir
21
+ rails_translation_manager = Gem::Specification.find_by_name("rails_translation_manager").gem_dir
22
+
23
+ I18n.load_path.concat(
24
+ Dir["#{rails_i18n_path}/rails/pluralization/*.rb"],
25
+ ["#{rails_translation_manager}/config/locales/plurals.rb"]
26
+ )
8
27
  end
@@ -1,16 +1,9 @@
1
- $LOAD_PATH.unshift(File.expand_path("../.."), __FILE__)
2
1
  require "rails_translation_manager"
2
+ require "i18n/tasks/cli"
3
+ require_relative "../tasks/translation_helper"
3
4
 
4
5
  namespace :translation do
5
6
 
6
- desc "Regenerate all locales from the EN locale - run this after adding keys"
7
- task(:regenerate, [:directory] => [:environment]) do |t, args|
8
- directory = args[:directory] || "tmp/locale_csv"
9
-
10
- Rake::Task["translation:export:all"].invoke(directory)
11
- Rake::Task["translation:import:all"].invoke(directory)
12
- end
13
-
14
7
  desc "Export a specific locale to CSV."
15
8
  task :export, [:directory, :base_locale, :target_locale] => [:environment] do |t, args|
16
9
  FileUtils.mkdir_p(args[:directory]) unless File.exist?(args[:directory])
@@ -37,34 +30,50 @@ namespace :translation do
37
30
  end
38
31
 
39
32
  desc "Import a specific locale CSV to YAML within the app."
40
- task :import, [:locale, :path] => [:environment] do |t, args|
41
- importer = RailsTranslationManager::Importer.new(args[:locale], args[:path], Rails.root.join("config", "locales"))
33
+ task :import, [:csv_path, :multiple_files_per_language] => [:environment] do |t, args|
34
+ import_dir = Rails.root.join("config", "locales")
35
+ csv_path = args[:csv_path]
36
+
37
+ importer = RailsTranslationManager::Importer.new(
38
+ locale: File.basename(args[:csv_path], ".csv"),
39
+ csv_path: csv_path,
40
+ import_directory: Rails.root.join("config", "locales"),
41
+ multiple_files_per_language: args[:multiple_files_per_language] || false
42
+ )
42
43
  importer.import
44
+
45
+ puts "Imported CSV from: #{csv_path} to #{import_dir}"
43
46
  end
44
47
 
45
48
  namespace :import do
46
49
  desc "Import all locale CSV files to YAML within the app."
47
- task :all, [:directory] => [:environment] do |t, args|
48
- directory = args[:directory] || "tmp/locale_csv"
49
- Dir[File.join(directory, "*.csv")].each do |csv_path|
50
- locale = File.basename(csv_path, ".csv")
51
- importer = RailsTranslationManager::Importer.new(locale, csv_path, Rails.root.join("config", "locales"))
50
+ task :all, [:csv_directory, :multiple_files_per_language] => [:environment] do |t, args|
51
+ directory = args[:csv_directory] || "tmp/locale_csv"
52
+ import_dir = Rails.root.join("config", "locales")
53
+
54
+ Dir[Rails.root.join(directory, "*.csv")].each do |csv_path|
55
+ importer = RailsTranslationManager::Importer.new(
56
+ locale: File.basename(csv_path, ".csv"),
57
+ csv_path: csv_path,
58
+ import_directory: import_dir,
59
+ multiple_files_per_language: args[:multiple_files_per_language] || false
60
+ )
52
61
  importer.import
53
62
  end
63
+
64
+ puts "Imported all CSVs from: #{directory} to #{import_dir}"
54
65
  end
55
66
  end
56
67
 
57
- desc "Check translation files for errors"
58
- task :validate do
59
- require 'rails_translation_manager/validator'
60
- logger = Logger.new(STDOUT)
61
- validator = RailsTranslationManager::Validator.new(Rails.root.join('config', 'locales'), logger)
62
- errors = validator.check!
63
- if errors.any?
64
- puts "Found #{errors.size} errors:"
65
- puts errors.map(&:to_s).join("\n")
66
- else
67
- puts "Success! No unexpected interpolation keys found."
68
- end
68
+ desc "Add missing translations"
69
+ task(:add_missing, [:locale] => [:environment]) do |t, args|
70
+ I18n::Tasks::CLI.start(TranslationHelper.new(["add-missing", "--nil-value"], args[:locale]).with_optional_locale)
71
+ RailsTranslationManager::Cleaner.new(Rails.root.join("config", "locales")).clean
72
+ end
73
+
74
+ desc "Normalize translations"
75
+ task(:normalize, [:locale] => [:environment]) do |t, args|
76
+ I18n::Tasks::CLI.start(TranslationHelper.new(["normalize"], args[:locale]).with_optional_locale)
77
+ RailsTranslationManager::Cleaner.new(Rails.root.join("config", "locales")).clean
69
78
  end
70
79
  end
@@ -0,0 +1,11 @@
1
+ class TranslationHelper
2
+
3
+ def initialize(task_options, locale)
4
+ @task_options = task_options
5
+ @locale = locale
6
+ end
7
+
8
+ def with_optional_locale
9
+ @locale ? @task_options << ["-l", @locale] : @task_options
10
+ end
11
+ end
@@ -20,8 +20,11 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_dependency "rails-i18n"
22
22
  spec.add_dependency "activesupport"
23
+ spec.add_dependency "i18n-tasks"
23
24
 
24
- spec.add_development_dependency "bundler", "~> 1.7"
25
+ spec.add_development_dependency "bundler"
25
26
  spec.add_development_dependency "rake", "~> 10.0"
26
27
  spec.add_development_dependency "minitest"
28
+ spec.add_development_dependency "rspec"
29
+ spec.add_development_dependency "byebug"
27
30
  end
@@ -0,0 +1,5 @@
1
+ ---
2
+ en:
3
+ test: key
4
+ key_1: foo
5
+ key_2: bar
@@ -0,0 +1,5 @@
1
+ ---
2
+ en:
3
+ test: key
4
+ key_1: foo
5
+ key_2: bar
@@ -0,0 +1,8 @@
1
+ key,source,translation
2
+ world_location.type.country,Country,Pays
3
+ world_location.fruit,"[Apples, Bananas, Pears]","[Pommes, Bananes, Poires]"
4
+ world_location.things,nil,nil
5
+ world_location.sentiment,:whatever,:bof
6
+ shared.price,123,123
7
+ shared.key1,is true,true
8
+ shared.key2,is false,false
@@ -0,0 +1,12 @@
1
+ ---
2
+ cy:
3
+ in_sync:
4
+ key: bwyd
5
+ second_key: cath
6
+ some_plurals:
7
+ few:
8
+ many:
9
+ one:
10
+ other:
11
+ two:
12
+ zero:
@@ -0,0 +1,8 @@
1
+ ---
2
+ cy:
3
+ in_sync:
4
+ key: food
5
+ second_key: cat
6
+ some_plurals:
7
+ one:
8
+ other:
@@ -0,0 +1,3 @@
1
+ ---
2
+ cy:
3
+ other_test: key
@@ -0,0 +1,6 @@
1
+ ---
2
+ en:
3
+ test: key
4
+ wrong_plural:
5
+ one: correct
6
+ zero: failure
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe RailsTranslationManager::Cleaner do
4
+
5
+ before(:each) do
6
+ FileUtils.cp('spec/locales/cleaner/with_whitespace.yml', 'tmp/')
7
+ end
8
+
9
+ it 'removes whitespace at the end of the line' do
10
+ described_class.new('tmp').clean
11
+ expect(FileUtils.compare_file('tmp/with_whitespace.yml', 'spec/locales/cleaner/clean.yml')).to be_truthy
12
+ end
13
+ end
@@ -0,0 +1,81 @@
1
+ require "spec_helper"
2
+ require "tmpdir"
3
+
4
+ RSpec.describe RailsTranslationManager::Importer do
5
+ let(:import_directory) { Dir.mktmpdir }
6
+
7
+ context "when there is one locale file per language" do
8
+ let(:yaml_translation_data) { YAML.load_file(import_directory + "/fr.yml")["fr"] }
9
+
10
+ before do
11
+ importer = described_class.new(
12
+ locale: "fr",
13
+ csv_path: "spec/locales/importer/fr.csv",
14
+ import_directory: import_directory,
15
+ multiple_files_per_language: false
16
+ )
17
+ importer.import
18
+ end
19
+
20
+ it "creates one YAML file per language" do
21
+ expect(File).to exist(import_directory + "/fr.yml")
22
+ end
23
+
24
+ it "imports nested locales" do
25
+ expected = { "type" => { "country" => "Pays" } }
26
+ expect(yaml_translation_data).to include("world_location" => hash_including(expected))
27
+ end
28
+
29
+ it "imports arrays from CSV as arrays" do
30
+ expected = { "fruit" => ["Pommes", "Bananes", "Poires"] }
31
+ expect(yaml_translation_data).to include("world_location" => hash_including(expected))
32
+ end
33
+
34
+ it "imports string 'nil' as nil" do
35
+ expected = { "things" => nil }
36
+ expect(yaml_translation_data).to include("world_location" => hash_including(expected))
37
+ end
38
+
39
+ it "imports string ':thing' as symbol" do
40
+ expected = { "sentiment" => :bof }
41
+ expect(yaml_translation_data).to include("world_location" => hash_including(expected))
42
+ end
43
+
44
+ it "imports integer strings as integers" do
45
+ expected = { "price" => 123 }
46
+ expect(yaml_translation_data).to include("shared" => hash_including(expected))
47
+ end
48
+
49
+ it "imports boolean values as booleans, not strings" do
50
+ expected = { "key1" => true, "key2" => false }
51
+ expect(yaml_translation_data).to include("shared" => hash_including(expected))
52
+ end
53
+ end
54
+
55
+ context "when there are multiple files per locale" do
56
+ before do
57
+ importer = described_class.new(
58
+ locale: "fr",
59
+ csv_path: "spec/locales/importer/fr.csv",
60
+ import_directory: import_directory,
61
+ multiple_files_per_language: true
62
+ )
63
+ importer.import
64
+ end
65
+
66
+ it "creates multiple YAML files per language in the language's directory" do
67
+ expect(File).to exist(import_directory + "/fr/world_location.yml")
68
+ .and exist(import_directory + "/fr/shared.yml")
69
+ end
70
+
71
+ it "imports only 'world_location' locales to the relevant file" do
72
+ yaml_translation_data = YAML.load_file(import_directory + "/fr/world_location.yml")["fr"]
73
+ expect(yaml_translation_data).to match("world_location" => anything)
74
+ end
75
+
76
+ it "imports only 'shared' locales to the relevant file" do
77
+ yaml_translation_data = YAML.load_file(import_directory + "/fr/shared.yml")["fr"]
78
+ expect(yaml_translation_data).to match("shared" => anything)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe AllLocales do
6
+ context "when there are locale files" do
7
+ it "generates an array of hashes for all locales" do
8
+ expect(described_class.new("spec/locales/out_of_sync/*.yml").generate)
9
+ .to eq(
10
+ [
11
+ { keys: %w[test wrong_plural wrong_plural.one wrong_plural.zero], locale: :en },
12
+ { keys: %w[other_test], locale: :cy }
13
+ ]
14
+ )
15
+ end
16
+ end
17
+
18
+ context "when there aren't any locale files present" do
19
+ it "raises an error" do
20
+ expect { described_class.new("path/to/none/existant/locale/files").generate }
21
+ .to raise_error(AllLocales::NoLocaleFilesFound, 'No locale files found for the supplied path')
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe IncompatiblePlurals do
6
+ context "when there are missing plurals" do
7
+ let(:all_locales) do
8
+ [
9
+ {
10
+ locale: :en,
11
+ keys: %w[browse.some_key.other browse.some_other_key.one]
12
+ }
13
+ ]
14
+ end
15
+
16
+ before do
17
+ allow(PluralForms).to receive(:all).and_return({ en: %i[one other] })
18
+ end
19
+
20
+ it "returns the missing plural forms" do
21
+ expect(described_class.new(all_locales).report)
22
+ .to eq(
23
+ <<~OUTPUT.chomp
24
+ \e[31m[ERROR]\e[0m Incompatible plural forms, for:
25
+
26
+ - 'en', with parent 'browse.some_key'. Expected: [:one, :other], actual: [:other]
27
+
28
+ - 'en', with parent 'browse.some_other_key'. Expected: [:one, :other], actual: [:one]
29
+
30
+ \e[1mIf the keys reported above are not plurals, rename them avoiding plural keywords: #{LocaleCheckerHelper::PLURAL_KEYS}\e[22m
31
+ OUTPUT
32
+ )
33
+ end
34
+ end
35
+
36
+ context "when there aren't any missing plurals" do
37
+ let(:all_locales) do
38
+ [
39
+ {
40
+ locale: :en,
41
+ keys: %w[browse.some_key.other browse.some_key.one]
42
+ }
43
+ ]
44
+ end
45
+
46
+ before do
47
+ allow(PluralForms).to receive(:all).and_return({ en: %i[one other] })
48
+ end
49
+
50
+ it "returns nil" do
51
+ expect(described_class.new(all_locales).report)
52
+ .to be_nil
53
+ end
54
+ end
55
+
56
+ context "when plural forms aren't available for the locales" do
57
+ let(:all_locales) do
58
+ [
59
+ {
60
+ locale: :en,
61
+ keys: %w[browse.some_key.one browse.some_key.other]
62
+ },
63
+ {
64
+ locale: :cy,
65
+ keys: %w[browse.some_key.few
66
+ browse.some_key.many
67
+ browse.some_key.one
68
+ browse.some_key.other
69
+ browse.some_key.two
70
+ browse.some_key.zero]
71
+ }
72
+ ]
73
+ end
74
+
75
+ before do
76
+ allow(PluralForms).to receive(:all).and_return({ cy: nil, en: nil })
77
+ end
78
+
79
+ it "outputs the missing plural forms" do
80
+ expect(described_class.new(all_locales).report)
81
+ .to eq(
82
+ <<~OUTPUT.chomp
83
+ \e[31m[ERROR]\e[0m Incompatible plural forms, for:
84
+
85
+ - \e[31m[ERROR]\e[0m Please add plural form for 'en' <link to future documentation>
86
+
87
+ - \e[31m[ERROR]\e[0m Please add plural form for 'cy' <link to future documentation>
88
+
89
+ \e[1mIf the keys reported above are not plurals, rename them avoiding plural keywords: #{LocaleCheckerHelper::PLURAL_KEYS}\e[22m
90
+ OUTPUT
91
+ )
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe LocaleCheckerHelper do
6
+ include LocaleCheckerHelper
7
+
8
+ describe "#exclude_plurals" do
9
+ it "excludes plural groups" do
10
+ expect(exclude_plurals(%w[key.one key.other]))
11
+ .to eq([])
12
+ end
13
+
14
+ it "doesn't exclude non-plurals" do
15
+ expect(exclude_plurals(%w[thing.bing red.blue]))
16
+ .to eq(%w[thing.bing red.blue])
17
+ end
18
+ end
19
+
20
+ describe "#group_keys" do
21
+ it "groups locales by keys" do
22
+ keys = {
23
+ en: %w[key.first key.second],
24
+ fr: %w[key.first key.second],
25
+ es: %w[key.second]
26
+ }
27
+
28
+ expect(group_keys(keys))
29
+ .to eq(
30
+ {
31
+ %w[key.first key.second] => %i[en fr],
32
+ %w[key.second] => %i[es]
33
+ }
34
+ )
35
+ end
36
+ end
37
+
38
+ describe "#english_keys_excluding_plurals" do
39
+ it "returns english keys excluding plurals" do
40
+ keys = [
41
+ { locale: :en, keys: %w[key.english plural.other] },
42
+ { locale: :fr, keys: %w[key.french] }
43
+ ]
44
+
45
+ expect(english_keys_excluding_plurals(keys))
46
+ .to eq(%w[key.english])
47
+ end
48
+ end
49
+
50
+ describe "#key_is_plural?" do
51
+ it "returns true if key is a plural keyword" do
52
+ expect(key_is_plural?("other"))
53
+ .to eq(true)
54
+ end
55
+
56
+ it "returns false if key isn't a plural keyword" do
57
+ expect(key_is_plural?("random"))
58
+ .to eq(false)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe MissingEnglishLocales do
6
+ context "where there are missing English locales" do
7
+ let(:all_locales) do
8
+ [
9
+ {
10
+ locale: :en,
11
+ keys: %w[browse.same_key]
12
+ },
13
+ {
14
+ locale: :cy,
15
+ keys: %w[browse.same_key browse.extra_key]
16
+ }
17
+ ]
18
+ end
19
+
20
+ it "outputs the missing locales" do
21
+ expect(described_class.new(all_locales).report)
22
+ .to eq(
23
+ <<~OUTPUT.chomp
24
+ \e[31m[ERROR]\e[0m Missing English locales, either remove these keys from the foreign locales or add them to the English locales
25
+
26
+ \e[1mMissing English keys:\e[22m ["browse.extra_key"]
27
+ \e[1mFound in:\e[22m [:cy]
28
+ OUTPUT
29
+ )
30
+ end
31
+ end
32
+
33
+ context "where there aren't missing English locales" do
34
+ let(:all_locales) do
35
+ [
36
+ {
37
+ locale: :en,
38
+ keys: %w[browse.same_key]
39
+ },
40
+ {
41
+ locale: :cy,
42
+ keys: %w[browse.same_key]
43
+ }
44
+ ]
45
+ end
46
+
47
+ it 'outputs nil' do
48
+ expect(described_class.new(all_locales).report)
49
+ .to be_nil
50
+ end
51
+ end
52
+
53
+ context "when there are plurals" do
54
+ let(:all_locales) do
55
+ [
56
+ {
57
+ locale: :en,
58
+ keys: []
59
+ },
60
+ {
61
+ locale: :cy,
62
+ keys: %w[browse.plurals.one browse.fake_plurals.other]
63
+ }
64
+ ]
65
+ end
66
+
67
+ it "doesn't include them in the report" do
68
+ expect(described_class.new(all_locales).report)
69
+ .to be_nil
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe MissingForeignLocales do
6
+ context "when there are missing foreign locales" do
7
+ let(:all_locales) do
8
+ [
9
+ {
10
+ locale: :en,
11
+ keys: %w[browse.same_key browse.extra_nested_key.nest]
12
+ },
13
+ {
14
+ locale: :cy,
15
+ keys: %w[browse.same_key]
16
+ },
17
+ {
18
+ locale: :fr,
19
+ keys: %w[browse.same_key]
20
+ }
21
+ ]
22
+ end
23
+
24
+ before do
25
+ I18n.available_locales << %i[fr]
26
+ end
27
+
28
+ it "outputs the missing locales and groups them by common keys" do
29
+ expect(described_class.new(all_locales).report)
30
+ .to eq(
31
+ <<~OUTPUT.chomp
32
+ \e[31m[ERROR]\e[0m Missing foreign locales, either add these keys to the foreign locales or remove them from the English locales\e[0m
33
+
34
+ \e[1mMissing foreign keys:\e[22m ["browse.extra_nested_key.nest"]
35
+ \e[1mAbsent from:\e[22m [:cy, :fr]
36
+ OUTPUT
37
+ )
38
+ end
39
+ end
40
+
41
+ context "when there aren't missing foreign locales" do
42
+ let(:all_locales) do
43
+ [
44
+ {
45
+ locale: :en,
46
+ keys: %w[browse.same_key]
47
+ },
48
+ {
49
+ locale: :cy,
50
+ keys: %w[browse.same_key]
51
+ }
52
+ ]
53
+ end
54
+
55
+ it "outputs nil" do
56
+ expect(described_class.new(all_locales).report)
57
+ .to be_nil
58
+ end
59
+ end
60
+
61
+ context "when there are plurals" do
62
+ let(:all_locales) do
63
+ [
64
+ {
65
+ locale: :en,
66
+ keys: %w[browse.plurals.one browse.fake_plurals.other]
67
+ },
68
+ {
69
+ locale: :cy,
70
+ keys: []
71
+ }
72
+ ]
73
+ end
74
+
75
+ it "doesn't include them in the report" do
76
+ expect(described_class.new(all_locales).report)
77
+ .to be_nil
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe PluralForms do
6
+ it "returns plural forms" do
7
+ expect(described_class.all).to include(
8
+ { cy: %i[few many one other two zero], en: %i[one other] }
9
+ )
10
+ end
11
+
12
+ context "when there are missing plural forms" do
13
+ around do |example|
14
+ load_path = I18n.load_path
15
+ # strips I18n of all pluralization files (rules)
16
+ I18n.load_path = I18n.load_path.flatten.reject { |path| path =~ /plural/ }
17
+
18
+ example.run
19
+
20
+ I18n.load_path = load_path
21
+ end
22
+
23
+ it "returns nil for associated locales" do
24
+ expect(described_class.all).to include({ cy: nil, en: nil })
25
+ end
26
+ end
27
+ end