rails_translation_manager 0.1.0 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +20 -0
  5. data/Jenkinsfile +3 -1
  6. data/Rakefile +13 -7
  7. data/config/locales/plurals.rb +49 -0
  8. data/lib/rails_translation_manager/cleaner.rb +14 -0
  9. data/lib/rails_translation_manager/i18n_tasks_option_parser.rb +10 -0
  10. data/lib/rails_translation_manager/importer.rb +32 -14
  11. data/lib/rails_translation_manager/locale_checker/all_locales.rb +61 -0
  12. data/lib/rails_translation_manager/locale_checker/base_checker.rb +13 -0
  13. data/lib/rails_translation_manager/locale_checker/incompatible_plurals.rb +79 -0
  14. data/lib/rails_translation_manager/locale_checker/locale_checker_helper.rb +23 -0
  15. data/lib/rails_translation_manager/locale_checker/missing_english_locales.rb +31 -0
  16. data/lib/rails_translation_manager/locale_checker/missing_foreign_locales.rb +31 -0
  17. data/lib/rails_translation_manager/locale_checker/plural_forms.rb +16 -0
  18. data/lib/rails_translation_manager/locale_checker.rb +50 -0
  19. data/lib/rails_translation_manager/version.rb +1 -1
  20. data/lib/rails_translation_manager.rb +21 -3
  21. data/lib/tasks/translation.rake +43 -42
  22. data/rails_translation_manager.gemspec +6 -2
  23. data/spec/locales/cleaner/clean.yml +5 -0
  24. data/spec/locales/cleaner/with_whitespace.yml +5 -0
  25. data/spec/locales/importer/fr.csv +8 -0
  26. data/spec/locales/importer/hy_with_byte_order_mark.csv +4 -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 +93 -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 +127 -0
  43. data/test/rails_translation_manager/yaml_writer_test.rb +2 -0
  44. data/tmp/.gitkeep +0 -0
  45. metadata +117 -18
  46. data/lib/rails_translation_manager/stealer.rb +0 -85
  47. data/lib/rails_translation_manager/validator.rb +0 -92
  48. data/test/rails_translation_manager/importer_test.rb +0 -132
  49. data/test/rails_translation_manager/stealer_test.rb +0 -251
  50. data/test/rails_translation_manager/validator_test.rb +0 -51
@@ -1,15 +1,9 @@
1
- require "rails_translation_manager"
1
+ require "i18n/tasks/cli"
2
+ require_relative "../rails_translation_manager"
3
+ require_relative "../rails_translation_manager/i18n_tasks_option_parser"
2
4
 
3
5
  namespace :translation do
4
6
 
5
- desc "Regenerate all locales from the EN locale - run this after adding keys"
6
- task(:regenerate, [:directory] => [:environment]) do |t, args|
7
- directory = args[:directory] || "tmp/locale_csv"
8
-
9
- Rake::Task["translation:export:all"].invoke(directory)
10
- Rake::Task["translation:import:all"].invoke(directory)
11
- end
12
-
13
7
  desc "Export a specific locale to CSV."
14
8
  task :export, [:directory, :base_locale, :target_locale] => [:environment] do |t, args|
15
9
  FileUtils.mkdir_p(args[:directory]) unless File.exist?(args[:directory])
@@ -36,51 +30,58 @@ namespace :translation do
36
30
  end
37
31
 
38
32
  desc "Import a specific locale CSV to YAML within the app."
39
- task :import, [:locale, :path] => [:environment] do |t, args|
40
- 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
+ )
41
43
  importer.import
44
+
45
+ puts "Imported CSV from: #{csv_path} to #{import_dir}"
42
46
  end
43
47
 
44
48
  namespace :import do
45
49
  desc "Import all locale CSV files to YAML within the app."
46
- task :all, [:directory] => [:environment] do |t, args|
47
- directory = args[:directory] || "tmp/locale_csv"
48
- Dir[File.join(directory, "*.csv")].each do |csv_path|
49
- locale = File.basename(csv_path, ".csv")
50
- 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
+ )
51
61
  importer.import
52
62
  end
53
- end
54
- end
55
63
 
56
- desc "Check translation files for errors"
57
- task :validate do
58
- require 'rails_translation_manager/validator'
59
- logger = Logger.new(STDOUT)
60
- validator = RailsTranslationManager::Validator.new(Rails.root.join('config', 'locales'), logger)
61
- errors = validator.check!
62
- if errors.any?
63
- puts "Found #{errors.size} errors:"
64
- puts errors.map(&:to_s).join("\n")
65
- else
66
- puts "Success! No unexpected interpolation keys found."
64
+ puts "Imported all CSVs from: #{directory} to #{import_dir}"
67
65
  end
68
66
  end
69
67
 
70
- desc "Import and convert a locale file from another app."
71
- task :steal, [:locale, :source_app_path, :mapping_file_path] do |t, args|
72
- stealer = RailsTranslationManager::Stealer.new(args[:locale], args[:source_app_path], args[:mapping_file_path], Rails.root.join('config', 'locales'))
73
- stealer.steal_locale
74
- end
68
+ desc "Add missing translations"
69
+ task(:add_missing, [:locale] => [:environment]) do |t, args|
70
+ option_parser = RailsTranslationManager::I18nTasksOptionParser.new(
71
+ ["add-missing", "--nil-value"], args[:locale]
72
+ ).with_optional_locale
75
73
 
