i18n-js 3.9.2 → 4.0.0.alpha1
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 +4 -4
- data/.github/CODEOWNERS +4 -0
- data/.github/FUNDING.yml +1 -1
- data/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +38 -0
- data/.github/dependabot.yml +15 -0
- data/.github/workflows/ruby-tests.yml +61 -0
- data/.gitignore +11 -7
- data/.rubocop.yml +12 -0
- data/CHANGELOG.md +12 -571
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +79 -0
- data/Gemfile +3 -0
- data/LICENSE.md +20 -0
- data/README.md +86 -1043
- data/Rakefile +10 -20
- data/exe/i18n +5 -0
- data/i18n-js.gemspec +47 -29
- data/lib/guard/i18n-js/templates/Guardfile +10 -0
- data/lib/guard/i18n-js/version.rb +13 -0
- data/lib/guard/i18n-js.rb +78 -0
- data/lib/i18n-js/cli/command.rb +43 -0
- data/lib/i18n-js/cli/export_command.rb +108 -0
- data/lib/i18n-js/cli/init_command.rb +50 -0
- data/lib/i18n-js/cli/ui.rb +30 -0
- data/lib/i18n-js/cli/version_command.rb +18 -0
- data/lib/i18n-js/cli.rb +47 -0
- data/lib/i18n-js/listen.rb +80 -0
- data/lib/i18n-js/schema.rb +92 -0
- data/lib/i18n-js/version.rb +5 -0
- data/lib/i18n-js.rb +66 -1
- metadata +125 -201
- data/.editorconfig +0 -24
- data/.github/workflows/tests.yaml +0 -106
- data/.npmignore +0 -27
- data/Appraisals +0 -52
- data/app/assets/javascripts/i18n/filtered.js.erb +0 -23
- data/app/assets/javascripts/i18n/shims.js +0 -240
- data/app/assets/javascripts/i18n/translations.js +0 -3
- data/app/assets/javascripts/i18n.js +0 -1095
- data/gemfiles/i18n_0_6.gemfile +0 -7
- data/gemfiles/i18n_0_7.gemfile +0 -7
- data/gemfiles/i18n_0_8.gemfile +0 -7
- data/gemfiles/i18n_0_9.gemfile +0 -7
- data/gemfiles/i18n_1_0.gemfile +0 -7
- data/gemfiles/i18n_1_1.gemfile +0 -7
- data/gemfiles/i18n_1_10.gemfile +0 -7
- data/gemfiles/i18n_1_2.gemfile +0 -7
- data/gemfiles/i18n_1_3.gemfile +0 -7
- data/gemfiles/i18n_1_4.gemfile +0 -7
- data/gemfiles/i18n_1_5.gemfile +0 -7
- data/gemfiles/i18n_1_6.gemfile +0 -7
- data/gemfiles/i18n_1_7.gemfile +0 -7
- data/gemfiles/i18n_1_8.gemfile +0 -7
- data/gemfiles/i18n_1_9.gemfile +0 -7
- data/i18njs.png +0 -0
- data/lib/i18n/js/dependencies.rb +0 -67
- data/lib/i18n/js/engine.rb +0 -87
- data/lib/i18n/js/fallback_locales.rb +0 -70
- data/lib/i18n/js/formatters/base.rb +0 -25
- data/lib/i18n/js/formatters/js.rb +0 -39
- data/lib/i18n/js/formatters/json.rb +0 -13
- data/lib/i18n/js/middleware.rb +0 -82
- data/lib/i18n/js/private/config_store.rb +0 -31
- data/lib/i18n/js/private/hash_with_symbol_keys.rb +0 -36
- data/lib/i18n/js/segment.rb +0 -81
- data/lib/i18n/js/utils.rb +0 -91
- data/lib/i18n/js/version.rb +0 -7
- data/lib/i18n/js.rb +0 -274
- data/lib/rails/generators/i18n/js/config/config_generator.rb +0 -19
- data/lib/rails/generators/i18n/js/config/templates/i18n-js.yml +0 -27
- data/lib/tasks/export.rake +0 -8
- data/package.json +0 -25
- data/spec/fixtures/custom_path.yml +0 -5
- data/spec/fixtures/default.yml +0 -5
- data/spec/fixtures/erb.yml +0 -5
- data/spec/fixtures/except_condition.yml +0 -7
- data/spec/fixtures/js_available_locales_custom.yml +0 -1
- data/spec/fixtures/js_export_dir_custom.yml +0 -7
- data/spec/fixtures/js_export_dir_none.yml +0 -6
- data/spec/fixtures/js_extend_parent.yml +0 -6
- data/spec/fixtures/js_extend_segment.yml +0 -6
- data/spec/fixtures/js_file_per_locale.yml +0 -7
- data/spec/fixtures/js_file_per_locale_with_fallbacks_as_default_locale_symbol.yml +0 -4
- data/spec/fixtures/js_file_per_locale_with_fallbacks_as_hash.yml +0 -6
- data/spec/fixtures/js_file_per_locale_with_fallbacks_as_locale.yml +0 -4
- data/spec/fixtures/js_file_per_locale_with_fallbacks_as_locale_without_fallback_translations.yml +0 -4
- data/spec/fixtures/js_file_per_locale_with_fallbacks_enabled.yml +0 -4
- data/spec/fixtures/js_file_per_locale_without_fallbacks.yml +0 -4
- data/spec/fixtures/js_file_with_namespace_prefix_and_pretty_print.yml +0 -9
- data/spec/fixtures/js_sort_translation_keys_false.yml +0 -6
- data/spec/fixtures/js_sort_translation_keys_true.yml +0 -6
- data/spec/fixtures/json_only.yml +0 -18
- data/spec/fixtures/locales.yml +0 -133
- data/spec/fixtures/merge_plurals.yml +0 -6
- data/spec/fixtures/merge_plurals_with_no_overrides.yml +0 -4
- data/spec/fixtures/merge_plurals_with_partial_overrides.yml +0 -4
- data/spec/fixtures/millions.yml +0 -4
- data/spec/fixtures/multiple_conditions.yml +0 -7
- data/spec/fixtures/multiple_conditions_per_locale.yml +0 -7
- data/spec/fixtures/multiple_files.yml +0 -7
- data/spec/fixtures/no_config.yml +0 -2
- data/spec/fixtures/no_scope.yml +0 -4
- data/spec/fixtures/simple_scope.yml +0 -5
- data/spec/js/currency.spec.js +0 -62
- data/spec/js/current_locale.spec.js +0 -19
- data/spec/js/dates.spec.js +0 -276
- data/spec/js/defaults.spec.js +0 -31
- data/spec/js/extend.spec.js +0 -110
- data/spec/js/interpolation.spec.js +0 -124
- data/spec/js/jasmine/MIT.LICENSE +0 -20
- data/spec/js/jasmine/jasmine-html.js +0 -190
- data/spec/js/jasmine/jasmine.css +0 -166
- data/spec/js/jasmine/jasmine.js +0 -2476
- data/spec/js/jasmine/jasmine_favicon.png +0 -0
- data/spec/js/json_parsable.spec.js +0 -14
- data/spec/js/locales.spec.js +0 -31
- data/spec/js/localization.spec.js +0 -78
- data/spec/js/numbers.spec.js +0 -174
- data/spec/js/placeholder.spec.js +0 -24
- data/spec/js/pluralization.spec.js +0 -228
- data/spec/js/prepare_options.spec.js +0 -41
- data/spec/js/require.js +0 -2083
- data/spec/js/specs.html +0 -49
- data/spec/js/specs_requirejs.html +0 -72
- data/spec/js/translate.spec.js +0 -304
- data/spec/js/translations.js +0 -188
- data/spec/js/utility_functions.spec.js +0 -20
- data/spec/ruby/i18n/js/fallback_locales_spec.rb +0 -84
- data/spec/ruby/i18n/js/segment_spec.rb +0 -286
- data/spec/ruby/i18n/js/utils_spec.rb +0 -138
- data/spec/ruby/i18n/js_spec.rb +0 -797
- data/spec/spec_helper.rb +0 -80
- data/yarn.lock +0 -138
data/Rakefile
CHANGED
|
@@ -1,25 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
require "rubygems"
|
|
3
|
-
require "bundler"
|
|
4
|
-
require "rspec/core/rake_task"
|
|
1
|
+
# frozen_string_literal: true
|
|
5
2
|
|
|
6
|
-
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rake/testtask"
|
|
5
|
+
require "rubocop/rake_task"
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# Need to call `exit!` manually to propogate exit status
|
|
13
|
-
system "npm", "test" or exit!(1)
|
|
7
|
+
Rake::TestTask.new(:test) do |t|
|
|
8
|
+
t.libs << "test"
|
|
9
|
+
t.libs << "lib"
|
|
10
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
|
14
11
|
end
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
task :spec => ["spec:ruby", "spec:js"]
|
|
13
|
+
RuboCop::RakeTask.new
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
task :default do
|
|
21
|
-
sh "appraisal install && rake appraisal spec"
|
|
22
|
-
end
|
|
23
|
-
else
|
|
24
|
-
task :default => :spec
|
|
25
|
-
end
|
|
15
|
+
task default: %i[test rubocop]
|
data/exe/i18n
ADDED
data/i18n-js.gemspec
CHANGED
|
@@ -1,30 +1,48 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "./lib/i18n-js/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "i18n-js"
|
|
7
|
+
spec.version = I18nJS::VERSION
|
|
8
|
+
spec.authors = ["Nando Vieira"]
|
|
9
|
+
spec.email = ["me@fnando.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Export i18n translations and use them on JavaScript."
|
|
12
|
+
spec.description = spec.summary
|
|
13
|
+
spec.license = "MIT"
|
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
|
|
15
|
+
|
|
16
|
+
github_url = "https://github.com/fnando/i18n-js"
|
|
17
|
+
github_tree_url = "#{github_url}/tree/v#{spec.version}"
|
|
18
|
+
|
|
19
|
+
spec.homepage = github_url
|
|
20
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
21
|
+
spec.metadata["bug_tracker_uri"] = "#{github_url}/issues"
|
|
22
|
+
spec.metadata["source_code_uri"] = github_tree_url
|
|
23
|
+
spec.metadata["changelog_uri"] = "#{github_tree_url}/CHANGELOG.md"
|
|
24
|
+
spec.metadata["documentation_uri"] = "#{github_tree_url}/README.md"
|
|
25
|
+
spec.metadata["license_uri"] = "#{github_tree_url}/LICENSE.md"
|
|
26
|
+
|
|
27
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
28
|
+
`git ls-files -z`
|
|
29
|
+
.split("\x0")
|
|
30
|
+
.reject {|f| f.match(%r{^(test|spec|features)/}) }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
spec.bindir = "exe"
|
|
34
|
+
spec.executables = spec.files.grep(%r{^exe/}) {|f| File.basename(f) }
|
|
35
|
+
spec.require_paths = ["lib"]
|
|
36
|
+
|
|
37
|
+
spec.add_dependency "glob"
|
|
38
|
+
spec.add_dependency "i18n"
|
|
39
|
+
|
|
40
|
+
spec.add_development_dependency "activesupport"
|
|
41
|
+
spec.add_development_dependency "minitest"
|
|
42
|
+
spec.add_development_dependency "minitest-utils"
|
|
43
|
+
spec.add_development_dependency "pry-meta"
|
|
44
|
+
spec.add_development_dependency "rake"
|
|
45
|
+
spec.add_development_dependency "rubocop"
|
|
46
|
+
spec.add_development_dependency "rubocop-fnando"
|
|
47
|
+
spec.add_development_dependency "simplecov"
|
|
30
48
|
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
guard(:"i18n-js",
|
|
4
|
+
run_on_start: true,
|
|
5
|
+
config_file: "./config/i18n.yml",
|
|
6
|
+
require_file: "./config/environment.rb") do
|
|
7
|
+
watch(%r{^(app|config)/locales/.+\.(yml|po)$})
|
|
8
|
+
watch(%r{^config/i18n.yml$})
|
|
9
|
+
watch("Gemfile")
|
|
10
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
gem "guard"
|
|
4
|
+
gem "guard-compat"
|
|
5
|
+
require "guard/compat/plugin"
|
|
6
|
+
|
|
7
|
+
require "i18n-js"
|
|
8
|
+
|
|
9
|
+
module Guard
|
|
10
|
+
class I18njs < Plugin
|
|
11
|
+
attr_reader :config_file, :require_file, :current_thread
|
|
12
|
+
|
|
13
|
+
def initialize(options = {})
|
|
14
|
+
@config_file = options.delete(:config_file)
|
|
15
|
+
@require_file = options.delete(:require_file)
|
|
16
|
+
super
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def start
|
|
20
|
+
export_files
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def stop
|
|
24
|
+
current_thread&.exit
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def reload
|
|
28
|
+
export_files
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def run_all
|
|
32
|
+
export_files
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def run_on_additions(paths)
|
|
36
|
+
export_files(paths)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def run_on_modifications(paths)
|
|
40
|
+
export_files(paths)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def run_on_removals(paths)
|
|
44
|
+
export_files(paths)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def export_files(changes = nil)
|
|
48
|
+
return unless validate_file(:config_file, config_file)
|
|
49
|
+
return unless validate_file(:require_file, require_file)
|
|
50
|
+
|
|
51
|
+
current_thread&.exit
|
|
52
|
+
|
|
53
|
+
info("Changes detected: #{changes.join(', ')}") if changes
|
|
54
|
+
|
|
55
|
+
@current_thread = Thread.new do
|
|
56
|
+
require @require_file
|
|
57
|
+
::I18nJS.call(config_file: @config_file)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
current_thread.join
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def validate_file(key, file)
|
|
64
|
+
return true if file && File.file?(file)
|
|
65
|
+
|
|
66
|
+
error("#{key.inspect} must be a file")
|
|
67
|
+
false
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def error(message)
|
|
71
|
+
::Guard::UI.error "[guard-i18n-js] #{message}"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def info(message)
|
|
75
|
+
::Guard::UI.info "[guard-i18n-js] #{message}"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module I18nJS
|
|
4
|
+
class CLI
|
|
5
|
+
class Command
|
|
6
|
+
attr_reader :ui, :argv
|
|
7
|
+
|
|
8
|
+
def self.command_name(name)
|
|
9
|
+
define_method(:name) { name }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.description(description)
|
|
13
|
+
define_method(:description) { description }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.parse(&block)
|
|
17
|
+
define_method(:parse) do
|
|
18
|
+
OptionParser
|
|
19
|
+
.new {|opts| instance_exec(opts, &block) }
|
|
20
|
+
.parse!(argv)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.command(&block)
|
|
25
|
+
define_method(:command, &block)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def initialize(argv:, ui:)
|
|
29
|
+
@argv = argv.dup
|
|
30
|
+
@ui = ui
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def call
|
|
34
|
+
parse
|
|
35
|
+
command
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def options
|
|
39
|
+
@options ||= {}
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "benchmark"
|
|
4
|
+
|
|
5
|
+
module I18nJS
|
|
6
|
+
class CLI
|
|
7
|
+
class ExportCommand < Command
|
|
8
|
+
command_name "export"
|
|
9
|
+
description "Export translations as JSON files"
|
|
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 generated"
|
|
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("-h", "--help", "Prints this help") do
|
|
31
|
+
ui.exit_with opts.to_s
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
command do # rubocop:disable Metrics/BlockLength
|
|
36
|
+
set_defaults!
|
|
37
|
+
|
|
38
|
+
ui.stdout_print("=> config file:", options[:config_file].inspect)
|
|
39
|
+
ui.stdout_print("=> require file:", options[:require_file].inspect)
|
|
40
|
+
|
|
41
|
+
unless options[:config_file]
|
|
42
|
+
ui.fail_with("=> ERROR: you need to specify the config file")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
config_file = File.expand_path(options[:config_file])
|
|
46
|
+
|
|
47
|
+
if options[:require_file]
|
|
48
|
+
require_file = File.expand_path(options[:require_file])
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
unless File.file?(config_file)
|
|
52
|
+
ui.fail_with(
|
|
53
|
+
"=> ERROR: config file doesn't exist at",
|
|
54
|
+
config_file.inspect
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if require_file && !File.file?(require_file)
|
|
59
|
+
ui.fail_with(
|
|
60
|
+
"=> ERROR: require file doesn't exist at",
|
|
61
|
+
require_file.inspect
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
time = Benchmark.realtime do
|
|
66
|
+
load_require_file!(require_file) if require_file
|
|
67
|
+
I18nJS.call(config_file: config_file)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
ui.stdout_print("=> done in #{time.round(2)}s")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private def set_defaults!
|
|
74
|
+
config_file = "./config/i18n.yml"
|
|
75
|
+
require_file = "./config/environment.rb"
|
|
76
|
+
|
|
77
|
+
options[:config_file] ||= config_file if File.file?(config_file)
|
|
78
|
+
options[:require_file] ||= require_file if File.file?(require_file)
|
|
79
|
+
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
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module I18nJS
|
|
4
|
+
class CLI
|
|
5
|
+
class InitCommand < Command
|
|
6
|
+
command_name "init"
|
|
7
|
+
description "Initialize a project"
|
|
8
|
+
|
|
9
|
+
parse do |opts|
|
|
10
|
+
opts.banner = "Usage: i18n #{name} [options]"
|
|
11
|
+
|
|
12
|
+
opts.on(
|
|
13
|
+
"-cCONFIG_FILE",
|
|
14
|
+
"--config=CONFIG_FILE",
|
|
15
|
+
"The configuration file that will be generated"
|
|
16
|
+
) do |config_file|
|
|
17
|
+
options[:config_file] = config_file
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
opts.on("-h", "--help", "Prints this help") do
|
|
21
|
+
ui.exit_with opts.to_s
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
command do
|
|
26
|
+
file_path = File.expand_path(options[:config_file])
|
|
27
|
+
|
|
28
|
+
if File.file?(file_path)
|
|
29
|
+
ui.fail_with("ERROR: #{file_path} already exists!")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
FileUtils.mkdir_p(File.dirname(file_path))
|
|
33
|
+
|
|
34
|
+
File.open(file_path, "w") do |file|
|
|
35
|
+
file << <<~YAML
|
|
36
|
+
---
|
|
37
|
+
translations:
|
|
38
|
+
- file: app/javascript/locales.json
|
|
39
|
+
patterns:
|
|
40
|
+
- "*"
|
|
41
|
+
- "!*.activerecord"
|
|
42
|
+
- "!*.errors"
|
|
43
|
+
- "!*.number.nth"
|
|
44
|
+
|
|
45
|
+
YAML
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module I18nJS
|
|
4
|
+
class CLI
|
|
5
|
+
class UI
|
|
6
|
+
def initialize(stdout:, stderr:)
|
|
7
|
+
@stdout = stdout
|
|
8
|
+
@stderr = stderr
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def stdout_print(*message)
|
|
12
|
+
@stdout << "#{message.join(' ')}\n"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def stderr_print(*message)
|
|
16
|
+
@stderr << "#{message.join(' ')}\n"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def fail_with(*message)
|
|
20
|
+
stderr_print(message)
|
|
21
|
+
exit(1)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def exit_with(*message)
|
|
25
|
+
stdout_print(message)
|
|
26
|
+
exit(0)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module I18nJS
|
|
4
|
+
class CLI
|
|
5
|
+
class VersionCommand < Command
|
|
6
|
+
command_name "version"
|
|
7
|
+
description "Show package version"
|
|
8
|
+
|
|
9
|
+
parse do |opts|
|
|
10
|
+
opts.banner = "Usage: i18n #{name}"
|
|
11
|
+
|
|
12
|
+
opts.on_tail do
|
|
13
|
+
ui.exit_with("v#{I18nJS::VERSION}")
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/i18n-js/cli.rb
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module I18nJS
|
|
4
|
+
class CLI
|
|
5
|
+
attr_reader :ui
|
|
6
|
+
|
|
7
|
+
def initialize(argv:, stdout:, stderr:)
|
|
8
|
+
@argv = argv.dup
|
|
9
|
+
@ui = UI.new(stdout: stdout, stderr: stderr)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
command_name = @argv.shift
|
|
14
|
+
command = commands.find {|cmd| cmd.name == command_name }
|
|
15
|
+
|
|
16
|
+
ui.fail_with(root_help) unless command
|
|
17
|
+
|
|
18
|
+
command.call
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private def command_classes
|
|
22
|
+
[InitCommand, ExportCommand, VersionCommand]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private def commands
|
|
26
|
+
command_classes.map do |command_class|
|
|
27
|
+
command_class.new(argv: @argv, ui: ui)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private def root_help
|
|
32
|
+
commands_list = commands
|
|
33
|
+
.map {|cmd| "- #{cmd.name}: #{cmd.description}" }
|
|
34
|
+
.join("\n")
|
|
35
|
+
|
|
36
|
+
<<~TEXT
|
|
37
|
+
Usage: i18n COMMAND FLAGS
|
|
38
|
+
|
|
39
|
+
Commands:
|
|
40
|
+
|
|
41
|
+
#{commands_list}
|
|
42
|
+
|
|
43
|
+
Run `i18n COMMAND --help` for more information on specific commands.
|
|
44
|
+
TEXT
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
gem "listen"
|
|
4
|
+
require "listen"
|
|
5
|
+
require "i18n-js"
|
|
6
|
+
|
|
7
|
+
module I18nJS
|
|
8
|
+
class << self
|
|
9
|
+
attr_accessor :started
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.listen(
|
|
13
|
+
config_file: Rails.root.join("config/i18n.yml"),
|
|
14
|
+
locales_dir: Rails.root.join("config/locales")
|
|
15
|
+
)
|
|
16
|
+
return unless Rails.env.development?
|
|
17
|
+
return if started
|
|
18
|
+
|
|
19
|
+
self.started = true
|
|
20
|
+
|
|
21
|
+
relative_paths =
|
|
22
|
+
[config_file, locales_dir].map {|path| relative_path(path) }
|
|
23
|
+
|
|
24
|
+
debug("Watching #{relative_paths.inspect}")
|
|
25
|
+
|
|
26
|
+
listener(config_file, locales_dir.to_s).start
|
|
27
|
+
I18nJS.call(config_file: config_file)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def self.relative_path(path)
|
|
31
|
+
Pathname.new(path).relative_path_from(Rails.root).to_s
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.relative_path_list(paths)
|
|
35
|
+
paths.map {|path| relative_path(path) }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.debug(message)
|
|
39
|
+
logger.tagged("i18n-js") { logger.debug(message) }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.logger
|
|
43
|
+
@logger ||= ActiveSupport::TaggedLogging.new(Rails.logger)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.listener(config_file, locales_dir) # rubocop:disable Metrics/MethodLength
|
|
47
|
+
paths = [File.dirname(config_file), locales_dir]
|
|
48
|
+
|
|
49
|
+
Listen.to(*paths) do |changed, added, removed|
|
|
50
|
+
changes = compute_changes(
|
|
51
|
+
[config_file, locales_dir],
|
|
52
|
+
changed,
|
|
53
|
+
added,
|
|
54
|
+
removed
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
next unless changes.any?
|
|
58
|
+
|
|
59
|
+
debug(changes.map {|key, value| "#{key}=#{value.inspect}" }.join(", "))
|
|
60
|
+
|
|
61
|
+
I18nJS.call(config_file: config_file)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def self.compute_changes(paths, changed, added, removed)
|
|
66
|
+
paths = paths.map {|path| relative_path(path) }
|
|
67
|
+
|
|
68
|
+
{
|
|
69
|
+
changed: included_on_watched_paths(paths, changed),
|
|
70
|
+
added: included_on_watched_paths(paths, added),
|
|
71
|
+
removed: included_on_watched_paths(paths, removed)
|
|
72
|
+
}.select {|_k, v| v.any? }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.included_on_watched_paths(paths, changes)
|
|
76
|
+
changes.map {|change| relative_path(change) }.select do |change|
|
|
77
|
+
paths.any? {|path| change.start_with?(path) }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|