rails_translation_manager 1.5.2 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0586632094e19c18a2fef0977554080b300afd1b590b25396f7212bc699bcf49'
4
- data.tar.gz: b40d1c4a33d1ab35e2dd997a28dbf1cf43303e96ef12b87b6f309038bee63754
3
+ metadata.gz: 96e105c50ae765f973ec2993ec1321ed96bd41594bca178dea8d7f411bf20414
4
+ data.tar.gz: cc4d21ec122aa9f69e33e83793eb8c4f04f70ed07dbba2ebeeb4c17a8c2e436e
5
5
  SHA512:
6
- metadata.gz: 6f99d23e8366b0d646d0e2e273cc2919cbf156b5b82a28de499ea4195f8c34ec956e00e118c8eefe09a378a07417bba8f7d6197c91559442e43f649081b63c94
7
- data.tar.gz: f1e76272d20dad72b019f078302329137308072e44054174591de882db82826f9fd9aca7c71df6a11d238b750e69039092316788e11d960172e7a673f9a01538
6
+ metadata.gz: f19d4c1ad7adbf432fb17143cd3ea7a2c22758ef15b45b6e875f2f53b3bd8010ccf19fc91cb789115c6c3a5b779a14c8d23b21888a3a073295eedc0de6a6f83c
7
+ data.tar.gz: 339310d4341e0f77cc6aeacbd06e51da634e251ee164bfd4055a3707d6f38c0fd007623cf9dd548d1d69690c724d3b94bd721d10758ea3e832608299596db5c4
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: /
5
+ schedule:
6
+ interval: daily
@@ -0,0 +1,36 @@
1
+ on: [push, pull_request]
2
+
3
+ jobs:
4
+ # This matrix job runs the test suite against multiple Ruby versions
5
+ test_matrix:
6
+ strategy:
7
+ fail-fast: false
8
+ matrix:
9
+ # Due to https://github.com/actions/runner/issues/849, we have to use quotes for '3.0'
10
+ ruby: [ 2.7, '3.0', 3.1 ]
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v2
14
+ - uses: ruby/setup-ruby@v1
15
+ with:
16
+ ruby-version: ${{ matrix.ruby }}
17
+ bundler-cache: true
18
+ - run: bundle exec rake
19
+
20
+ # Branch protection rules cannot directly depend on status checks from matrix jobs.
21
+ # So instead we define `test` as a dummy job which only runs after the preceding `test_matrix` checks have passed.
22
+ # Solution inspired by: https://github.community/t/status-check-for-a-matrix-jobs/127354/3
23
+ test:
24
+ needs: test_matrix
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ - run: echo "All matrix tests have passed 🚀"
28
+
29
+ publish:
30
+ needs: test
31
+ if: ${{ github.ref == 'refs/heads/main' }}
32
+ permissions:
33
+ contents: write
34
+ uses: alphagov/govuk-infrastructure/.github/workflows/publish-rubygem.yaml@main
35
+ secrets:
36
+ GEM_HOST_API_KEY: ${{ secrets.ALPHAGOV_RUBYGEMS_API_KEY }}
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # 1.6.0
2
+
3
+ Update plural file loading https://github.com/alphagov/rails_translation_manager/pull/52
4
+ Update missing English keys checker https://github.com/alphagov/rails_translation_manager/pull/53
5
+ Add missing plurals for Welsh, Maltese and Hong Kong Chinese.
6
+ * https://github.com/alphagov/rails_translation_manager/pull/49
7
+ * https://github.com/alphagov/rails_translation_manager/pull/50
8
+
1
9
  # 1.5.2
2
10
 
3
11
  Add missing plurals for Gujarati and Yiddish https://github.com/alphagov/rails_translation_manager/pull/44
