i18n-js 4.0.0.alpha3 → 4.0.0.alpha4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7e0fd83a034e8eaa82e97f46beb39a96da4d671952762f7751d093d4823e1aed
4
- data.tar.gz: acff26df94aa46c0c50d5864c97b32bc1108a611a748c2dd7fff4d626ec41cf4
3
+ metadata.gz: 3ecf4853a33adc9a67520a585c733a55e7b05e07bdc436830c519213bfc728b6
4
+ data.tar.gz: 5a1b68a4182bc30fcc3c57438ab226ba72a97a7f16dd6c29ac938106f4c5e00c
5
5
  SHA512:
6
- metadata.gz: d72a28ddbe75742e605c86d8e3b06ce2e1ada21bc95f2b189e2e120b671c7c0d4d239dfc7c3753abd4b97f57820146001cfdfb89e2c407ae3054ea93fba98d72
7
- data.tar.gz: 5ed38c2ea91915fadcc6cc7a4b718d1473cc41afff0c5cd3f6dd6e1345e2eed29c53bace6403239dd516a180485b055414cd65c00291747d20c6055c6b2f6a2a
6
+ metadata.gz: f8468f07c440fa8c29c84a6550ef8b7d5914cf08ce93d0b02f77caf65838a4057f8a7653cc221c33a1dfaf1ab0486aa195a368248ca9509af4af7071ab76ddaa
7
+ data.tar.gz: cb3822d5fe66aa90b20a4a596869a0adb93c3154d5877f66b1374794961536bc2916c051f8d5ce5f61d2d57c66951c25b477f8b808b7d737b39941875e545afb
@@ -4,8 +4,6 @@ name: ruby-tests
4
4
  on:
5
5
  pull_request_target:
6
6
  push:
7
- branches:
8
- - v4
9
7
  workflow_dispatch:
10
8
  inputs: {}
11
9
 
data/README.md CHANGED
@@ -82,14 +82,35 @@ I18nJS.call(config: config)
82
82
  The CLI API:
83
83
 
84
84
  ```console
85
- $ i18n init --config config/i18n.yml
86
- $ i18n export --config config/i18n.yml --require config/environment.rb
85
+ $ i18n --help
86
+ Usage: i18n COMMAND FLAGS
87
+
88
+ Commands:
89
+
90
+ - init: Initialize a project
91
+ - export: Export translations as JSON files
92
+ - version: Show package version
93
+ - check: Check for missing translations
94
+
95
+ Run `i18n COMMAND --help` for more information on specific commands.
87
96
  ```
88
97
 
89
98
  By default, `i18n` will use `config/i18n.yml` and `config/environment.rb` as the
90
99
  configuration files. If you don't have these files, then you'll need to specify
91
100
  both `--config` and `--require`.
92
101
 
