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.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +4 -0
- data/.github/FUNDING.yml +3 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
- data/.github/ISSUE_TEMPLATE/config.yml +5 -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 +73 -0
- data/.gitignore +13 -7
- data/.rubocop.yml +19 -0
- data/CHANGELOG.md +45 -386
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +79 -0
- data/Gemfile +3 -0
- data/LICENSE.md +20 -0
- data/MIGRATING_FROM_V3_TO_V4.md +191 -0
- data/README.md +439 -791
- data/Rakefile +10 -20
- data/bin/release +81 -0
- data/exe/i18n +5 -0
- data/i18n-js.gemspec +51 -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 +95 -0
- data/lib/i18n-js/clean_hash.rb +13 -0
- data/lib/i18n-js/cli/check_command.rb +17 -0
- data/lib/i18n-js/cli/command.rb +79 -0
- data/lib/i18n-js/cli/export_command.rb +95 -0
- data/lib/i18n-js/cli/init_command.rb +52 -0
- data/lib/i18n-js/cli/lint_scripts_command.rb +157 -0
- data/lib/i18n-js/cli/lint_translations_command.rb +155 -0
- data/lib/i18n-js/cli/plugins_command.rb +67 -0
- data/lib/i18n-js/cli/ui.rb +64 -0
- data/lib/i18n-js/cli/version_command.rb +18 -0
- data/lib/i18n-js/cli.rb +66 -0
- data/lib/i18n-js/embed_fallback_translations_plugin.rb +70 -0
- data/lib/i18n-js/export_files_plugin.rb +103 -0
- data/lib/i18n-js/lint.js +150645 -0
- data/lib/i18n-js/lint.ts +196 -0
- data/lib/i18n-js/listen.rb +96 -0
- data/lib/i18n-js/plugin.rb +103 -0
- data/lib/i18n-js/schema.rb +216 -0
- data/lib/i18n-js/sort_hash.rb +12 -0
- data/lib/i18n-js/version.rb +5 -0
- data/lib/i18n-js.rb +107 -1
- data/package.json +5 -20
- metadata +153 -181
- data/.editorconfig +0 -24
- data/.npmignore +0 -27
- data/.travis.yml +0 -36
- data/Appraisals +0 -32
- data/app/assets/javascripts/i18n/filtered.js.erb +0 -23
- data/app/assets/javascripts/i18n/shims.js +0 -208
- data/app/assets/javascripts/i18n/translations.js +0 -3
- data/app/assets/javascripts/i18n.js +0 -1077
- 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_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/lib/i18n/js/dependencies.rb +0 -59
- 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 -23
- data/lib/i18n/js/formatters/js.rb +0 -31
- data/lib/i18n/js/formatters/json.rb +0 -13
- data/lib/i18n/js/middleware.rb +0 -82
- data/lib/i18n/js/private/hash_with_symbol_keys.rb +0 -36
- data/lib/i18n/js/segment.rb +0 -75
- data/lib/i18n/js/utils.rb +0 -65
- data/lib/i18n/js/version.rb +0 -7
- data/lib/i18n/js.rb +0 -259
- 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/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_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_and_pretty_print.yml +0 -7
- 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 -95
- data/spec/fixtures/merge_plurals.yml +0 -6
- 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 -265
- 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/locales.spec.js +0 -31
- data/spec/js/localization.spec.js +0 -48
- data/spec/js/numbers.spec.js +0 -170
- data/spec/js/placeholder.spec.js +0 -24
- data/spec/js/pluralization.spec.js +0 -211
- 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 -284
- data/spec/js/translations.js +0 -163
- 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 -219
- data/spec/ruby/i18n/js/utils_spec.rb +0 -106
- data/spec/ruby/i18n/js_spec.rb +0 -663
- data/spec/spec_helper.rb +0 -79
- data/yarn.lock +0 -131
data/gemfiles/i18n_0_6.gemfile
DELETED
data/gemfiles/i18n_0_7.gemfile
DELETED
data/gemfiles/i18n_0_8.gemfile
DELETED
data/gemfiles/i18n_0_9.gemfile
DELETED
data/gemfiles/i18n_1_0.gemfile
DELETED
data/gemfiles/i18n_1_1.gemfile
DELETED
data/gemfiles/i18n_1_2.gemfile
DELETED
data/gemfiles/i18n_1_3.gemfile
DELETED
data/gemfiles/i18n_1_4.gemfile
DELETED
data/gemfiles/i18n_1_5.gemfile
DELETED
data/lib/i18n/js/dependencies.rb
DELETED
@@ -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
|
data/lib/i18n/js/engine.rb
DELETED
@@ -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
|
data/lib/i18n/js/middleware.rb
DELETED
@@ -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
|
data/lib/i18n/js/segment.rb
DELETED
@@ -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
|