i18n-js 4.0.0.alpha1 → 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: d07791eb7f9b879e4d5e6edd43d10564a5efad2f44e3ac0ddd2c892696dbd28b
4
- data.tar.gz: cab23b9274ee26513b48974dd307ad020a1ad3ba88bb36756397d6c47223ffb4
3
+ metadata.gz: 3ecf4853a33adc9a67520a585c733a55e7b05e07bdc436830c519213bfc728b6
4
+ data.tar.gz: 5a1b68a4182bc30fcc3c57438ab226ba72a97a7f16dd6c29ac938106f4c5e00c
5
5
  SHA512:
6
- metadata.gz: 0d0bb95c8e0f01bed11eced7859d6f40d032ca85a03f458d515a4cdcc444a194f315b22db39f0d6956c45951a1cf8e3e28ab06a11abb6165ca7dc5d6fa07baa1
7
- data.tar.gz: a7afe30f6f81a9b7536cb5be2a26112825bd5324443d9fe7edb43779c6084e2c4d4e439814f4458853a6ffaf540afdfc0640f8be2a7cb428b46c45c83313d0bb
6
+ metadata.gz: f8468f07c440fa8c29c84a6550ef8b7d5914cf08ce93d0b02f77caf65838a4057f8a7653cc221c33a1dfaf1ab0486aa195a368248ca9509af4af7071ab76ddaa
7
+ data.tar.gz: cb3822d5fe66aa90b20a4a596869a0adb93c3154d5877f66b1374794961536bc2916c051f8d5ce5f61d2d57c66951c25b477f8b808b7d737b39941875e545afb
@@ -0,0 +1,5 @@
1
+ ---
2
+ contact_links:
3
+ - name: "🤨 Q&A"
4
+ url: https://github.com/fnando/i18n-js/discussions/new?category=q-a
5
+ about: Have a question? Ask it away here!
@@ -2,18 +2,8 @@
2
2
  name: ruby-tests
3
3
 
4
4
  on:
5
- pull_request:
6
- branches:
7
- - main
8
-
5
+ pull_request_target:
9
6
  push:
10
- branches:
11
- - main
12
- - v4
13
-
14
- schedule:
15
- - cron: "0 10 * * *"
16
-
17
7
  workflow_dispatch:
18
8
  inputs: {}
19
9
 
@@ -24,25 +14,26 @@ jobs:
24
14
  strategy:
25
15
  fail-fast: false
26
16
  matrix:
27
- ruby: [2.6.x, 2.7.x, 3.0.x]
17
+ ruby: ["2.7", "3.0", "3.1"]
28
18
  gemfile:
29
19
  - Gemfile
20
+ if: |
21
+ github.actor == 'dependabot[bot]' && github.event_name == 'pull_request_target' ||
22
+ github.actor != 'dependabot[bot]'
30
23
 
31
24
  steps:
32
- - uses: actions/checkout@v1
25
+ - uses: actions/checkout@v3
33
26
 
34
- - uses: actions/cache@v2
27
+ - uses: actions/cache@v3
28
+ id: bundler-cache
35
29
  with:
36
30
  path: vendor/bundle
37
31
  key: >
38
32
  ${{ runner.os }}-${{ matrix.ruby }}-gems-${{
39
33
  hashFiles(matrix.gemfile) }}
40
- restore-keys: >
41
- ${{ runner.os }}-${{ matrix.ruby }}-gems-${{
42
- hashFiles(matrix.gemfile) }}
43
34
 
44
35
  - name: Set up Ruby
45
- uses: actions/setup-ruby@v1
36
+ uses: ruby/setup-ruby@v1
46
37
  with:
47
38
  ruby-version: ${{ matrix.ruby }}
48
39
 
data/.rubocop.yml CHANGED
@@ -5,6 +5,10 @@ inherit_gem:
5
5
  AllCops:
6
6
  TargetRubyVersion: 2.6
7
7
  NewCops: enable
8
+ Exclude:
9
+ - tmp/**/*
10
+ - vendor/**/*
11
+ - gemfiles/**/*
8
12
 
9
13
  Naming/FileName:
