i18n-js 3.0.0.rc8 → 3.0.0.rc9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/Appraisals +5 -1
- data/CHANGELOG.md +13 -0
- data/README.md +104 -7
- data/app/assets/javascripts/i18n.js +85 -49
- data/app/assets/javascripts/i18n/filtered.js.erb +1 -3
- data/gemfiles/i18n_0_7.gemfile +7 -0
- data/i18n-js.gemspec +0 -1
- data/lib/i18n/js.rb +54 -44
- data/lib/i18n/js/dependencies.rb +8 -6
- data/lib/i18n/js/segment.rb +39 -0
- data/lib/i18n/js/utils.rb +10 -2
- data/lib/i18n/js/version.rb +1 -1
- data/package.json +4 -0
- data/spec/fixtures/except_condition.yml +5 -0
- data/spec/fixtures/js_export_dir_custom.yml +6 -0
- data/spec/fixtures/js_export_dir_none.yml +6 -0
- data/spec/fixtures/js_file_with_namespace_and_pretty_print.yml +5 -0
- data/spec/i18n_js_spec.rb +139 -118
- data/spec/js/currency.spec.js +3 -1
- data/spec/js/defaults.spec.js +8 -0
- data/spec/js/interpolation.spec.js +58 -4
- data/spec/js/require.js +2083 -0
- data/spec/js/specs_requirejs.html +71 -0
- data/spec/js/translate.spec.js +21 -0
- data/spec/js/translations.js +3 -1
- data/spec/segment_spec.rb +71 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/sprockets_spec.rb +42 -0
- data/spec/utils_spec.rb +69 -0
- metadata +23 -17
@@ -1,14 +1,12 @@
|
|
1
1
|
<%# encoding: utf-8 %>
|
2
2
|
|
3
3
|
;(function(factory) {
|
4
|
-
if (typeof module !== 'undefined') {
|
4
|
+
if (typeof module !== 'undefined' && module.exports) {
|
5
5
|
// Node/CommonJS
|
6
6
|
factory(require('i18n'));
|
7
|
-
|
8
7
|
} else if (typeof define === 'function' && define.amd) {
|
9
8
|
// AMD
|
10
9
|
define(['i18n'], factory);
|
11
|
-
|
12
10
|
} else {
|
13
11
|
// Browser globals
|
14
12
|
factory(this.I18n);
|
data/i18n-js.gemspec
CHANGED
@@ -23,7 +23,6 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_development_dependency "activesupport", ">= 3"
|
24
24
|
s.add_development_dependency "rspec", "~> 3.0"
|
25
25
|
s.add_development_dependency "rake"
|
26
|
-
s.add_development_dependency "pry-meta"
|
27
26
|
s.add_development_dependency "gem-release", ">= 0.7"
|
28
27
|
|
29
28
|
s.required_ruby_version = ">= 1.9.3"
|
data/lib/i18n/js.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
|
+
require "yaml"
|
1
2
|
require "i18n"
|
2
3
|
require "fileutils"
|
3
|
-
|
4
4
|
require "i18n/js/utils"
|
5
5
|
|
6
6
|
module I18n
|
7
7
|
module JS
|
8
8
|
require "i18n/js/dependencies"
|
9
9
|
require "i18n/js/fallback_locales"
|
10
|
+
require "i18n/js/segment"
|
10
11
|
if JS::Dependencies.rails?
|
11
12
|
require "i18n/js/middleware"
|
12
13
|
require "i18n/js/engine"
|
@@ -20,6 +21,7 @@ module I18n
|
|
20
21
|
def self.config_file_path
|
21
22
|
@config_file_path ||= DEFAULT_CONFIG_PATH
|
22
23
|
end
|
24
|
+
|
23
25
|
def self.config_file_path=(new_path)
|
24
26
|
@config_file_path = new_path
|
25
27
|
end
|
@@ -29,48 +31,51 @@ module I18n
|
|
29
31
|
def self.export
|
30
32
|
export_i18n_js
|
31
33
|
|
32
|
-
translation_segments.each
|
33
|
-
save(translations, filename)
|
34
|
-
end
|
34
|
+
translation_segments.each(&:save!)
|
35
35
|
end
|
36
36
|
|
37
|
-
def self.segments_per_locale(pattern, scope)
|
38
|
-
I18n.available_locales.each_with_object(
|
37
|
+
def self.segments_per_locale(pattern, scope, exceptions, options)
|
38
|
+
I18n.available_locales.each_with_object([]) do |locale, segments|
|
39
39
|
scope = [scope] unless scope.respond_to?(:each)
|
40
|
-
result = scoped_translations(scope.collect{|s| "#{locale}.#{s}"})
|
41
|
-
merge_with_fallbacks!(result, locale, scope) if use_fallbacks?
|
40
|
+
result = scoped_translations(scope.collect{|s| "#{locale}.#{s}"}, exceptions)
|
41
|
+
merge_with_fallbacks!(result, locale, scope, exceptions) if use_fallbacks?
|
42
42
|
|
43
43
|
next if result.empty?
|
44
|
-
|
45
|
-
segment_name = ::I18n.interpolate(pattern,{:locale => locale})
|
46
|
-
segments[segment_name] = result
|
44
|
+
segments << Segment.new(::I18n.interpolate(pattern, {:locale => locale}), result, options)
|
47
45
|
end
|
48
46
|
end
|
49
47
|
|
50
|
-
def self.segment_for_scope(scope)
|
48
|
+
def self.segment_for_scope(scope, exceptions)
|
51
49
|
if scope == "*"
|
52
|
-
translations
|
50
|
+
exclude(translations, exceptions)
|
53
51
|
else
|
54
|
-
scoped_translations(scope)
|
52
|
+
scoped_translations(scope, exceptions)
|
55
53
|
end
|
56
54
|
end
|
57
55
|
|
58
56
|
def self.configured_segments
|
59
|
-
config[:translations].
|
60
|
-
options
|
61
|
-
|
62
|
-
|
57
|
+
config[:translations].inject([]) do |segments, options|
|
58
|
+
file = options[:file]
|
59
|
+
only = options[:only] || '*'
|
60
|
+
exceptions = [options[:except] || []].flatten
|
61
|
+
|
62
|
+
segment_options = options.slice(:namespace, :pretty_print)
|
63
|
+
|
64
|
+
if file =~ ::I18n::INTERPOLATION_PATTERN
|
65
|
+
segments += segments_per_locale(file, only, exceptions, segment_options)
|
63
66
|
else
|
64
|
-
result = segment_for_scope(
|
65
|
-
segments
|
67
|
+
result = segment_for_scope(only, exceptions)
|
68
|
+
segments << Segment.new(file, result, segment_options) unless result.empty?
|
66
69
|
end
|
70
|
+
|
71
|
+
segments
|
67
72
|
end
|
68
73
|
end
|
69
74
|
|
70
75
|
def self.filtered_translations
|
71
76
|
{}.tap do |result|
|
72
|
-
translation_segments.each do |
|
73
|
-
Utils.deep_merge!(result, translations)
|
77
|
+
translation_segments.each do |segment|
|
78
|
+
Utils.deep_merge!(result, segment.translations)
|
74
79
|
end
|
75
80
|
end
|
76
81
|
end
|
@@ -79,7 +84,7 @@ module I18n
|
|
79
84
|
if config? && config[:translations]
|
80
85
|
configured_segments
|
81
86
|
else
|
82
|
-
|
87
|
+
[Segment.new("#{DEFAULT_EXPORT_DIR_PATH}/translations.js", translations)]
|
83
88
|
end
|
84
89
|
end
|
85
90
|
|
@@ -99,28 +104,30 @@ module I18n
|
|
99
104
|
File.file? config_file_path
|
100
105
|
end
|
101
106
|
|
102
|
-
|
103
|
-
def self.save(translations, file)
|
104
|
-
FileUtils.mkdir_p File.dirname(file)
|
105
|
-
|
106
|
-
File.open(file, "w+") do |f|
|
107
|
-
f << %(I18n.translations || (I18n.translations = {});\n)
|
108
|
-
Utils.strip_keys_with_nil_values(translations).each do |locale, translations_for_locale|
|
109
|
-
f << %(I18n.translations["#{locale}"] = #{translations_for_locale.to_json};\n);
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def self.scoped_translations(scopes) # :nodoc:
|
107
|
+
def self.scoped_translations(scopes, exceptions = []) # :nodoc:
|
115
108
|
result = {}
|
116
109
|
|
117
110
|
[scopes].flatten.each do |scope|
|
118
|
-
|
111
|
+
translations_without_exceptions = exclude(translations, exceptions)
|
112
|
+
filtered_translations = filter(translations_without_exceptions, scope)
|
113
|
+
|
114
|
+
Utils.deep_merge! result, filtered_translations
|
119
115
|
end
|
120
116
|
|
121
117
|
result
|
122
118
|
end
|
123
119
|
|
120
|
+
# Exclude keys from translations listed in the `except:` section in the config file
|
121
|
+
def self.exclude(translations, exceptions)
|
122
|
+
return translations if exceptions.empty?
|
123
|
+
|
124
|
+
exceptions.inject(translations) do |memo, exception|
|
125
|
+
Utils.deep_reject(memo) do |key, value|
|
126
|
+
key.to_s == exception.to_s
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
124
131
|
# Filter translations according to the specified scope.
|
125
132
|
def self.filter(translations, scopes)
|
126
133
|
scopes = scopes.split(".") if scopes.is_a?(String)
|
@@ -160,35 +167,38 @@ module I18n
|
|
160
167
|
end
|
161
168
|
|
162
169
|
# deep_merge! given result with result for fallback locale
|
163
|
-
def self.merge_with_fallbacks!(result, locale, scope)
|
170
|
+
def self.merge_with_fallbacks!(result, locale, scope, exceptions)
|
164
171
|
result[locale] ||= {}
|
165
172
|
fallback_locales = FallbackLocales.new(fallbacks, locale)
|
166
173
|
|
167
174
|
fallback_locales.each do |fallback_locale|
|
168
|
-
fallback_result = scoped_translations(scope.collect{|s| "#{fallback_locale}.#{s}"}) # NOTE: Duplicated code here
|
175
|
+
fallback_result = scoped_translations(scope.collect{|s| "#{fallback_locale}.#{s}"}, exceptions) # NOTE: Duplicated code here
|
169
176
|
result[locale] = Utils.deep_merge(fallback_result[fallback_locale], result[locale])
|
170
177
|
end
|
171
178
|
end
|
172
179
|
|
173
|
-
|
174
180
|
### Export i18n.js
|
175
181
|
begin
|
182
|
+
|
176
183
|
# Copy i18n.js
|
177
184
|
def self.export_i18n_js
|
178
|
-
return
|
185
|
+
return unless export_i18n_js_dir_path.is_a? String
|
179
186
|
|
180
187
|
FileUtils.mkdir_p(export_i18n_js_dir_path)
|
181
188
|
|
182
189
|
i18n_js_path = File.expand_path('../../../app/assets/javascripts/i18n.js', __FILE__)
|
183
190
|
FileUtils.cp(i18n_js_path, export_i18n_js_dir_path)
|
184
191
|
end
|
185
|
-
def self.export_i18n_js_dir_path
|
186
|
-
return @export_i18n_js_dir_path if defined?(@export_i18n_js_dir_path)
|
187
192
|
|
188
|
-
|
193
|
+
def self.export_i18n_js_dir_path
|
194
|
+
@export_i18n_js_dir_path ||= (config[:export_i18n_js] || :none) if config.has_key?(:export_i18n_js)
|
195
|
+
@export_i18n_js_dir_path ||= DEFAULT_EXPORT_DIR_PATH
|
196
|
+
@export_i18n_js_dir_path
|
189
197
|
end
|
198
|
+
|
190
199
|
# Setting this to nil would disable i18n.js exporting
|
191
200
|
def self.export_i18n_js_dir_path=(new_path)
|
201
|
+
new_path = :none unless new_path.is_a? String
|
192
202
|
@export_i18n_js_dir_path = new_path
|
193
203
|
end
|
194
204
|
end
|
data/lib/i18n/js/dependencies.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
module I18n
|
2
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
|
3
5
|
module Dependencies
|
4
6
|
class << self
|
5
7
|
def rails3?
|
6
|
-
safe_gem_check("rails", "~> 3") && running_rails3?
|
8
|
+
safe_gem_check("rails", "~> 3.0") && running_rails3?
|
7
9
|
end
|
8
10
|
|
9
11
|
def rails4?
|
10
|
-
safe_gem_check("rails", "~> 4") && running_rails4?
|
12
|
+
safe_gem_check("rails", "~> 4.0", ">= 4.0.0.beta1") && running_rails4?
|
11
13
|
end
|
12
14
|
|
13
15
|
def sprockets_supports_register_preprocessor?
|
@@ -19,7 +21,7 @@ module I18n
|
|
19
21
|
end
|
20
22
|
|
21
23
|
def rails_available?
|
22
|
-
safe_gem_check("rails", '>= 3')
|
24
|
+
safe_gem_check("rails", '>= 3.0.0.beta')
|
23
25
|
end
|
24
26
|
|
25
27
|
def using_asset_pipeline?
|
@@ -49,11 +51,11 @@ module I18n
|
|
49
51
|
defined?(Rails) && Rails.respond_to?(:version)
|
50
52
|
end
|
51
53
|
|
52
|
-
def safe_gem_check(
|
54
|
+
def safe_gem_check(*args)
|
53
55
|
if Gem::Specification.respond_to?(:find_by_name)
|
54
|
-
Gem::Specification.find_by_name(
|
56
|
+
Gem::Specification.find_by_name(*args)
|
55
57
|
elsif Gem.respond_to?(:available?)
|
56
|
-
Gem.available?(
|
58
|
+
Gem.available?(*args)
|
57
59
|
end
|
58
60
|
rescue Gem::LoadError
|
59
61
|
false
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module I18n
|
2
|
+
module JS
|
3
|
+
|
4
|
+
# Class which enscapulates a translations hash and outputs a single JSON translation file
|
5
|
+
class Segment
|
6
|
+
attr_accessor :file, :translations, :namespace, :pretty_print
|
7
|
+
|
8
|
+
def initialize(file, translations, options = {})
|
9
|
+
@file = file
|
10
|
+
@translations = translations
|
11
|
+
@namespace = options[:namespace] || 'I18n'
|
12
|
+
@pretty_print = !!options[:pretty_print]
|
13
|
+
end
|
14
|
+
|
15
|
+
# Saves JSON file containing translations
|
16
|
+
def save!
|
17
|
+
FileUtils.mkdir_p File.dirname(self.file)
|
18
|
+
|
19
|
+
File.open(self.file, "w+") do |f|
|
20
|
+
f << %(#{self.namespace}.translations || (#{self.namespace}.translations = {});\n)
|
21
|
+
self.translations.each do |locale, translations|
|
22
|
+
f << %(#{self.namespace}.translations["#{locale}"] = #{print_json(translations)};\n);
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
# Outputs pretty or ugly JSON depending on :pretty_print option
|
30
|
+
def print_json(translations)
|
31
|
+
if pretty_print
|
32
|
+
JSON.pretty_generate(translations)
|
33
|
+
else
|
34
|
+
translations.to_json
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/i18n/js/utils.rb
CHANGED
@@ -5,11 +5,11 @@ module I18n
|
|
5
5
|
MERGER = proc do |key, v1, v2|
|
6
6
|
Hash === v1 && Hash === v2 ? v1.merge(v2, &MERGER) : v2
|
7
7
|
end
|
8
|
+
|
8
9
|
HASH_NIL_VALUE_CLEANER_PROC = proc do |k, v|
|
9
|
-
|
10
|
+
v.kind_of?(Hash) ? (v.delete_if(&HASH_NIL_VALUE_CLEANER_PROC); false) : v.nil?
|
10
11
|
end
|
11
12
|
|
12
|
-
|
13
13
|
def self.strip_keys_with_nil_values(hash)
|
14
14
|
hash.dup.delete_if(&HASH_NIL_VALUE_CLEANER_PROC)
|
15
15
|
end
|
@@ -21,6 +21,14 @@ module I18n
|
|
21
21
|
def self.deep_merge!(target_hash, hash) # :nodoc:
|
22
22
|
target_hash.merge!(hash, &MERGER)
|
23
23
|
end
|
24
|
+
|
25
|
+
def self.deep_reject(hash, &block)
|
26
|
+
hash.each_with_object({}) do |(k, v), memo|
|
27
|
+
unless block.call(k, v)
|
28
|
+
memo[k] = v.kind_of?(Hash) ? deep_reject(v, &block) : v
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
24
32
|
end
|
25
33
|
end
|
26
34
|
end
|
data/lib/i18n/js/version.rb
CHANGED
data/package.json
CHANGED
data/spec/i18n_js_spec.rb
CHANGED
@@ -29,13 +29,15 @@ describe I18n::JS do
|
|
29
29
|
|
30
30
|
it "exports messages using custom output path" do
|
31
31
|
set_config "custom_path.yml"
|
32
|
-
I18n::JS.should_receive(:
|
32
|
+
I18n::JS::Segment.should_receive(:new).with("tmp/i18n-js/all.js", translations, {}).and_call_original
|
33
|
+
I18n::JS::Segment.any_instance.should_receive(:save!).with(no_args)
|
33
34
|
I18n::JS.export
|
34
35
|
end
|
35
36
|
|
36
37
|
it "sets default scope to * when not specified" do
|
37
38
|
set_config "no_scope.yml"
|
38
|
-
I18n::JS.should_receive(:
|
39
|
+
I18n::JS::Segment.should_receive(:new).with("tmp/i18n-js/no_scope.js", translations, {}).and_call_original
|
40
|
+
I18n::JS::Segment.any_instance.should_receive(:save!).with(no_args)
|
39
41
|
I18n::JS.export
|
40
42
|
end
|
41
43
|
|
@@ -59,6 +61,7 @@ describe I18n::JS do
|
|
59
61
|
I18n::JS.export
|
60
62
|
|
61
63
|
file_should_exist "en.js"
|
64
|
+
file_should_exist "fr.js"
|
62
65
|
end
|
63
66
|
|
64
67
|
it "exports with multiple conditions" do
|
@@ -73,18 +76,23 @@ describe I18n::JS do
|
|
73
76
|
|
74
77
|
set_config "multiple_conditions_per_locale.yml"
|
75
78
|
|
76
|
-
expected_locales = %w(en fr)
|
77
|
-
|
78
79
|
result = I18n::JS.translation_segments
|
79
|
-
|
80
|
-
result.keys.should eql(expected_files)
|
80
|
+
result.map(&:file).should eql(["tmp/i18n-js/bits.en.js", "tmp/i18n-js/bits.fr.js"])
|
81
81
|
|
82
|
-
|
83
|
-
result
|
84
|
-
|
82
|
+
%w(en fr).each do |lang|
|
83
|
+
segment = result.select{|s| s.file == "tmp/i18n-js/bits.#{lang}.js"}.first
|
84
|
+
segment.translations.keys.should eql([lang.to_sym])
|
85
|
+
segment.translations[lang.to_sym].keys.sort.should eql([:date, :number])
|
85
86
|
end
|
86
87
|
end
|
87
88
|
|
89
|
+
it "exports with :except condition" do
|
90
|
+
set_config "except_condition.yml"
|
91
|
+
I18n::JS.export
|
92
|
+
|
93
|
+
file_should_exist "trimmed.js"
|
94
|
+
end
|
95
|
+
|
88
96
|
it "calls .export_i18n_js" do
|
89
97
|
allow(described_class).to receive(:export_i18n_js)
|
90
98
|
I18n::JS.export
|
@@ -132,33 +140,67 @@ describe I18n::JS do
|
|
132
140
|
end
|
133
141
|
end
|
134
142
|
|
143
|
+
context "exceptions" do
|
144
|
+
it "does not include a key listed in the exceptions list" do
|
145
|
+
result = I18n::JS.scoped_translations("*", ['admin'])
|
146
|
+
|
147
|
+
result[:en][:admin].should be_nil
|
148
|
+
result[:fr][:admin].should be_nil
|
149
|
+
end
|
150
|
+
|
151
|
+
it "does not include multiple keys listed in the exceptions list" do
|
152
|
+
result = I18n::JS.scoped_translations("*", ['title', 'note'])
|
153
|
+
|
154
|
+
result[:en][:admin][:show].should be_empty
|
155
|
+
result[:en][:admin][:edit].should be_empty
|
156
|
+
|
157
|
+
result[:fr][:admin][:show].should be_empty
|
158
|
+
result[:fr][:admin][:show].should be_empty
|
159
|
+
result[:fr][:admin][:edit].should be_empty
|
160
|
+
end
|
161
|
+
|
162
|
+
it "does not include a key listed in the exceptions list and respecs the 'only' option" do
|
163
|
+
result = I18n::JS.scoped_translations("fr.*", ['date', 'time', 'number', 'show'])
|
164
|
+
|
165
|
+
result[:en].should be_nil
|
166
|
+
result[:de].should be_nil
|
167
|
+
result[:ja].should be_nil
|
168
|
+
|
169
|
+
result[:fr][:date].should be_nil
|
170
|
+
result[:fr][:time].should be_nil
|
171
|
+
result[:fr][:number].should be_nil
|
172
|
+
result[:fr][:admin][:show].should be_nil
|
173
|
+
|
174
|
+
result[:fr][:admin][:edit][:title].should be_a(String)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
135
178
|
context "fallbacks" do
|
179
|
+
subject do
|
180
|
+
I18n::JS.translation_segments.inject({}) do |hash, segment|
|
181
|
+
hash[segment.file] = segment.translations
|
182
|
+
hash
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
136
186
|
it "exports without fallback when disabled" do
|
137
187
|
set_config "js_file_per_locale_without_fallbacks.yml"
|
138
|
-
|
139
|
-
result = I18n::JS.translation_segments
|
140
|
-
result["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql(nil)
|
188
|
+
subject["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql(nil)
|
141
189
|
end
|
142
190
|
|
143
191
|
it "exports with default_locale as fallback when enabled" do
|
144
192
|
set_config "js_file_per_locale_with_fallbacks_enabled.yml"
|
145
|
-
|
146
|
-
result = I18n::JS.translation_segments
|
147
|
-
result["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Success")
|
193
|
+
subject["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Success")
|
148
194
|
end
|
149
195
|
|
150
196
|
it "exports with default_locale as fallback when enabled with :default_locale" do
|
151
197
|
set_config "js_file_per_locale_with_fallbacks_as_default_locale_symbol.yml"
|
152
|
-
|
153
|
-
result = I18n::JS.translation_segments
|
154
|
-
result["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Success")
|
198
|
+
subject["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Success")
|
155
199
|
end
|
156
200
|
|
157
201
|
it "exports with given locale as fallback" do
|
158
202
|
set_config "js_file_per_locale_with_fallbacks_as_locale.yml"
|
159
|
-
|
160
|
-
result = I18n::JS.translation_segments
|
161
|
-
result["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Erfolg")
|
203
|
+
subject["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Erfolg")
|
162
204
|
end
|
163
205
|
|
164
206
|
context "with I18n::Fallbacks enabled" do
|
@@ -173,27 +215,53 @@ describe I18n::JS do
|
|
173
215
|
|
174
216
|
it "exports with defined locale as fallback when enabled" do
|
175
217
|
set_config "js_file_per_locale_with_fallbacks_enabled.yml"
|
176
|
-
|
177
|
-
result = I18n::JS.translation_segments
|
178
|
-
result["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Erfolg")
|
218
|
+
subject["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Erfolg")
|
179
219
|
end
|
180
220
|
|
181
221
|
it "exports with defined locale as fallback when enabled with :default_locale" do
|
182
222
|
set_config "js_file_per_locale_with_fallbacks_as_default_locale_symbol.yml"
|
183
|
-
|
184
|
-
result = I18n::JS.translation_segments
|
185
|
-
result["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Success")
|
223
|
+
subject["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Success")
|
186
224
|
end
|
187
225
|
|
188
226
|
it "exports with Fallbacks as Hash" do
|
189
227
|
set_config "js_file_per_locale_with_fallbacks_as_hash.yml"
|
190
|
-
|
191
|
-
result = I18n::JS.translation_segments
|
192
|
-
result["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Erfolg")
|
228
|
+
subject["tmp/i18n-js/fr.js"][:fr][:fallback_test].should eql("Erfolg")
|
193
229
|
end
|
194
230
|
end
|
195
231
|
end
|
196
232
|
|
233
|
+
context "namespace and pretty_print options" do
|
234
|
+
|
235
|
+
before do
|
236
|
+
stub_const('I18n::JS::DEFAULT_EXPORT_DIR_PATH', temp_path)
|
237
|
+
set_config "js_file_with_namespace_and_pretty_print.yml"
|
238
|
+
end
|
239
|
+
|
240
|
+
it "exports with defined locale as fallback when enabled" do
|
241
|
+
I18n::JS.export
|
242
|
+
file_should_exist "en.js"
|
243
|
+
output = File.read(File.join(I18n::JS.export_i18n_js_dir_path, "en.js"))
|
244
|
+
expect(output).to match(/^#{
|
245
|
+
<<EOS
|
246
|
+
Foo.translations || (Foo.translations = {});
|
247
|
+
Foo.translations["en"] = {
|
248
|
+
"number": {
|
249
|
+
"format": {
|
250
|
+
EOS
|
251
|
+
}.+#{
|
252
|
+
<<EOS
|
253
|
+
"edit": {
|
254
|
+
"title": "Edit"
|
255
|
+
}
|
256
|
+
},
|
257
|
+
"foo": "Foo",
|
258
|
+
"fallback_test": "Success"
|
259
|
+
};
|
260
|
+
EOS
|
261
|
+
}$/)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
197
265
|
context "I18n.available_locales" do
|
198
266
|
context "when I18n.available_locales is not set" do
|
199
267
|
it "should allow all locales" do
|
@@ -236,9 +304,10 @@ describe I18n::JS do
|
|
236
304
|
end
|
237
305
|
end
|
238
306
|
|
239
|
-
|
240
307
|
describe "i18n.js exporting" do
|
241
|
-
|
308
|
+
after { begin described_class.send(:remove_instance_variable, :@export_i18n_js_dir_path); rescue; end }
|
309
|
+
|
310
|
+
describe ".export_i18n_js with global variable" do
|
242
311
|
before do
|
243
312
|
allow(FileUtils).to receive(:mkdir_p).and_call_original
|
244
313
|
allow(FileUtils).to receive(:cp).and_call_original
|
@@ -273,11 +342,47 @@ describe I18n::JS do
|
|
273
342
|
end
|
274
343
|
end
|
275
344
|
|
345
|
+
describe ".export_i18n_js with config" do
|
346
|
+
|
347
|
+
let(:export_action) do
|
348
|
+
allow(FileUtils).to receive(:mkdir_p).and_call_original
|
349
|
+
allow(FileUtils).to receive(:cp).and_call_original
|
350
|
+
I18n::JS.export_i18n_js
|
351
|
+
end
|
352
|
+
|
353
|
+
context 'when :export_i18n_js set in config' do
|
354
|
+
before { set_config "js_export_dir_custom.yml"; export_action }
|
355
|
+
let(:export_i18n_js_dir_path) { temp_path }
|
356
|
+
let(:config_export_path) { "tmp/i18n-js/foo" }
|
357
|
+
|
358
|
+
it "does create the folder before copying" do
|
359
|
+
expect(FileUtils).to have_received(:mkdir_p).with(config_export_path).once
|
360
|
+
end
|
361
|
+
it "does copy the file with FileUtils.cp" do
|
362
|
+
expect(FileUtils).to have_received(:cp).once
|
363
|
+
end
|
364
|
+
it "exports the file" do
|
365
|
+
File.should be_file(File.join(config_export_path, "i18n.js"))
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
context 'when .export_i18n_js_dir_path is set to false' do
|
370
|
+
before { set_config "js_export_dir_none.yml"; export_action }
|
371
|
+
|
372
|
+
it "does NOT create the folder before copying" do
|
373
|
+
expect(FileUtils).to_not have_received(:mkdir_p)
|
374
|
+
end
|
375
|
+
|
376
|
+
it "does NOT copy the file with FileUtils.cp" do
|
377
|
+
expect(FileUtils).to_not have_received(:cp)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
276
381
|
|
277
382
|
describe '.export_i18n_js_dir_path' do
|
278
383
|
let(:default_path) { I18n::JS::DEFAULT_EXPORT_DIR_PATH }
|
279
384
|
let(:new_path) { File.join("tmp", default_path) }
|
280
|
-
|
385
|
+
after { described_class.send(:remove_instance_variable, :@export_i18n_js_dir_path) }
|
281
386
|
|
282
387
|
subject { described_class.export_i18n_js_dir_path }
|
283
388
|
|
@@ -292,92 +397,8 @@ describe I18n::JS do
|
|
292
397
|
context "when it is set to nil already" do
|
293
398
|
before { described_class.export_i18n_js_dir_path = nil }
|
294
399
|
|
295
|
-
it { should
|
296
|
-
end
|
297
|
-
end
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
describe I18n::JS::Dependencies, ".sprockets_supports_register_preprocessor?" do
|
302
|
-
|
303
|
-
subject { described_class.sprockets_supports_register_preprocessor? }
|
304
|
-
|
305
|
-
context 'when Sprockets is available to register preprocessors' do
|
306
|
-
let!(:sprockets_double) do
|
307
|
-
class_double('Sprockets').as_stubbed_const(register_processor: true).tap do |double|
|
308
|
-
allow(double).to receive(:respond_to?).with(:register_preprocessor).and_return(true)
|
400
|
+
it { should eq :none }
|
309
401
|
end
|
310
402
|
end
|
311
|
-
|
312
|
-
it { is_expected.to be_truthy }
|
313
|
-
it 'calls respond_to? with register_preprocessor on Sprockets' do
|
314
|
-
expect(sprockets_double).to receive(:respond_to?).with(:register_preprocessor).and_return(true)
|
315
|
-
subject
|
316
|
-
end
|
317
403
|
end
|
318
|
-
|
319
|
-
context 'when Sprockets is NOT available to register preprocessors' do
|
320
|
-
let!(:sprockets_double) do
|
321
|
-
class_double('Sprockets').as_stubbed_const(register_processor: true).tap do |double|
|
322
|
-
allow(double).to receive(:respond_to?).with(:register_preprocessor).and_return(false)
|
323
|
-
end
|
324
|
-
end
|
325
|
-
|
326
|
-
it { is_expected.to be_falsy }
|
327
|
-
it 'calls respond_to? with register_preprocessor on Sprockets' do
|
328
|
-
expect(sprockets_double).to receive(:respond_to?).with(:register_preprocessor).and_return(false)
|
329
|
-
subject
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
context 'when Sprockets is missing' do
|
334
|
-
before do
|
335
|
-
hide_const('Sprockets')
|
336
|
-
expect { Sprockets }.to raise_error(NameError)
|
337
|
-
end
|
338
|
-
|
339
|
-
it { is_expected.to be_falsy }
|
340
|
-
end
|
341
|
-
|
342
|
-
end
|
343
|
-
|
344
|
-
describe I18n::JS::Utils do
|
345
|
-
|
346
|
-
describe ".strip_keys_with_nil_values" do
|
347
|
-
subject { described_class.strip_keys_with_nil_values(input_hash) }
|
348
|
-
|
349
|
-
context 'when input_hash does NOT contain nil value' do
|
350
|
-
let(:input_hash) { {a: 1, b: { c: 2 }} }
|
351
|
-
let(:expected_hash) { input_hash }
|
352
|
-
|
353
|
-
it 'returns the original input' do
|
354
|
-
is_expected.to eq expected_hash
|
355
|
-
end
|
356
|
-
end
|
357
|
-
context 'when input_hash does contain nil value' do
|
358
|
-
let(:input_hash) { {a: 1, b: { c: 2, d: nil }, e: { f: nil }} }
|
359
|
-
let(:expected_hash) { {a: 1, b: { c: 2 }, e: {}} }
|
360
|
-
|
361
|
-
it 'returns the original input with nil values removed' do
|
362
|
-
is_expected.to eq expected_hash
|
363
|
-
end
|
364
|
-
end
|
365
|
-
end
|
366
|
-
|
367
|
-
context "hash merging" do
|
368
|
-
it "performs a deep merge" do
|
369
|
-
target = {:a => {:b => 1}}
|
370
|
-
result = described_class.deep_merge(target, {:a => {:c => 2}})
|
371
|
-
|
372
|
-
result[:a].should eql({:b => 1, :c => 2})
|
373
|
-
end
|
374
|
-
|
375
|
-
it "performs a banged deep merge" do
|
376
|
-
target = {:a => {:b => 1}}
|
377
|
-
described_class.deep_merge!(target, {:a => {:c => 2}})
|
378
|
-
|
379
|
-
target[:a].should eql({:b => 1, :c => 2})
|
380
|
-
end
|
381
|
-
end
|
382
|
-
|
383
404
|
end
|