@@ -1,6 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  {
4
+ # Welsh
5
+ cy: { i18n: { plural: { keys: %i[zero one two few many other],
6
+ rule:
7
+ lambda do |n|
8
+ case n
9
+ when 0 then :zero
10
+ when 1 then :one
11
+ when 2 then :two
12
+ when 3 then :few
13
+ when 6 then :many
14
+ else :other
15
+ end
16
+ end } } },
4
17
  # Dari - this isn't an iso code. Probably should be 'prs' as per ISO 639-3.
5
18
  dr: { i18n: { plural: { keys: %i[one other], rule: ->(n) { n == 1 ? :one : :other } } } },
6
19
  # Latin America and Caribbean Spanish
@@ -25,6 +38,23 @@
25
38
  # Kazakh
26
39
  kk: { i18n: { plural: { keys: %i[one other], rule: ->(n) { n == 1 ? :one : :other } } } },
27
40
  # Pashto
41
+ # Maltese
42
+ mt: { i18n: { plural: { keys: %i[one few many other],
43
+ rule:
44
+ lambda do |n|
45
+ n ||= 0
46
+ mod100 = n % 100
47
+
48
+ if n == 1
49
+ :one
50
+ elsif n.zero? || (2..10).to_a.include?(mod100)
51
+ :few
52
+ elsif (11..19).to_a.include?(mod100)
53
+ :many
54
+ else
55
+ :other
56
+ end
57
+ end } } },
28
58
  ps: { i18n: { plural: { keys: %i[one other], rule: ->(n) { n == 1 ? :one : :other } } } },
29
59
  # Punjabi Shahmukhi
30
60
  "pa-pk": { i18n: { plural: { keys: %i[one other], rule: ->(n) { [0, 1].include?(n) ? :one : :other } } } },
@@ -44,6 +74,8 @@
44
74
  uz: { i18n: { plural: { keys: %i[one other], rule: ->(n) { n == 1 ? :one : :other } } } },
45
75
  # Yiddish
46
76
  yi: { i18n: { plural: { keys: %i[one other], rule: ->(n) { [0, 1].include?(n) ? :one : :other } } } },
77
+ # Chinese
78
+ zh: { i18n: { plural: { keys: %i[other], rule: ->(_) { :other } } } },
47
79
  # Chinese Hong Kong
48
80
  'zh-hk' => { i18n: { plural: { keys: %i[other], rule: -> { :other } } } },
49
81
  # Chinese Taiwan
@@ -13,19 +13,23 @@ class MissingEnglishLocales < BaseChecker
13
13
 
14
14
  def format_missing_english_locales(keys)
15
15
  formatted_keys = keys.to_a.map do |group|
16
- "\e[1mMissing English keys:\e[22m #{group[0]}\n\e[1mFound in:\e[22m #{group[1]}"
16
+ "\e[1mMissing English locales:\e[22m #{group[0]}\n\e[1mFound in:\e[22m #{group[1]}"
17
17
  end
18
18
 
19
- "\e[31m[ERROR]\e[0m Missing English locales, either remove these keys from the foreign locales or add them to the English locales\n\n#{formatted_keys.join("\n\n")}"
19
+ "\e[31m[ERROR]\e[0m Missing English locales, either remove them from the foreign locale files or add them to the English locale files\n\n#{formatted_keys.join("\n\n")}"
20
20
  end
21
21
 
22
22
  def missing_english_locales
23
- all_locales.each_with_object({}) do |locale, hsh|
24
- missing_keys = exclude_plurals(locale[:keys]) - english_keys_excluding_plurals(all_locales)
23
+ all_locales.each_with_object({}) do |group, hsh|
24
+ next if group[:locale] == :en
25
+
26
+ keys = exclude_plurals(group[:keys])
27
+
28
+ missing_keys = keys.reject { |key| I18n.exists?(key) }
25
29
 
26
30
  next if missing_keys.blank?
27
31
 
28
- hsh[locale[:locale]] = missing_keys
32
+ hsh[group[:locale]] = missing_keys
29
33
  end
30
34
  end
31
35
  end
@@ -4,7 +4,7 @@ class PluralForms
4
4
  def self.all
5
5
  I18n.available_locales.each_with_object({}) do |locale, hsh|
6
6
  begin
7
- # fetches plural form (rule) from rails-i18n for locale
7
+ # fetches plural form (rule) from rails-i18n or config/locales/plurals.rb for locale
8
8
  plural_form = I18n.with_locale(locale) { I18n.t!("i18n.plural.keys") }.sort
9
9
  rescue I18n::MissingTranslationData
10
10
  plural_form = nil
@@ -1,3 +1,3 @@
1
1
  module RailsTranslationManager
2
- VERSION = "1.5.2"
2
+ VERSION = "1.6.0"
3
3
  end
@@ -20,13 +20,9 @@ require "rails_translation_manager/exporter"
20
20
  require "rails_translation_manager/importer"
21
21
 
22
22
  module RailsTranslationManager
23
- rails_i18n_path = Gem::Specification.find_by_name("rails-i18n").gem_dir
24
23
  rails_translation_manager = Gem::Specification.find_by_name("rails_translation_manager").gem_dir
25
24
 
26
- I18n.load_path.concat(
27
- Dir["#{rails_i18n_path}/rails/pluralization/*.rb"],
28
- ["#{rails_translation_manager}/config/locales/plurals.rb"]
29
- )
25
+ I18n.load_path += ["#{rails_translation_manager}/config/locales/plurals.rb"]
30
26
 
31
27
  def self.locale_root
32
28
  if ENV["RAILS_TRANSLATION_MANAGER_LOCALE_ROOT"]
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  spec.add_development_dependency "bundler"
27
27
  spec.add_development_dependency "climate_control"
28
- spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rake", "~> 13.0"
29
29
  spec.add_development_dependency "minitest"
30
30
  spec.add_development_dependency "rspec"
31
31
  spec.add_development_dependency "byebug"
@@ -1,5 +1,5 @@
1
1
  ---
2
- cy:
2
+ en:
3
3
  in_sync:
4
4
  key: food
5
5
  second_key: cat
@@ -32,73 +32,81 @@ RSpec.describe RailsTranslationManager::Importer do
32
32
  context "when there is one locale file per language" do
33
33
  let(:yaml_translation_data) { YAML.load_file(import_directory + "/fr.yml")["fr"] }
34
34
 
35
- before do
36
- importer = described_class.new(
35
+ let(:importer) do
36
+ described_class.new(
37
37
  locale: "fr",
38
38
  csv_path: "spec/locales/importer/fr.csv",
39
39
  import_directory: import_directory,
40
40
  multiple_files_per_language: false
41
41
  )
42
- importer.import
43
42
  end
44
43
 
45
44
  it "creates one YAML file per language" do
45
+ expect { importer.import }.to output.to_stdout
46
46
  expect(File).to exist(import_directory + "/fr.yml")
47
47
  end
48
48
 
49
49
  it "imports nested locales" do
50
+ expect { importer.import }.to output.to_stdout
50
51
  expected = { "type" => { "country" => "Pays" } }
51
52
  expect(yaml_translation_data).to include("world_location" => hash_including(expected))
52
53
  end
53
54
 
54
55
  it "imports arrays from CSV as arrays" do
56
+ expect { importer.import }.to output.to_stdout
55
57
  expected = { "fruit" => ["Pommes", "Bananes", "Poires"] }
56
58
  expect(yaml_translation_data).to include("world_location" => hash_including(expected))
57
59
  end
58
60
 
59
61
  it "imports string 'nil' as nil" do
62
+ expect { importer.import }.to output.to_stdout
60
63
  expected = { "things" => nil }
61
64
  expect(yaml_translation_data).to include("world_location" => hash_including(expected))
62
65
  end
63
66
 
64
67
  it "imports string ':thing' as symbol" do
68
+ expect { importer.import }.to output.to_stdout
65
69
  expected = { "sentiment" => :bof }
66
70
  expect(yaml_translation_data).to include("world_location" => hash_including(expected))
67
71
  end
68
72
 
69
73
  it "imports integer strings as integers" do
74
+ expect { importer.import }.to output.to_stdout
70
75
  expected = { "price" => 123 }
71
76
  expect(yaml_translation_data).to include("shared" => hash_including(expected))
72
77
  end
73
78
 
74
79
  it "imports boolean values as booleans, not strings" do
80
+ expect { importer.import }.to output.to_stdout
75
81
  expected = { "key1" => true, "key2" => false }
76
82
  expect(yaml_translation_data).to include("shared" => hash_including(expected))
77
83
  end
78
84
  end
79
85
 
80
86
  context "when there are multiple files per locale" do
81
- before do
82
- importer = described_class.new(
87
+ let(:importer) do
88
+ described_class.new(
83
89
  locale: "fr",
84
90
  csv_path: "spec/locales/importer/fr.csv",
85
91
  import_directory: import_directory,
86
92
  multiple_files_per_language: true
87
93
  )
88
- importer.import
89
94
  end
90
95
 
91
96
  it "creates multiple YAML files per language in the language's directory" do
97
+ expect { importer.import }.to output.to_stdout
92
98
  expect(File).to exist(import_directory + "/fr/world_location.yml")
93
99
  .and exist(import_directory + "/fr/shared.yml")
94
100
  end
95
101
 
96
102
  it "imports only 'world_location' locales to the relevant file" do
103
+ expect { importer.import }.to output.to_stdout
97
104
  yaml_translation_data = YAML.load_file(import_directory + "/fr/world_location.yml")["fr"]
98
105
  expect(yaml_translation_data).to match("world_location" => anything)
99
106
  end
100
107
 
101
108
  it "imports only 'shared' locales to the relevant file" do
109
+ expect { importer.import }.to output.to_stdout
102
110
  yaml_translation_data = YAML.load_file(import_directory + "/fr/shared.yml")["fr"]
103
111
  expect(yaml_translation_data).to match("shared" => anything)
104
112
  end
@@ -4,6 +4,12 @@ require "spec_helper"
4
4
 
5
5
  RSpec.describe MissingEnglishLocales do
6
6
  context "where there are missing English locales" do
7
+ before do
8
+ I18n.backend.store_translations :en, { browse: { same_key: "value" } }
9
+ I18n.backend.store_translations :cy, { browse: { same_key: "value" } }
10
+ I18n.backend.store_translations :cy, { browse: { extra_key: "extra_key" } }
11
+ end
12
+
7
13
  let(:all_locales) do
8
14
  [
9
15
  {
@@ -21,9 +27,9 @@ RSpec.describe MissingEnglishLocales do
21
27
  expect(described_class.new(all_locales).report)
22
28
  .to eq(
23
29
  <<~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
30
+ \e[31m[ERROR]\e[0m Missing English locales, either remove them from the foreign locale files or add them to the English locale files
25
31
 
26
- \e[1mMissing English keys:\e[22m ["browse.extra_key"]
32
+ \e[1mMissing English locales:\e[22m ["browse.extra_key"]
27
33
  \e[1mFound in:\e[22m [:cy]
28
34
  OUTPUT
29
35
  )
@@ -31,6 +37,11 @@ RSpec.describe MissingEnglishLocales do
31
37
  end
32
38
 
33
39
  context "where there aren't missing English locales" do
40
+ before do
41
+ I18n.backend.store_translations :en, { browse: { same_key: "value" } }
42
+ I18n.backend.store_translations :cy, { browse: { same_key: "value" } }
43
+ end
44
+
34
45
  let(:all_locales) do
35
46
  [
36
47
  {
@@ -21,6 +21,9 @@ RSpec.describe PluralForms do
21
21
  end
22
22
 
23
23
  it "returns nil for associated locales" do
24
+ # clears any in-memory translations
25
+ I18n.backend.reload!
26
+
24
27
  expect(described_class.all).to include({ cy: nil, en: nil })
25
28
  end
26
29
  end
@@ -4,12 +4,19 @@ require "spec_helper"
4
4
 
5
5
  RSpec.describe RailsTranslationManager::LocaleChecker do
6
6
  context "when the locales are valid" do
7
+ before do
8
+ I18n.backend.load_translations(
9
+ ["spec/locales/in_sync/cy/browse.yml", "spec/locales/in_sync/en/browse.yml"]
10
+ )
11
+ end
12
+
7
13
  it "calls each checker class" do
8
14
  described_class::CHECKER_CLASSES.each do |checker|
9
15
  expect_any_instance_of(checker).to receive(:report)
10
16
  end
11
17
 
12
- described_class.new("spec/locales/in_sync/**/*.yml").validate_locales
18
+ expect { described_class.new("spec/locales/in_sync/**/*.yml").validate_locales }
19
+ .to output.to_stdout
13
20
  end
14
21
 
15
22
  it "outputs a confirmation" do
@@ -18,51 +25,51 @@ RSpec.describe RailsTranslationManager::LocaleChecker do
18
25
  end
19
26
 
20
27
  it "returns true" do
21
- expect(described_class.new("spec/locales/in_sync/**/*.yml").validate_locales)
22
- .to eq(true)
28
+ outcome = nil
29
+ expect { outcome = described_class.new("spec/locales/in_sync/**/*.yml").validate_locales }.to output.to_stdout
30
+ expect(outcome).to be(true)
23
31
  end
24
32
  end
25
33
 
26
34
  context "when the locales are not valid" do
35
+ before do
36
+ I18n.backend.load_translations(
37
+ ["spec/locales/out_of_sync/cy.yml", "spec/locales/out_of_sync/en.yml"]
38
+ )
39
+ end
40
+
27
41
  it "calls each checker class" do
28
42
  described_class::CHECKER_CLASSES.each do |checker|
29
43
  expect_any_instance_of(checker).to receive(:report)
30
44
  end
31
45
 
32
- described_class.new("spec/locales/out_of_sync/*.yml").validate_locales
46
+ expect { described_class.new("spec/locales/out_of_sync/*.yml").validate_locales }
47
+ .to output.to_stdout
33
48
  end
34
49
 
35
50
  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)
51
+ # expect output to contain 3 errors ([ERROR])
52
+ expect { described_class.new("spec/locales/out_of_sync/*.yml").validate_locales }
53
+ .to output(/(?:\[ERROR\](?:.|\n)*){3}/).to_stdout
41
54
  end
42
55
 
43
56
  it "returns false" do
44
- expect(described_class.new("spec/locales/out_of_sync/*.yml").validate_locales)
45
- .to eq(false)
57
+ outcome = nil
58
+ expect { outcome = described_class.new("spec/locales/out_of_sync/*.yml").validate_locales }.to output.to_stdout
59
+ expect(outcome).to be(false)
46
60
  end
47
61
  end
48
62
 
49
63
  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
64
  it "outputs an error message" do
59
65
  expect { described_class.new("some/random/path").validate_locales }
60
66
  .to output("No locale files found for the supplied path\n").to_stdout
61
67
  end
62
68
 
63
69
  it "returns false" do
64
- expect(described_class.new("some/random/path").validate_locales)
65
- .to eq(false)
70
+ outcome = nil
71
+ expect { outcome = described_class.new("some/random/path").validate_locales }.to output.to_stdout
72
+ expect(outcome).to be(false)
66
73
  end
67
74
  end
68
75
  end
data/spec/spec_helper.rb CHANGED
@@ -6,15 +6,23 @@ require "climate_control"
6
6
  RSpec.configure do |config|
7
7
  config.before do
8
8
  I18n.available_locales = %i[en cy]
9
- config.before { allow($stdout).to receive(:puts) }
10
- end
9
+ I18n.backend.store_translations :en, i18n: { plural: { keys: %i[one other],
10
+ rule:
11
+ lambda do |n|
12
+ n == 1 ? :one : :other
13
+ end } }
14
+ I18n.backend.store_translations :cy, i18n: { plural: { keys: %i[zero one two few many other],
15
+ rule:
16
+ lambda do |n|
17
+ case n
18
+ when 0 then :zero
19
+ when 1 then :one
20
+ when 2 then :two
21
+ when 3 then :few
22
+ when 6 then :many
23
+ else :other
24
+ end
25
+ end } }
11
26
 
12
- def capture_stdout(&blk)
13
- old = $stdout
14
- $stdout = fake = StringIO.new
15
- blk.call
16
- fake.string
17
- ensure
18
- $stdout = old
19
27
  end
20
28
  end
@@ -20,7 +20,7 @@ describe "rake tasks" do
20
20
  end
21
21
 
22
22
  it "calls the Importer class with the csv and import paths" do
23
- task.execute(csv_path: csv_path)
23
+ expect { task.execute(csv_path: csv_path) }.to output.to_stdout
24
24
 
25
25
  expect(RailsTranslationManager::Importer)
26
26
  .to have_received(:new)
@@ -44,7 +44,10 @@ describe "rake tasks" do
44
44
  end
45
45
 
46
46
  it "calls the importer class for each target path" do
47
- task.execute(csv_directory: csv_directory, multiple_files_per_language: true)
47
+ expect { task.execute(csv_directory: csv_directory, multiple_files_per_language: true) }
48
+ .to output
49
+ .to_stdout
50
+
48
51
  import_paths = Dir["spec/locales/importer/*.csv"]
49
52
 
50
53
  import_paths.each do |csv_path|
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: 1.5.2
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Edd Sowden
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-07 00:00:00.000000000 Z
11
+ date: 2022-11-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '10.0'
103
+ version: '13.0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '10.0'
110
+ version: '13.0'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: minitest
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -157,11 +157,12 @@ executables: []
157
157
  extensions: []
158
158
  extra_rdoc_files: []
159
159
  files:
160
+ - ".github/dependabot.yml"
161
+ - ".github/workflows/ci.yml"
160
162
  - ".gitignore"
161
163
  - ".ruby-version"
162
164
  - CHANGELOG.md
163
165
  - Gemfile
164
- - Jenkinsfile
165
166
  - LICENSE.txt
166
167
  - README.md
167
168
  - Rakefile
@@ -235,7 +236,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
235
236
  - !ruby/object:Gem::Version
236
237
  version: '0'
237
238
  requirements: []
238
- rubygems_version: 3.1.6
239
+ rubygems_version: 3.3.26
239
240
  signing_key:
240
241
  specification_version: 4
241
242
  summary: Tasks to manage translation files
data/Jenkinsfile DELETED
@@ -1,9 +0,0 @@
1
- #!/usr/bin/env groovy
2
-
3
- library("govuk")
4
-
5
- node {
6
- govuk.buildProject(
7
- cleanWorkspace: true,
8
- )
9
- }