10
14
  Exclude:
data/README.md CHANGED
@@ -1,15 +1,30 @@
1
- # i18n-js
2
-
3
- [![Tests](https://github.com/fnando/i18n-js/workflows/ruby-tests/badge.svg)](https://github.com/fnando/i18n-js)
4
- [![Code Climate](https://codeclimate.com/github/fnando/i18n-js/badges/gpa.svg)](https://codeclimate.com/github/fnando/i18n-js)
5
- [![Gem](https://img.shields.io/gem/v/i18n-js.svg)](https://rubygems.org/gems/i18n-js)
6
- [![Gem](https://img.shields.io/gem/dt/i18n-js.svg)](https://rubygems.org/gems/i18n-js)
7
-
8
- Export [i18n](https://rubygems.org/gems/i18n) translations to JSON. A perfect
9
- fit if you want to export translations to JavaScript.
10
-
11
- Oh, you don't use Ruby? No problem! You can still use i18n-js and the
12
- [companion JavaScript package](https://npmjs.com/package/i18n-js).
1
+ <p align="center">
2
+ <img width="250" height="58" src="https://github.com/fnando/i18n-js/raw/main/i18njs.png" alt="i18n.js">
3
+ </p>
4
+
5
+ <p align="center">
6
+ Export <a href="https://rubygems.org/gems/i18n">i18n</a> translations to JSON.
7
+ <br>
8
+ A perfect fit if you want to export translations to JavaScript.
9
+ </p>
10
+
11
+ <p align="center">
12
+ <small>
13
+ Oh, you don't use Ruby? No problem! You can still use i18n-js
14
+ <br>
15
+ and the
16
+ <a href="https://www.npmjs.com/package/i18n-js/v/next">companion JavaScript package</a>.
17
+ </small>
18
+ </p>
19
+
20
+ <p align="center">
21
+ <a href="https://github.com/fnando/i18n-js"><img src="https://github.com/fnando/i18n-js/workflows/ruby-tests/badge.svg" alt="Tests"></a>
22
+ <a href="https://rubygems.org/gems/i18n-js"><img src="https://img.shields.io/gem/v/i18n-js.svg" alt="Gem"></a>
23
+ <a href="https://rubygems.org/gems/i18n-js"><img src="https://img.shields.io/gem/dt/i18n-js.svg" alt="Gem"></a>
24
+ <a href="https://tldrlegal.com/license/mit-license"><img src="https://img.shields.io/:License-MIT-blue.svg" alt="MIT License"></a>
25
+ </p>
26
+
27
+ ![This branch contains the code for v4, our next major release.](https://messages-svg.herokuapp.com/warning.svg?message=This%20branch%20contains%20the%20code%20for%20v4%2C%20our%20next%20major%20release.)
13
28
 
14
29
  ## Installation
15
30
 
@@ -45,11 +60,16 @@ translations:
45
60
  - "!*.errors"
46
61
  - "!*.number.nth"
47
62
 
48
- - file: app/frontend/locales/:locale.json
63
+ - file: app/frontend/locales/:locale.:digest.json
49
64
  patterns:
50
65
  - "*"
51
66
  ```
52
67
 
68
+ The output path can use the following placeholders:
69
+
70
+ - `:locale`: the language that's being exported.
71
+ - `:digest`: the MD5 hex digest of the exported file.
72
+
53
73
  The Ruby API:
54
74
 
55
75
  ```ruby
@@ -62,16 +82,82 @@ I18nJS.call(config: config)
62
82
  The CLI API:
63
83
 
64
84
  ```console
65
- $ i18n init --config config/i18n.yml
66
- $ 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.
67
96
  ```
68
97
 
69
98
  By default, `i18n` will use `config/i18n.yml` and `config/environment.rb` as the
70
99
  configuration files. If you don't have these files, then you'll need to specify
71
100
  both `--config` and `--require`.
72
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
+
73
114
  ## Automatically export translations
74
115
 
116
+ ### Using watchman
117
+
118
+ Create a script at `bin/i18n-watch`.
119
+
120
+ ```bash
121
+ #!/usr/bin/env bash
122
+
123
+ root=`pwd`
124
+
125
+ watchman watch-del "$root"
126
+ watchman watch-project "$root"
127
+ watchman trigger-del "$root" i18n
128
+
129
+ watchman -j <<-JSON
130
+ [
131
+ "trigger",
132
+ "$root",
133
+ {
134
+ "name": "i18n",
135
+ "expression": [
136
+ "anyof",
137
+ ["match", "config/locales/**/*.yml", "wholename"],
138
+ ["match", "config/i18n.yml", "wholename"]
139
+ ],
140
+ "command": ["i18n", "export"]
141
+ }
142
+ ]
143
+ JSON
144
+
145
+ # If you're running this through Foreman,
146
+ # the uncomment the following lines:
147
+ # while true; do
148
+ # sleep 1
149
+ # done
150
+ ```
151
+
152
+ Make it executable with `chmod +x bin/i18n-watch`. To watch for changes, run
153
+ `./bin/i18n-watch`. If you're using Foreman, make sure you uncommented the lines
154
+ that keep the process running (`while..`), and add something like the following
155
+ line to your Procfile:
156
+
157
+ ```
158
+ i18n: ./bin/i18n-watch
159
+ ```
160
+
75
161
  ### Using guard
76
162
 
77
163
  Install [guard](https://rubygems.org/packages/guard) and
@@ -89,7 +175,7 @@ guard(:"i18n-js",
89
175
  end
90
176
  ```
91
177
 
92
- If you files in a different location, the remember to configure file paths
178
+ If your files are located in a different path, remember to configure file paths
93
179
  accordingly.
94
180
 
95
181
  Now you can run `guard start -i`.
@@ -99,11 +185,10 @@ Now you can run `guard start -i`.
99
185
  Create a file under `config/initializers/i18n.rb` with the following content:
100
186
 
101
187
  ```ruby
102
- # frozen_string_literal: true
103
-
104
- require "i18n-js/listen"
105
-
106
- I18nJS.listen
188
+ Rails.application.config.after_initialize do
189
+ require "i18n-js/listen"
190
+ I18nJS.listen
191
+ end
107
192
  ```
108
193
 
109
194
  The code above will watch for changes based on `config/i18n.yml` and
@@ -116,6 +201,31 @@ You're done exporting files, now what? Well, go to
116
201
  [i18n](https://github.com/fnando/i18n) to discover how to use the NPM package
117
202
  that loads all the exported translation.
118
203
 
204
+ ### FAQ
205
+
206
+ #### How can I export translations without having a database around?
207
+
208
+ Some people may have a build process using something like Docker that don't
209
+ necessarily have a database available. In this case, you may define your own
210
+ loading file by using something like
211
+ `i18n export --require ./config/i18n_export.rb`, where `i18n_export.rb` may look
212
+ like this:
213
+
214
+ ```ruby
215
+ # frozen_string_literal: true
216
+
217
+ require "bundler/setup"
218
+ require "rails"
219
+ require "active_support/railtie"
220
+ require "action_view/railtie"
221
+
222
+ I18n.load_path += Dir["./config/locales/**/*.yml"]
223
+ ```
224
+
225
+ Notice that you may not need to load ActiveSupport and ActionView lines, or even
226
+ may need to add additional requires for other libs. With this approach you have
227
+ full control on what's going to be loaded.
228
+
119
229
  ## Maintainer
120
230
 
121
231
  - [Nando Vieira](https://github.com/fnando)
data/exe/i18n CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require_relative "../lib/i18n-js"
4
+ require_relative "../lib/i18n-js/cli"
5
5
  I18nJS::CLI.new(argv: ARGV, stdout: $stdout, stderr: $stderr).call
data/i18n-js.gemspec CHANGED
@@ -12,6 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = spec.summary
13
13
  spec.license = "MIT"
14
14
  spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
15
+ spec.metadata = {"rubygems_mfa_required" => "true"}
15
16
 
16
17
  github_url = "https://github.com/fnando/i18n-js"
17
18
  github_tree_url = "#{github_url}/tree/v#{spec.version}"
data/i18njs.png ADDED
Binary file
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
@@ -32,19 +32,18 @@ module I18nJS
32
32
  end
33
33
  end
34
34
 
35
- command do # rubocop:disable Metrics/BlockLength
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
@@ -23,7 +23,9 @@ module I18nJS
23
23
  end
24
24
 
25
25
  command do
26
- file_path = File.expand_path(options[:config_file])
26
+ file_path = File.expand_path(
27
+ options.fetch(:config_file, "config/i18n.yml")
28
+ )
27
29
 
28
30
  if File.file?(file_path)
29
31
  ui.fail_with("ERROR: #{file_path} already exists!")
@@ -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
@@ -1,12 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../i18n-js"
4
+ require_relative "cli/command"
5
+ require_relative "cli/ui"
6
+ require_relative "cli/init_command"
7
+ require_relative "cli/version_command"
8
+ require_relative "cli/export_command"
9
+ require_relative "cli/check_command"
10
+
3
11
  module I18nJS
4
12
  class CLI
5
13
  attr_reader :ui
6
14
 
7
- def initialize(argv:, stdout:, stderr:)
15
+ def initialize(argv:, stdout:, stderr:, colored: stdout.tty?)
8
16
  @argv = argv.dup
9
- @ui = UI.new(stdout: stdout, stderr: stderr)
17
+ @ui = UI.new(stdout: stdout, stderr: stderr, colored: colored)
10
18
  end
11
19
 
12
20
  def call
@@ -19,7 +27,7 @@ module I18nJS
19
27
  end
20
28
 
21
29
  private def command_classes
22
- [InitCommand, ExportCommand, VersionCommand]
30
+ [InitCommand, ExportCommand, VersionCommand, CheckCommand]
23
31
  end
24
32
 
25
33
  private def commands
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- gem "listen"
4
- require "listen"
5
- require "i18n-js"
6
-
7
3
  module I18nJS
8
4
  class << self
9
5
  attr_accessor :started
@@ -16,6 +12,10 @@ module I18nJS
16
12
  return unless Rails.env.development?
17
13
  return if started
18
14
 
15
+ gem "listen"
16
+ require "listen"
17
+ require "i18n-js"
18
+
19
19
  self.started = true
20
20
 
21
21
  relative_paths =
@@ -43,7 +43,7 @@ module I18nJS
43
43
  @logger ||= ActiveSupport::TaggedLogging.new(Rails.logger)
44
44
  end
45
45
 
46
- def self.listener(config_file, locales_dir) # rubocop:disable Metrics/MethodLength
46
+ def self.listener(config_file, locales_dir)
47
47
  paths = [File.dirname(config_file), locales_dir]
48
48
 
49
49
  Listen.to(*paths) do |changed, added, removed|
@@ -58,6 +58,7 @@ module I18nJS
58
58
 
59
59
  debug(changes.map {|key, value| "#{key}=#{value.inspect}" }.join(", "))
60
60
 
61
+ ::I18n.backend.reload!
61
62
  I18nJS.call(config_file: config_file)
62
63
  end
63
64
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module I18nJS
4
- VERSION = "4.0.0.alpha1"
4
+ VERSION = "4.0.0.alpha4"
5
5
  end
data/lib/i18n-js.rb CHANGED
@@ -7,14 +7,8 @@ require "glob"
7
7
  require "fileutils"
8
8
  require "optparse"
9
9
 
10
- require_relative "./i18n-js/cli"
11
- require_relative "./i18n-js/cli/command"
12
- require_relative "./i18n-js/cli/ui"
13
- require_relative "./i18n-js/cli/init_command"
14
- require_relative "./i18n-js/cli/version_command"
15
- require_relative "./i18n-js/cli/export_command"
16
- require_relative "./i18n-js/schema"
17
- require_relative "./i18n-js/version"
10
+ require_relative "i18n-js/schema"
11
+ require_relative "i18n-js/version"
18
12
 
19
13
  module I18nJS
20
14
  MissingConfigError = Class.new(StandardError)
@@ -27,32 +21,45 @@ module I18nJS
27
21
 
28
22
  config = Glob::SymbolizeKeys.call(config || YAML.load_file(config_file))
29
23
  Schema.validate!(config)
24
+ exported_files = []
30
25
 
31
26
  config[:translations].each do |group|
32
- export_group(group)
27
+ exported_files += export_group(group)
33
28
  end
29
+
30
+ exported_files
34
31
  end
35
32
 
36
33
  def self.export_group(group)
37
34
  filtered_translations = Glob.filter(translations, group[:patterns])
38
35
  output_file_path = File.expand_path(group[:file])
36
+ exported_files = []
39
37
 
40
38
  if output_file_path.include?(":locale")
41
39
  filtered_translations.each_key do |locale|
42
40
  locale_file_path = output_file_path.gsub(/:locale/, locale.to_s)
43
- write_file(locale_file_path, locale => filtered_translations[locale])
41
+ exported_files << write_file(locale_file_path,
42
+ locale => filtered_translations[locale])
44
43
  end
45
44
  else
46
- write_file(output_file_path, filtered_translations)
45
+ exported_files << write_file(output_file_path, filtered_translations)
47
46
  end
47
+
48
+ exported_files
48
49
  end
49
50
 
50
51
  def self.write_file(file_path, translations)
51
52
  FileUtils.mkdir_p(File.dirname(file_path))
52
53
 
54
+ contents = ::JSON.pretty_generate(translations)
55
+ digest = Digest::MD5.hexdigest(contents)
56
+ file_path = file_path.gsub(/:digest/, digest)
57
+
53
58
  File.open(file_path, "w") do |file|
54
- file << ::JSON.pretty_generate(translations)
59
+ file << contents
55
60
  end
61
+
62
+ file_path
56
63
  end
57
64
 
58
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.alpha1
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: 2021-05-24 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
@@ -161,6 +161,7 @@ files:
161
161
  - ".github/CODEOWNERS"
162
162
  - ".github/FUNDING.yml"
163
163
  - ".github/ISSUE_TEMPLATE/bug_report.md"
164
+ - ".github/ISSUE_TEMPLATE/config.yml"
164
165
  - ".github/ISSUE_TEMPLATE/feature_request.md"
165
166
  - ".github/PULL_REQUEST_TEMPLATE.md"
166
167
  - ".github/dependabot.yml"
@@ -176,11 +177,14 @@ files:
176
177
  - Rakefile
177
178
  - exe/i18n
178
179
  - i18n-js.gemspec
180
+ - i18njs.png
181
+ - images/i18njs-check.gif
179
182
  - lib/guard/i18n-js.rb
180
183
  - lib/guard/i18n-js/templates/Guardfile
181
184
  - lib/guard/i18n-js/version.rb
182
185
  - lib/i18n-js.rb
183
186
  - lib/i18n-js/cli.rb
187
+ - lib/i18n-js/cli/check_command.rb
184
188
  - lib/i18n-js/cli/command.rb
185
189
  - lib/i18n-js/cli/export_command.rb
186
190
  - lib/i18n-js/cli/init_command.rb
@@ -193,12 +197,13 @@ homepage: https://github.com/fnando/i18n-js
193
197
  licenses:
194
198
  - MIT
195
199
  metadata:
200
+ rubygems_mfa_required: 'true'
196
201
  homepage_uri: https://github.com/fnando/i18n-js
197
202
  bug_tracker_uri: https://github.com/fnando/i18n-js/issues
198
- source_code_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha1
199
- changelog_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha1/CHANGELOG.md
200
- documentation_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha1/README.md
201
- license_uri: https://github.com/fnando/i18n-js/tree/v4.0.0.alpha1/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
202
207
  post_install_message:
203
208
  rdoc_options: []
204
209
  require_paths:
@@ -214,7 +219,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
214
219
  - !ruby/object:Gem::Version
215
220
  version: 1.3.1
216
221
  requirements: []
217
- rubygems_version: 3.2.15
222
+ rubygems_version: 3.3.7
218
223
  signing_key:
219
224
  specification_version: 4
220
225
  summary: Export i18n translations and use them on JavaScript.