102
+ ### Listing missing translations
103
+
104
+ To list missing and extraneous translations, you can use `i18n check`. This
105
+ command will load your translations similarly to how `i18n export` does, but
106
+ will output the list of keys that don't have a matching translation against the
107
+ default locale. Here's an example:
108
+
109
+ ![`i18n check` command in action](https://github.com/fnando/i18n-js/raw/main/images/i18njs-check.gif)
110
+
111
+ This command will exist with status 1 whenever there are missing translations.
112
+ This way you can use it as a CI linting.
113
+
93
114
  ## Automatically export translations
94
115
 
95
116
  ### Using watchman
Binary file
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "benchmark"
4
+
5
+ module I18nJS
6
+ class CLI
7
+ class CheckCommand < Command
8
+ command_name "check"
9
+ description "Check for missing translations"
10
+
11
+ parse do |opts|
12
+ opts.banner = "Usage: i18n #{name} [options]"
13
+
14
+ opts.on(
15
+ "-cCONFIG_FILE",
16
+ "--config=CONFIG_FILE",
17
+ "The configuration file that will be used"
18
+ ) do |config_file|
19
+ options[:config_file] = config_file
20
+ end
21
+
22
+ opts.on(
23
+ "-rREQUIRE_FILE",
24
+ "--require=REQUIRE_FILE",
25
+ "A Ruby file that must be loaded"
26
+ ) do |require_file|
27
+ options[:require_file] = require_file
28
+ end
29
+
30
+ opts.on(
31
+ "--[no-]color",
32
+ "Force colored output"
33
+ ) do |colored|
34
+ options[:colored] = colored
35
+ end
36
+
37
+ opts.on("-h", "--help", "Prints this help") do
38
+ ui.exit_with opts.to_s
39
+ end
40
+ end
41
+
42
+ command do
43
+ set_defaults!
44
+ ui.colored = options[:colored]
45
+
46
+ unless options[:config_file]
47
+ ui.fail_with("=> ERROR: you need to specify the config file")
48
+ end
49
+
50
+ ui.stdout_print("=> Config file:", options[:config_file].inspect)
51
+ config_file = File.expand_path(options[:config_file])
52
+
53
+ if options[:require_file]
54
+ ui.stdout_print("=> Require file:", options[:require_file].inspect)
55
+ require_file = File.expand_path(options[:require_file])
56
+ end
57
+
58
+ unless File.file?(config_file)
59
+ ui.fail_with(
60
+ "=> ERROR: config file doesn't exist at",
61
+ config_file.inspect
62
+ )
63
+ end
64
+
65
+ if require_file && !File.file?(require_file)
66
+ ui.fail_with(
67
+ "=> ERROR: require file doesn't exist at",
68
+ require_file.inspect
69
+ )
70
+ end
71
+
72
+ load_require_file!(require_file) if require_file
73
+ default_locale = I18n.default_locale
74
+ available_locales = I18n.available_locales
75
+
76
+ mapping = available_locales.each_with_object({}) do |locale, buffer|
77
+ buffer[locale] =
78
+ Glob::Map.call(Glob.filter(I18nJS.translations, ["#{locale}.*"]))
79
+ .map {|key| key.gsub(/^.*?\./, "") }
80
+ end
81
+
82
+ default_locale_keys = mapping.delete(default_locale)
83
+
84
+ ui.stdout_print "=> #{default_locale}: #{default_locale_keys.size} " \
85
+ "translations"
86
+
87
+ total_missing_count = 0
88
+
89
+ mapping.each do |locale, partial_keys|
90
+ extraneous = partial_keys - default_locale_keys
91
+ missing = default_locale_keys - (partial_keys - extraneous)
92
+ total_missing_count += missing.size
93
+ ui.stdout_print "=> #{locale}: #{missing.size} missing, " \
94
+ "#{extraneous.size} extraneous"
95
+
96
+ all_keys = (default_locale_keys + extraneous + missing).uniq.sort
97
+
98
+ all_keys.each do |key|
99
+ label = if extraneous.include?(key)
100
+ ui.yellow("extraneous")
101
+ elsif missing.include?(key)
102
+ ui.red("missing")
103
+ else
104
+ next
105
+ end
106
+
107
+ ui.stdout_print(" - #{locale}.#{key} (#{label})")
108
+ end
109
+ end
110
+
111
+ exit(1) if total_missing_count.nonzero?
112
+ end
113
+
114
+ private def set_defaults!
115
+ config_file = "./config/i18n.yml"
116
+ require_file = "./config/environment.rb"
117
+
118
+ options[:config_file] ||= config_file if File.file?(config_file)
119
+ options[:require_file] ||= require_file if File.file?(require_file)
120
+ end
121
+ end
122
+ end
123
+ end
@@ -38,6 +38,32 @@ module I18nJS
38
38
  def options
39
39
  @options ||= {}
40
40
  end
41
+
42
+ private def load_require_file!(require_file)
43
+ require_without_warnings(require_file)
44
+ rescue Exception => error # rubocop:disable Lint/RescueException
45
+ ui.stderr_print("=> ERROR: couldn't load",
46
+ options[:require_file].inspect)
47
+ ui.fail_with(
48
+ "\n#{error_description(error)}\n#{error.backtrace.join("\n")}"
49
+ )
50
+ end
51
+
52
+ private def error_description(error)
53
+ [
54
+ error.class.name,
55
+ error.message
56
+ ].reject(&:empty?).join(" => ")
57
+ end
58
+
59
+ private def require_without_warnings(path)
60
+ old_verbose = $VERBOSE
61
+ $VERBOSE = nil
62
+
63
+ load path
64
+ ensure
65
+ $VERBOSE = old_verbose
66
+ end
41
67
  end
42
68
  end
43
69
  end
@@ -14,7 +14,7 @@ module I18nJS
14
14
  opts.on(
15
15
  "-cCONFIG_FILE",
16
16
  "--config=CONFIG_FILE",
17
- "The configuration file that will be generated"
17
+ "The configuration file that will be used"
18
18
  ) do |config_file|
19
19
  options[:config_file] = config_file
20
20
  end
@@ -35,16 +35,15 @@ module I18nJS
35
35
  command do
36
36
  set_defaults!
37
37
 
38
- ui.stdout_print("=> config file:", options[:config_file].inspect)
39
- ui.stdout_print("=> require file:", options[:require_file].inspect)
40
-
41
38
  unless options[:config_file]
42
39
  ui.fail_with("=> ERROR: you need to specify the config file")
43
40
  end
44
41
 
42
+ ui.stdout_print("=> Config file:", options[:config_file].inspect)
45
43
  config_file = File.expand_path(options[:config_file])
46
44
 
47
45
  if options[:require_file]
46
+ ui.stdout_print("=> Require file:", options[:require_file].inspect)
48
47
  require_file = File.expand_path(options[:require_file])
49
48
  end
50
49
 
@@ -67,7 +66,7 @@ module I18nJS
67
66
  I18nJS.call(config_file: config_file)
68
67
  end
69
68
 
70
- ui.stdout_print("=> done in #{time.round(2)}s")
69
+ ui.stdout_print("=> Done in #{time.round(2)}s")
71
70
  end
72
71
 
73
72
  private def set_defaults!
@@ -77,32 +76,6 @@ module I18nJS
77
76
  options[:config_file] ||= config_file if File.file?(config_file)
78
77
  options[:require_file] ||= require_file if File.file?(require_file)
79
78
  end
80
-
81
- private def load_require_file!(require_file)
82
- require_without_warnings(require_file)
83
- rescue Exception => error # rubocop:disable Lint/RescueException
84
- ui.stderr_print("=> ERROR: couldn't load",
85
- options[:require_file].inspect)
86
- ui.fail_with(
87
- "\n#{error_description(error)}\n#{error.backtrace.join("\n")}"
88
- )
89
- end
90
-
91
- private def error_description(error)
92
- [
93
- error.class.name,
94
- error.message
95
- ].reject(&:empty?).join(" => ")
96
- end
97
-
98
- private def require_without_warnings(path)
99
- old_verbose = $VERBOSE
100
- $VERBOSE = nil
101
-
102
- require path
103
- ensure
104
- $VERBOSE = old_verbose
105
- end
106
79
  end
107
80
  end
108
81
  end
@@ -3,17 +3,21 @@
3
3
  module I18nJS
4
4
  class CLI
5
5
  class UI
6
- def initialize(stdout:, stderr:)
6
+ attr_reader :stdout, :stderr
7
+ attr_accessor :colored
8
+
9
+ def initialize(stdout:, stderr:, colored: nil)
7
10
  @stdout = stdout
8
11
  @stderr = stderr
12
+ @colored = colored
9
13
  end
10
14
 
11
15
  def stdout_print(*message)
12
- @stdout << "#{message.join(' ')}\n"
16
+ stdout << "#{message.join(' ')}\n"
13
17
  end
14
18
 
15
19
  def stderr_print(*message)
16
- @stderr << "#{message.join(' ')}\n"
20
+ stderr << "#{message.join(' ')}\n"
17
21
  end
18
22
 
19
23
  def fail_with(*message)
@@ -25,6 +29,36 @@ module I18nJS
25
29
  stdout_print(message)
26
30
  exit(0)
27
31
  end
32
+
33
+ def yellow(text)
34
+ ansi(text, 33)
35
+ end
36
+
37
+ def red(text)
38
+ ansi(text, 31)
39
+ end
40
+
41
+ def colored?
42
+ colored_output = if colored.nil?
43
+ stdout.tty?
44
+ else
45
+ colored
46
+ end
47
+
48
+ colored_output && !no_color?
49
+ end
50
+
51
+ def ansi(text, code)
52
+ if colored?
53
+ "\e[#{code}m#{text}\e[0m"
54
+ else
55
+ text
56
+ end
57
+ end
58
+
59
+ def no_color?
60
+ !ENV["NO_COLOR"].nil? && ENV["NO_COLOR"] == "1"
61
+ end
28
62
  end
29
63
  end
30
64
  end
data/lib/i18n-js/cli.rb CHANGED
@@ -6,14 +6,15 @@ require_relative "cli/ui"
6
6
  require_relative "cli/init_command"
7
7
  require_relative "cli/version_command"
8
8
  require_relative "cli/export_command"
9
+ require_relative "cli/check_command"
9
10
 
10
11
  module I18nJS
11
12
  class CLI
12
13
  attr_reader :ui
13
14
 
14
- def initialize(argv:, stdout:, stderr:)
15
+ def initialize(argv:, stdout:, stderr:, colored: stdout.tty?)
15
16
  @argv = argv.dup
16
- @ui = UI.new(stdout: stdout, stderr: stderr)
17
+ @ui = UI.new(stdout: stdout, stderr: stderr, colored: colored)
17
18
  end
18
19
 
19
20
  def call
@@ -26,7 +27,7 @@ module I18nJS
26
27
  end
27
28
 
28
29
  private def command_classes
29
- [InitCommand, ExportCommand, VersionCommand]
30
+ [InitCommand, ExportCommand, VersionCommand, CheckCommand]
30
31
  end
31
32
 
32
33
  private def commands
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module I18nJS
4
- VERSION = "4.0.0.alpha3"
4
+ VERSION = "4.0.0.alpha4"
5
5
  end
data/lib/i18n-js.rb CHANGED
@@ -21,24 +21,31 @@ module I18nJS
21
21
 
22
22
  config = Glob::SymbolizeKeys.call(config || YAML.load_file(config_file))
23
23
  Schema.validate!(config)
24
+ exported_files = []
24
25
 
25
26
  config[:translations].each do |group|
26
- export_group(group)
27
+ exported_files += export_group(group)
27
28
  end
29
+
30
+ exported_files
28
31
  end
29
32
 
30
33
  def self.export_group(group)
31
34
  filtered_translations = Glob.filter(translations, group[:patterns])
32
35
  output_file_path = File.expand_path(group[:file])
36
+ exported_files = []
33
37
 
34
38
  if output_file_path.include?(":locale")
35
39
  filtered_translations.each_key do |locale|
36
40
  locale_file_path = output_file_path.gsub(/:locale/, locale.to_s)
37
- write_file(locale_file_path, locale => filtered_translations[locale])
41
+ exported_files << write_file(locale_file_path,
42
+ locale => filtered_translations[locale])
38
43
  end
39
44
  else
40
- write_file(output_file_path, filtered_translations)
45
+ exported_files << write_file(output_file_path, filtered_translations)
41
46
  end
47
+
48
+ exported_files
42
49
  end
43
50
 
44
51
  def self.write_file(file_path, translations)
@@ -51,6 +58,8 @@ module I18nJS
51
58
  File.open(file_path, "w") do |file|
52
59
  file << contents
53
60
  end
61
+
62
+ file_path
54
63
  end
55
64
 
56
65
  def self.translations
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: i18n-js
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0.alpha3
4
+ version: 4.0.0.alpha4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nando Vieira
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-07-20 00:00:00.000000000 Z
11
+ date: 2022-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glob
@@ -178,11 +178,13 @@ files:
178
178
  - exe/i18n
179
179
  - i18n-js.gemspec
180
180
  - i18njs.png
181
+ - images/i18njs-check.gif
181
182
  - lib/guard/i18n-js.rb
182
183
  - lib/guard/i18n-js/templates/Guardfile
183
184
  - lib/guard/i18n-js/version.rb
184
185
  - lib/i18n-js.rb
185
186
  - lib/i18n-js/cli.rb
187
+ - lib/i18n-js/cli/check_command.rb
186
188
  - lib/i18n-js/cli/command.rb
187
189
  - lib/i18n-js/cli/export_command.rb
188
190
  - lib/i18n-js/cli/init_command.rb
@@ -198,10 +200,10 @@ metadata:
198
200
  rubygems_mfa_required: 'true'
199
201
  homepage_uri: https://github.com/fnando/i18n-js
200
202
  bug_tracker_uri: https://github.com/fnando/i18n-js/issues
201
- source_code_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha3
202
- changelog_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha3/CHANGELOG.md
203
- documentation_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha3/README.md
204
- license_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha3/LICENSE.md
203
+ source_code_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha4
204
+ changelog_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha4/CHANGELOG.md
205
+ documentation_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha4/README.md
206
+ license_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha4/LICENSE.md
205
207
  post_install_message:
206
208
  rdoc_options: []
207
209
  require_paths:
@@ -217,7 +219,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
217
219
  - !ruby/object:Gem::Version
218
220
  version: 1.3.1
219
221
  requirements: []
220
- rubygems_version: 3.3.17
222
+ rubygems_version: 3.3.7
221
223
  signing_key:
222
224
  specification_version: 4
223
225
  summary: Export i18n translations and use them on JavaScript.