i18n-js 3.2.1 → 4.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +4 -0
  3. data/.github/FUNDING.yml +3 -0
  4. data/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
  5. data/.github/ISSUE_TEMPLATE/config.yml +5 -0
  6. data/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
  7. data/.github/PULL_REQUEST_TEMPLATE.md +38 -0
  8. data/.github/dependabot.yml +15 -0
  9. data/.github/workflows/ruby-tests.yml +73 -0
  10. data/.gitignore +13 -7
  11. data/.rubocop.yml +19 -0
  12. data/CHANGELOG.md +45 -386
  13. data/CODE_OF_CONDUCT.md +74 -0
  14. data/CONTRIBUTING.md +79 -0
  15. data/Gemfile +3 -0
  16. data/LICENSE.md +20 -0
  17. data/MIGRATING_FROM_V3_TO_V4.md +191 -0
  18. data/README.md +439 -791
  19. data/Rakefile +10 -20
  20. data/bin/release +81 -0
  21. data/exe/i18n +5 -0
  22. data/i18n-js.gemspec +51 -29
  23. data/lib/guard/i18n-js/templates/Guardfile +10 -0
  24. data/lib/guard/i18n-js/version.rb +13 -0
  25. data/lib/guard/i18n-js.rb +95 -0
  26. data/lib/i18n-js/clean_hash.rb +13 -0
  27. data/lib/i18n-js/cli/check_command.rb +17 -0
  28. data/lib/i18n-js/cli/command.rb +79 -0
  29. data/lib/i18n-js/cli/export_command.rb +95 -0
  30. data/lib/i18n-js/cli/init_command.rb +52 -0
  31. data/lib/i18n-js/cli/lint_scripts_command.rb +157 -0
  32. data/lib/i18n-js/cli/lint_translations_command.rb +155 -0
  33. data/lib/i18n-js/cli/plugins_command.rb +67 -0
  34. data/lib/i18n-js/cli/ui.rb +64 -0
  35. data/lib/i18n-js/cli/version_command.rb +18 -0
  36. data/lib/i18n-js/cli.rb +66 -0
  37. data/lib/i18n-js/embed_fallback_translations_plugin.rb +70 -0
  38. data/lib/i18n-js/export_files_plugin.rb +103 -0
  39. data/lib/i18n-js/lint.js +150645 -0
  40. data/lib/i18n-js/lint.ts +196 -0
  41. data/lib/i18n-js/listen.rb +96 -0
  42. data/lib/i18n-js/plugin.rb +103 -0
  43. data/lib/i18n-js/schema.rb +216 -0
  44. data/lib/i18n-js/sort_hash.rb +12 -0
  45. data/lib/i18n-js/version.rb +5 -0
  46. data/lib/i18n-js.rb +107 -1
  47. data/package.json +5 -20
  48. metadata +153 -181
  49. data/.editorconfig +0 -24
  50. data/.npmignore +0 -27
  51. data/.travis.yml +0 -36
  52. data/Appraisals +0 -32
  53. data/app/assets/javascripts/i18n/filtered.js.erb +0 -23
  54. data/app/assets/javascripts/i18n/shims.js +0 -208
  55. data/app/assets/javascripts/i18n/translations.js +0 -3
  56. data/app/assets/javascripts/i18n.js +0 -1077
  57. data/gemfiles/i18n_0_6.gemfile +0 -7
  58. data/gemfiles/i18n_0_7.gemfile +0 -7
  59. data/gemfiles/i18n_0_8.gemfile +0 -7
  60. data/gemfiles/i18n_0_9.gemfile +0 -7
  61. data/gemfiles/i18n_1_0.gemfile +0 -7
  62. data/gemfiles/i18n_1_1.gemfile +0 -7
  63. data/gemfiles/i18n_1_2.gemfile +0 -7
  64. data/gemfiles/i18n_1_3.gemfile +0 -7
  65. data/gemfiles/i18n_1_4.gemfile +0 -7
  66. data/gemfiles/i18n_1_5.gemfile +0 -7
  67. data/lib/i18n/js/dependencies.rb +0 -59
  68. data/lib/i18n/js/engine.rb +0 -87
  69. data/lib/i18n/js/fallback_locales.rb +0 -70
  70. data/lib/i18n/js/formatters/base.rb +0 -23
  71. data/lib/i18n/js/formatters/js.rb +0 -31
  72. data/lib/i18n/js/formatters/json.rb +0 -13
  73. data/lib/i18n/js/middleware.rb +0 -82
  74. data/lib/i18n/js/private/hash_with_symbol_keys.rb +0 -36
  75. data/lib/i18n/js/segment.rb +0 -75
  76. data/lib/i18n/js/utils.rb +0 -65
  77. data/lib/i18n/js/version.rb +0 -7
  78. data/lib/i18n/js.rb +0 -259
  79. data/lib/rails/generators/i18n/js/config/config_generator.rb +0 -19
  80. data/lib/rails/generators/i18n/js/config/templates/i18n-js.yml +0 -27
  81. data/lib/tasks/export.rake +0 -8
  82. data/spec/fixtures/custom_path.yml +0 -5
  83. data/spec/fixtures/default.yml +0 -5
  84. data/spec/fixtures/erb.yml +0 -5
  85. data/spec/fixtures/except_condition.yml +0 -7
  86. data/spec/fixtures/js_export_dir_custom.yml +0 -7
  87. data/spec/fixtures/js_export_dir_none.yml +0 -6
  88. data/spec/fixtures/js_extend_parent.yml +0 -6
  89. data/spec/fixtures/js_extend_segment.yml +0 -6
  90. data/spec/fixtures/js_file_per_locale.yml +0 -7
  91. data/spec/fixtures/js_file_per_locale_with_fallbacks_as_default_locale_symbol.yml +0 -4
  92. data/spec/fixtures/js_file_per_locale_with_fallbacks_as_hash.yml +0 -6
  93. data/spec/fixtures/js_file_per_locale_with_fallbacks_as_locale.yml +0 -4
  94. data/spec/fixtures/js_file_per_locale_with_fallbacks_as_locale_without_fallback_translations.yml +0 -4
  95. data/spec/fixtures/js_file_per_locale_with_fallbacks_enabled.yml +0 -4
  96. data/spec/fixtures/js_file_per_locale_without_fallbacks.yml +0 -4
  97. data/spec/fixtures/js_file_with_namespace_and_pretty_print.yml +0 -7
  98. data/spec/fixtures/js_sort_translation_keys_false.yml +0 -6
  99. data/spec/fixtures/js_sort_translation_keys_true.yml +0 -6
  100. data/spec/fixtures/json_only.yml +0 -18
  101. data/spec/fixtures/locales.yml +0 -95
  102. data/spec/fixtures/merge_plurals.yml +0 -6
  103. data/spec/fixtures/multiple_conditions.yml +0 -7
  104. data/spec/fixtures/multiple_conditions_per_locale.yml +0 -7
  105. data/spec/fixtures/multiple_files.yml +0 -7
  106. data/spec/fixtures/no_config.yml +0 -2
  107. data/spec/fixtures/no_scope.yml +0 -4
  108. data/spec/fixtures/simple_scope.yml +0 -5
  109. data/spec/js/currency.spec.js +0 -62
  110. data/spec/js/current_locale.spec.js +0 -19
  111. data/spec/js/dates.spec.js +0 -265
  112. data/spec/js/defaults.spec.js +0 -31
  113. data/spec/js/extend.spec.js +0 -110
  114. data/spec/js/interpolation.spec.js +0 -124
  115. data/spec/js/jasmine/MIT.LICENSE +0 -20
  116. data/spec/js/jasmine/jasmine-html.js +0 -190
  117. data/spec/js/jasmine/jasmine.css +0 -166
  118. data/spec/js/jasmine/jasmine.js +0 -2476
  119. data/spec/js/jasmine/jasmine_favicon.png +0 -0
  120. data/spec/js/locales.spec.js +0 -31
  121. data/spec/js/localization.spec.js +0 -48
  122. data/spec/js/numbers.spec.js +0 -170
  123. data/spec/js/placeholder.spec.js +0 -24
  124. data/spec/js/pluralization.spec.js +0 -211
  125. data/spec/js/prepare_options.spec.js +0 -41
  126. data/spec/js/require.js +0 -2083
  127. data/spec/js/specs.html +0 -49
  128. data/spec/js/specs_requirejs.html +0 -72
  129. data/spec/js/translate.spec.js +0 -284
  130. data/spec/js/translations.js +0 -163
  131. data/spec/js/utility_functions.spec.js +0 -20
  132. data/spec/ruby/i18n/js/fallback_locales_spec.rb +0 -84
  133. data/spec/ruby/i18n/js/segment_spec.rb +0 -219
  134. data/spec/ruby/i18n/js/utils_spec.rb +0 -106
  135. data/spec/ruby/i18n/js_spec.rb +0 -663
  136. data/spec/spec_helper.rb +0 -79
  137. data/yarn.lock +0 -131
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "i18n", "~> 0.6.0"
6
-
7
- gemspec path: "../"
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "i18n", "~> 0.7.0"
6
-
7
- gemspec path: "../"
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "i18n", "~> 0.8.0"
6
-
7
- gemspec path: "../"
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "i18n", "~> 0.9.0"
6
-
7
- gemspec path: "../"
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "i18n", "~> 1.0.0"
6
-
7
- gemspec path: "../"
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "i18n", "~> 1.1.0"
6
-
7
- gemspec path: "../"
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "i18n", "~> 1.2.0"
6
-
7
- gemspec path: "../"
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "i18n", "~> 1.3.0"
6
-
7
- gemspec path: "../"
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "i18n", "~> 1.4.0"
6
-
7
- gemspec path: "../"
@@ -1,7 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "i18n", "~> 1.5.1"
6
-
7
- gemspec path: "../"
@@ -1,59 +0,0 @@
1
- module I18n
2
- module JS
3
- # When using `safe_gem_check` to check for a pre-release version of gem,
4
- # we need to specify pre-release version suffix in version constraint
5
- module Dependencies
6
- class << self
7
- def rails?
8
- defined?(Rails) && Rails.respond_to?(:version)
9
- end
10
-
11
- def sprockets_rails_v2_plus?
12
- safe_gem_check("sprockets-rails", ">= 2")
13
- end
14
-
15
- # This cannot be called at class definition time
16
- # Since not all libraries are loaded
17
- #
18
- # Call this in an initializer
19
- def using_asset_pipeline?
20
- assets_pipeline_available =
21
- (rails3? || rails4? || rails5?) &&
22
- Rails.respond_to?(:application) &&
23
- Rails.application.config.respond_to?(:assets)
24
- rails3_assets_enabled =
25
- rails3? &&
26
- assets_pipeline_available &&
27
- Rails.application.config.assets.enabled != false
28
-
29
- assets_pipeline_available && (rails4? || rails5? || rails3_assets_enabled)
30
- end
31
-
32
- private
33
-
34
- def rails3?
35
- rails? && Rails.version.to_i == 3
36
- end
37
-
38
- def rails4?
39
- rails? && Rails.version.to_i == 4
40
- end
41
-
42
- def rails5?
43
- rails? && Rails.version.to_i == 5
44
- end
45
-
46
- def safe_gem_check(*args)
47
- if Gem::Specification.respond_to?(:find_by_name)
48
- Gem::Specification.find_by_name(*args)
49
- elsif Gem.respond_to?(:available?)
50
- Gem.available?(*args)
51
- end
52
- rescue Gem::LoadError
53
- false
54
- end
55
-
56
- end
57
- end
58
- end
59
- end
@@ -1,87 +0,0 @@
1
- require "i18n/js"
2
-
3
- module I18n
4
- module JS
5
- # @api private
6
- # The class cannot be private
7
- class SprocketsExtension
8
- # Actual definition is placed below
9
- end
10
-
11
- class Engine < ::Rails::Engine
12
- # See https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md#supporting-all-versions-of-sprockets-in-processors
13
- # for reference of supporting multiple versions
14
-
15
- # `sprockets.environment` was used for 1.x of `sprockets-rails`
16
- # https://github.com/rails/sprockets-rails/issues/227
17
- #
18
- # References for current values:
19
- #
20
- # Here is where sprockets are attached with Rails. There is no 'sprockets.environment' mentioned.
21
- # https://github.com/rails/sprockets-rails/blob/master/lib/sprockets/railtie.rb
22
- #
23
- # Finisher hook is the place which should be used as border.
24
- # http://guides.rubyonrails.org/configuring.html#initializers
25
- #
26
- # For detail see Pull Request:
27
- # https://github.com/fnando/i18n-js/pull/371
28
- initializer "i18n-js.register_preprocessor", after: :engines_blank_point, before: :finisher_hook do
29
- # This must be called inside initializer block
30
- # For details see comments for `using_asset_pipeline?`
31
- next unless JS::Dependencies.using_asset_pipeline?
32
-
33
- # From README of 2.x & 3.x of `sprockets-rails`
34
- # It seems the `configure` block is preferred way to call `register_preprocessor`
35
- # Not sure if this will break older versions of rails
36
- #
37
- # https://github.com/rails/sprockets-rails/blob/v2.3.3/README.md
38
- # https://github.com/rails/sprockets-rails/blob/v3.0.0/README.md
39
- if JS::Dependencies.sprockets_rails_v2_plus?
40
- Rails.application.config.assets.configure do |config|
41
- config.register_preprocessor("application/javascript", ::I18n::JS::SprocketsExtension)
42
- end
43
- elsif Rails.application.assets.respond_to?(:register_preprocessor)
44
- Rails.application.assets.register_preprocessor("application/javascript", ::I18n::JS::SprocketsExtension)
45
- end
46
- end
47
- end
48
-
49
- # @api private
50
- class SprocketsExtension
51
- def initialize(filename, &block)
52
- @filename = filename
53
- @source = block.call
54
- end
55
-
56
- def render(context, empty_hash_wtf)
57
- self.class.run(@filename, @source, context)
58
- end
59
-
60
- def self.run(filename, source, context)
61
- if context.logical_path == "i18n/filtered"
62
- ::I18n.load_path.each { |path| context.depend_on(File.expand_path(path)) }
63
-
64
- # Absolute path is required or
65
- # Sprockets assumes it's a logical path
66
- #
67
- # Calling `depend on` with an absent file
68
- # will invoke `resolve` and will throw an error in the end
69
- if I18n::JS.config_file_exists?
70
- context.depend_on(File.expand_path(I18n::JS.config_file_path))
71
- end
72
- end
73
-
74
- source
75
- end
76
-
77
- def self.call(input)
78
- filename = input[:filename]
79
- source = input[:data]
80
- context = input[:environment].context_class.new(input)
81
-
82
- result = run(filename, source, context)
83
- context.metadata.merge(data: result)
84
- end
85
- end
86
- end
87
- end
@@ -1,70 +0,0 @@
1
- module I18n
2
- module JS
3
- class FallbackLocales
4
- attr_reader :fallbacks, :locale
5
-
6
- def initialize(fallbacks, locale)
7
- @fallbacks = fallbacks
8
- @locale = locale
9
- end
10
-
11
- def each
12
- locales.each { |locale| yield(locale) }
13
- end
14
-
15
- # @return [Array<String, Symbol>]
16
- # An Array of locales to use as fallbacks for given locale.
17
- def locales
18
- locales = case fallbacks
19
- when true
20
- default_fallbacks
21
- when :default_locale
22
- [::I18n.default_locale]
23
- when Symbol, String
24
- [fallbacks.to_sym]
25
- when Array
26
- ensure_valid_fallbacks_as_array!
27
- fallbacks
28
- when Hash
29
- Array(fallbacks[locale] || default_fallbacks)
30
- else
31
- fail ArgumentError, "fallbacks must be: true, :default_locale an Array or a Hash - given: #{fallbacks}"
32
- end
33
-
34
- locales.map! { |locale| locale.to_sym }
35
- locales
36
- end
37
-
38
- private
39
-
40
- # @return [Array<String, Symbol>] An Array of locales.
41
- def default_fallbacks
42
- if using_i18n_fallbacks_module?
43
- I18n.fallbacks[locale]
44
- else
45
- [::I18n.default_locale]
46
- end
47
- end
48
-
49
- # @return
50
- # true if we can safely use I18n.fallbacks, false otherwise.
51
- #
52
- # @note
53
- # We should implement this as `I18n.respond_to?(:fallbacks)`, but
54
- # once I18n::Backend::Fallbacks is included, I18n will _always_
55
- # respond to :fallbacks. Even if we switch the backend to one
56
- # without fallbacks!
57
- #
58
- # Maybe this should be fixed within I18n.
59
- def using_i18n_fallbacks_module?
60
- I18n::JS.backend.class.included_modules.include?(I18n::Backend::Fallbacks)
61
- end
62
-
63
- def ensure_valid_fallbacks_as_array!
64
- return if fallbacks.all? { |e| e.is_a?(String) || e.is_a?(Symbol) }
65
-
66
- fail ArgumentError, "If fallbacks is passed as Array, it must ony include Strings or Symbols. Given: #{fallbacks}"
67
- end
68
- end
69
- end
70
- end
@@ -1,23 +0,0 @@
1
- module I18n
2
- module JS
3
- module Formatters
4
- class Base
5
- def initialize(js_extend: false, namespace: nil, pretty_print: false)
6
- @js_extend = js_extend
7
- @namespace = namespace
8
- @pretty_print = pretty_print
9
- end
10
-
11
- protected
12
-
13
- def format_json(translations)
14
- if @pretty_print
15
- ::JSON.pretty_generate(translations)
16
- else
17
- translations.to_json
18
- end
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,31 +0,0 @@
1
- require "i18n/js/formatters/base"
2
-
3
- module I18n
4
- module JS
5
- module Formatters
6
- class JS < Base
7
- def format(translations)
8
- contents = header
9
- translations.each do |locale, translations_for_locale|
10
- contents << line(locale, format_json(translations_for_locale))
11
- end
12
- contents
13
- end
14
-
15
- protected
16
-
17
- def header
18
- %(#{@namespace}.translations || (#{@namespace}.translations = {});\n)
19
- end
20
-
21
- def line(locale, translations)
22
- if @js_extend
23
- %(#{@namespace}.translations["#{locale}"] = I18n.extend((#{@namespace}.translations["#{locale}"] || {}), #{translations});\n)
24
- else
25
- %(#{@namespace}.translations["#{locale}"] = #{translations};\n)
26
- end
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,13 +0,0 @@
1
- require "i18n/js/formatters/base"
2
-
3
- module I18n
4
- module JS
5
- module Formatters
6
- class JSON < Base
7
- def format(translations)
8
- format_json(translations)
9
- end
10
- end
11
- end
12
- end
13
- end
@@ -1,82 +0,0 @@
1
- require "fileutils"
2
-
3
- module I18n
4
- module JS
5
- class Middleware
6
- def initialize(app)
7
- @app = app
8
- clear_cache
9
- end
10
-
11
- def call(env)
12
- @cache = nil
13
- verify_locale_files!
14
- @app.call(env)
15
- end
16
-
17
- private
18
- def cache_path
19
- @cache_path ||= cache_dir.join("i18n-js.yml")
20
- end
21
-
22
- def cache_dir
23
- @cache_dir ||= Rails.root.join("tmp/cache")
24
- end
25
-
26
- def cache
27
- @cache ||= begin
28
- if cache_path.exist?
29
- YAML.load_file(cache_path) || {}
30
- else
31
- {}
32
- end
33
- end
34
- end
35
-
36
- def clear_cache
37
- # `File.delete` will raise error when "multiple worker"
38
- # Are running at the same time, like in a parallel test
39
- #
40
- # `FileUtils.rm_f` is tested manually
41
- #
42
- # See https://github.com/fnando/i18n-js/issues/436
43
- FileUtils.rm_f(cache_path) if File.exist?(cache_path)
44
- end
45
-
46
- def save_cache(new_cache)
47
- # path could be a symbolic link
48
- FileUtils.mkdir_p(cache_dir) unless File.exists?(cache_dir)
49
- File.open(cache_path, "w+") do |file|
50
- file << new_cache.to_yaml
51
- end
52
- end
53
-
54
- # Check if translations should be regenerated.
55
- # ONLY REGENERATE when these conditions are met:
56
- #
57
- # # Cache file doesn't exist
58
- # # Translations and cache size are different (files were removed/added)
59
- # # Translation file has been updated
60
- #
61
- def verify_locale_files!
62
- valid_cache = []
63
- new_cache = {}
64
-
65
- valid_cache.push cache_path.exist?
66
- valid_cache.push ::I18n.load_path.uniq.size == cache.size
67
-
68
- ::I18n.load_path.each do |path|
69
- changed_at = File.mtime(path).to_i
70
- valid_cache.push changed_at == cache[path]
71
- new_cache[path] = changed_at
72
- end
73
-
74
- return if valid_cache.all?
75
-
76
- save_cache(new_cache)
77
-
78
- ::I18n::JS.export
79
- end
80
- end
81
- end
82
- end
@@ -1,36 +0,0 @@
1
- module I18n
2
- module JS
3
- # @api private
4
- module Private
5
- # Hash with string keys converted to symbol keys
6
- # Used for handling values read on YAML
7
- #
8
- # @api private
9
- class HashWithSymbolKeys < ::Hash
10
- # An instance can only be created by passing in another hash
11
- def initialize(hash)
12
- raise TypeError unless hash.is_a?(::Hash)
13
-
14
- hash.each_key do |key|
15
- # Objects like `Integer` does not have `to_sym`
16
- new_key = key.respond_to?(:to_sym) ? key.to_sym : key
17
- self[new_key] = hash[key]
18
- end
19
-
20
- self.default = hash.default if hash.default
21
- self.default_proc = hash.default_proc if hash.default_proc
22
-
23
- freeze
24
- end
25
-
26
- # From AS Core extension
27
- def slice(*keys)
28
- hash = keys.each_with_object(Hash.new) do |k, hash|
29
- hash[k] = self[k] if has_key?(k)
30
- end
31
- self.class.new(hash)
32
- end
33
- end
34
- end
35
- end
36
- end
@@ -1,75 +0,0 @@
1
- require "i18n/js/private/hash_with_symbol_keys"
2
- require "i18n/js/formatters/js"
3
- require "i18n/js/formatters/json"
4
-
5
- module I18n
6
- module JS
7
-
8
- # Class which enscapulates a translations hash and outputs a single JSON translation file
9
- class Segment
10
- OPTIONS = [:namespace, :pretty_print, :js_extend, :sort_translation_keys, :json_only].freeze
11
- LOCALE_INTERPOLATOR = /%\{locale\}/
12
-
13
- attr_reader *([:file, :translations] | OPTIONS)
14
-
15
- def initialize(file, translations, options = {})
16
- @file = file
17
- # `#slice` will be used
18
- # But when activesupport is absent,
19
- # the core extension from `i18n` gem will be used instead
20
- # And it's causing errors (at least in test)
21
- #
22
- # So the input is wrapped by our class for better `#slice`
23
- @translations = Private::HashWithSymbolKeys.new(translations)
24
- @namespace = options[:namespace] || 'I18n'
25
- @pretty_print = !!options[:pretty_print]
26
- @js_extend = options.key?(:js_extend) ? !!options[:js_extend] : true
27
- @sort_translation_keys = options.key?(:sort_translation_keys) ? !!options[:sort_translation_keys] : true
28
- @json_only = options.key?(:json_only) ? !!options[:json_only] : false
29
- end
30
-
31
- # Saves JSON file containing translations
32
- def save!
33
- if @file =~ LOCALE_INTERPOLATOR
34
- I18n.available_locales.each do |locale|
35
- write_file(file_for_locale(locale), @translations.slice(locale))
36
- end
37
- else
38
- write_file
39
- end
40
- end
41
-
42
- protected
43
-
44
- def file_for_locale(locale)
45
- @file.gsub(LOCALE_INTERPOLATOR, locale.to_s)
46
- end
47
-
48
- def write_file(_file = @file, _translations = @translations)
49
- FileUtils.mkdir_p File.dirname(_file)
50
- _translations = Utils.deep_key_sort(_translations) if @sort_translation_keys
51
- contents = formatter.format(_translations)
52
-
53
- return if File.exist?(_file) && File.read(_file) == contents
54
-
55
- File.open(_file, "w+") do |f|
56
- f << contents
57
- end
58
- end
59
-
60
- def formatter
61
- if @json_only
62
- Formatters::JSON.new(**formatter_options)
63
- else
64
- Formatters::JS.new(**formatter_options)
65
- end
66
- end
67
-
68
- def formatter_options
69
- { js_extend: @js_extend,
70
- namespace: @namespace,
71
- pretty_print: @pretty_print }
72
- end
73
- end
74
- end
75
- end
data/lib/i18n/js/utils.rb DELETED
@@ -1,65 +0,0 @@
1
- module I18n
2
- module JS
3
- module Utils
4
- PLURAL_KEYS = %i[zero one two few many other].freeze
5
-
6
- # Based on deep_merge by Stefan Rusterholz, see <http://www.ruby-forum.com/topic/142809>.
7
- # This method is used to handle I18n fallbacks. Given two equivalent path nodes in two locale trees:
8
- # 1. If the node in the current locale appears to be an I18n pluralization (:one, :other, etc.),
9
- # use the node as-is without merging. This prevents mixing locales with different pluralization schemes.
10
- # 2. Else if both nodes are Hashes, combine (merge) the key-value pairs of the two nodes into one,
11
- # prioritizing the current locale.
12
- # 3. Else if either node is nil, use the other node.
13
- MERGER = proc do |_key, v1, v2|
14
- if Hash === v2 && (v2.keys - PLURAL_KEYS).empty?
15
- v2
16
- elsif Hash === v1 && Hash === v2
17
- v1.merge(v2, &MERGER)
18
- else
19
- v2.nil? ? v1 : v2
20
- end
21
- end
22
-
23
- HASH_NIL_VALUE_CLEANER_PROC = proc do |k, v|
24
- v.kind_of?(Hash) ? (v.delete_if(&HASH_NIL_VALUE_CLEANER_PROC); false) : v.nil?
25
- end
26
-
27
- def self.strip_keys_with_nil_values(hash)
28
- hash.dup.delete_if(&HASH_NIL_VALUE_CLEANER_PROC)
29
- end
30
-
31
- def self.deep_merge(target_hash, hash) # :nodoc:
32
- target_hash.merge(hash, &MERGER)
33
- end
34
-
35
- def self.deep_merge!(target_hash, hash) # :nodoc:
36
- target_hash.merge!(hash, &MERGER)
37
- end
38
-
39
- def self.deep_reject(hash, scopes = [], &block)
40
- hash.each_with_object({}) do |(k, v), memo|
41
- unless block.call(k, v, scopes + [k.to_s])
42
- memo[k] = v.kind_of?(Hash) ? deep_reject(v, scopes + [k.to_s], &block) : v
43
- end
44
- end
45
- end
46
-
47
- def self.scopes_match?(scopes1, scopes2)
48
- if scopes1.length == scopes2.length
49
- [scopes1, scopes2].transpose.all? do |scope1, scope2|
50
- scope1.to_s == '*' || scope2.to_s == '*' || scope1.to_s == scope2.to_s
51
- end
52
- end
53
- end
54
-
55
- def self.deep_key_sort(hash)
56
- # Avoid things like `true` or `1` from YAML which causes error
57
- hash.keys.sort {|a, b| a.to_s <=> b.to_s}.
58
- each_with_object({}) do |key, seed|
59
- value = hash[key]
60
- seed[key] = value.is_a?(Hash) ? deep_key_sort(value) : value
61
- end
62
- end
63
- end
64
- end
65
- end
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module I18n
4
- module JS
5
- VERSION = "3.2.1"
6
- end
7
- end