i18n-js 4.0.0.alpha3 → 4.0.0.alpha4

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: 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.