i18n-js 3.0.0.rc8 → 3.0.0.rc9
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/.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
|