76
- namespace :steal do
77
- desc "Import and convert all locale files from another app."
78
- task :all, [:source_app_path, :mapping_file_path] => [:environment] do |t, args|
79
- I18n.available_locales.reject { |l| l == :en }.each do |locale|
80
- stealer = RailsTranslationManager::Stealer.new(locale.to_s, args[:source_app_path], args[:mapping_file_path], Rails.root.join('config', 'locales'))
81
- stealer.steal_locale
82
- end
83
- end
74
+ I18n::Tasks::CLI.start(option_parser)
75
+ RailsTranslationManager::Cleaner.new(Rails.root.join("config", "locales")).clean
84
76
  end
85
77
 
78
+ desc "Normalize translations"
79
+ task(:normalize, [:locale] => [:environment]) do |t, args|
80
+ option_parser = RailsTranslationManager::I18nTasksOptionParser.new(
81
+ ["normalize"], args[:locale]
82
+ ).with_optional_locale
83
+
84
+ I18n::Tasks::CLI.start(option_parser)
85
+ RailsTranslationManager::Cleaner.new(Rails.root.join("config", "locales")).clean
86
+ end
86
87
  end
@@ -18,10 +18,14 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "rails-i18n"
22
21
  spec.add_dependency "activesupport"
22
+ spec.add_dependency "csv", "~> 3.2"
23
+ spec.add_dependency "i18n-tasks"
24
+ spec.add_dependency "rails-i18n"
23
25
 
24
- spec.add_development_dependency "bundler", "~> 1.7"
26
+ spec.add_development_dependency "bundler"
25
27
  spec.add_development_dependency "rake", "~> 10.0"
26
28
  spec.add_development_dependency "minitest"
29
+ spec.add_development_dependency "rspec"
30
+ spec.add_development_dependency "byebug"
27
31
  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,4 @@
1
+ key,source,translation
2
+ unpublishing.title,The page you're looking for is no longer available,Ձեր փնտրած էջն այլևս հասանելի չէ
3
+ working_group.contact_details,Contact details,Կոնտակտային տվյալներ
4
+ working_group.policies,Policies,Քաղաքականություններ
@@ -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,93 @@
1
+ require "spec_helper"
2
+ require "tmpdir"
3
+
4
+ RSpec.describe RailsTranslationManager::Importer do
5
+ let(:import_directory) { Dir.mktmpdir }
6
+
7
+ it "imports CSV containing a byte order mark" do
8
+ importer = described_class.new(
9
+ locale: "hy",
10
+ csv_path: "spec/locales/importer/hy_with_byte_order_mark.csv",
11
+ import_directory: import_directory,
12
+ multiple_files_per_language: false
13
+ )
14
+ importer.import
15
+
16
+ expect(File).to exist(import_directory + "/hy.yml")
17
+ end
18
+
19
+ context "when there is one locale file per language" do
20
+ let(:yaml_translation_data) { YAML.load_file(import_directory + "/fr.yml")["fr"] }
21
+
22
+ before do
23
+ importer = described_class.new(
24
+ locale: "fr",
25
+ csv_path: "spec/locales/importer/fr.csv",
26
+ import_directory: import_directory,
27
+ multiple_files_per_language: false
28
+ )
29
+ importer.import
30
+ end
31
+
32
+ it "creates one YAML file per language" do
33
+ expect(File).to exist(import_directory + "/fr.yml")
34
+ end
35
+
36
+ it "imports nested locales" do
37
+ expected = { "type" => { "country" => "Pays" } }
38
+ expect(yaml_translation_data).to include("world_location" => hash_including(expected))
39
+ end
40
+
41
+ it "imports arrays from CSV as arrays" do
42
+ expected = { "fruit" => ["Pommes", "Bananes", "Poires"] }
43
+ expect(yaml_translation_data).to include("world_location" => hash_including(expected))
44
+ end
45
+
46
+ it "imports string 'nil' as nil" do
47
+ expected = { "things" => nil }
48
+ expect(yaml_translation_data).to include("world_location" => hash_including(expected))
49
+ end
50
+
51
+ it "imports string ':thing' as symbol" do
52
+ expected = { "sentiment" => :bof }
53
+ expect(yaml_translation_data).to include("world_location" => hash_including(expected))
54
+ end
55
+
56
+ it "imports integer strings as integers" do
57
+ expected = { "price" => 123 }
58
+ expect(yaml_translation_data).to include("shared" => hash_including(expected))
59
+ end
60
+
61
+ it "imports boolean values as booleans, not strings" do
62
+ expected = { "key1" => true, "key2" => false }
63
+ expect(yaml_translation_data).to include("shared" => hash_including(expected))
64
+ end
65
+ end
66
+
67
+ context "when there are multiple files per locale" do
68
+ before do
69
+ importer = described_class.new(
70
+ locale: "fr",
71
+ csv_path: "spec/locales/importer/fr.csv",
72
+ import_directory: import_directory,
73
+ multiple_files_per_language: true
74
+ )
75
+ importer.import
76
+ end
77
+
78
+ it "creates multiple YAML files per language in the language's directory" do
79
+ expect(File).to exist(import_directory + "/fr/world_location.yml")
80
+ .and exist(import_directory + "/fr/shared.yml")
81
+ end
82
+
83
+ it "imports only 'world_location' locales to the relevant file" do
84
+ yaml_translation_data = YAML.load_file(import_directory + "/fr/world_location.yml")["fr"]
85
+ expect(yaml_translation_data).to match("world_location" => anything)
86
+ end
87
+
88
+ it "imports only 'shared' locales to the relevant file" do
89
+ yaml_translation_data = YAML.load_file(import_directory + "/fr/shared.yml")["fr"]
90
+ expect(yaml_translation_data).to match("shared" => anything)
91
+ end
92
+ end
93
+ 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