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.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +20 -0
- data/Jenkinsfile +3 -1
- data/Rakefile +13 -7
- data/config/locales/plurals.rb +49 -0
- data/lib/rails_translation_manager/cleaner.rb +14 -0
- data/lib/rails_translation_manager/i18n_tasks_option_parser.rb +10 -0
- data/lib/rails_translation_manager/importer.rb +32 -14
- data/lib/rails_translation_manager/locale_checker/all_locales.rb +61 -0
- data/lib/rails_translation_manager/locale_checker/base_checker.rb +13 -0
- data/lib/rails_translation_manager/locale_checker/incompatible_plurals.rb +79 -0
- data/lib/rails_translation_manager/locale_checker/locale_checker_helper.rb +23 -0
- data/lib/rails_translation_manager/locale_checker/missing_english_locales.rb +31 -0
- data/lib/rails_translation_manager/locale_checker/missing_foreign_locales.rb +31 -0
- data/lib/rails_translation_manager/locale_checker/plural_forms.rb +16 -0
- data/lib/rails_translation_manager/locale_checker.rb +50 -0
- data/lib/rails_translation_manager/version.rb +1 -1
- data/lib/rails_translation_manager.rb +21 -3
- data/lib/tasks/translation.rake +43 -42
- data/rails_translation_manager.gemspec +6 -2
- data/spec/locales/cleaner/clean.yml +5 -0
- data/spec/locales/cleaner/with_whitespace.yml +5 -0
- data/spec/locales/importer/fr.csv +8 -0
- data/spec/locales/importer/hy_with_byte_order_mark.csv +4 -0
- data/spec/locales/in_sync/cy/browse.yml +12 -0
- data/spec/locales/in_sync/en/browse.yml +8 -0
- data/spec/locales/out_of_sync/cy.yml +3 -0
- data/spec/locales/out_of_sync/en.yml +6 -0
- data/spec/rails_translation_manager/cleaner_spec.rb +13 -0
- data/spec/rails_translation_manager/importer_spec.rb +93 -0
- data/spec/rails_translation_manager/locale_checker/all_locales_spec.rb +24 -0
- data/spec/rails_translation_manager/locale_checker/incompatible_plurals_spec.rb +94 -0
- data/spec/rails_translation_manager/locale_checker/locale_checker_helper_spec.rb +61 -0
- data/spec/rails_translation_manager/locale_checker/missing_english_locales_spec.rb +72 -0
- data/spec/rails_translation_manager/locale_checker/missing_foreign_locales_spec.rb +80 -0
- data/spec/rails_translation_manager/locale_checker/plural_forms_spec.rb +27 -0
- data/spec/rails_translation_manager/locale_checker_spec.rb +68 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/support/tasks.rb +7 -0
- data/spec/tasks/translation_spec.rb +127 -0
- data/test/rails_translation_manager/yaml_writer_test.rb +2 -0
- data/tmp/.gitkeep +0 -0
- metadata +117 -18
- data/lib/rails_translation_manager/stealer.rb +0 -85
- data/lib/rails_translation_manager/validator.rb +0 -92
- data/test/rails_translation_manager/importer_test.rb +0 -132
- data/test/rails_translation_manager/stealer_test.rb +0 -251
- data/test/rails_translation_manager/validator_test.rb +0 -51
data/lib/tasks/translation.rake
CHANGED
@@ -1,15 +1,9 @@
|
|
1
|
-
require "
|
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, [:
|
40
|
-
|
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, [:
|
47
|
-
directory = args[:
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
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 "
|
71
|
-
task
|
72
|
-
|
73
|
-
|
74
|
-
|
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
|
-
|
77
|
-
|
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"
|
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,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,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
|