i18n-js 3.0.0.rc5 → 3.0.0.rc6
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/.gitignore +3 -0
- data/.travis.yml +10 -0
- data/Appraisals +4 -0
- data/CHANGELOG.md +27 -0
- data/README.md +101 -20
- data/Rakefile +12 -1
- data/app/assets/javascripts/i18n.js +146 -33
- data/app/assets/javascripts/i18n/{translations.js.erb → filtered.js.erb} +1 -3
- data/app/assets/javascripts/i18n/shims.js +26 -0
- data/app/assets/javascripts/i18n/translations.js +3 -0
- data/gemfiles/i18n_0_6.gemfile +7 -0
- data/i18n-js.gemspec +5 -3
- data/lib/i18n/js.rb +13 -15
- data/lib/i18n/js/dependencies.rb +61 -0
- data/lib/i18n/js/engine.rb +6 -7
- data/lib/i18n/js/middleware.rb +13 -4
- data/lib/i18n/js/version.rb +1 -1
- data/lib/rails/generators/i18n/js/config/config_generator.rb +19 -0
- data/lib/rails/generators/i18n/js/config/templates/i18n-js.yml +28 -0
- data/lib/tasks/export.rake +8 -0
- data/spec/fixtures/erb.yml +4 -0
- data/spec/fixtures/locales.yml +6 -0
- data/spec/fixtures/multiple_conditions_per_locale.yml +5 -0
- data/spec/i18n_js_spec.rb +46 -1
- data/spec/js/dates.spec.js +40 -0
- data/spec/js/specs.html +1 -1
- data/spec/js/translate.spec.js +58 -0
- data/spec/js/translations.js +12 -1
- data/spec/spec_helper.rb +10 -2
- metadata +86 -16
- data/Gemfile.lock +0 -52
@@ -91,3 +91,29 @@ if ( !Array.prototype.forEach ) {
|
|
91
91
|
// 8. return undefined
|
92
92
|
};
|
93
93
|
}
|
94
|
+
|
95
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
|
96
|
+
if (!Array.prototype.some)
|
97
|
+
{
|
98
|
+
Array.prototype.some = function(fun /*, thisArg */)
|
99
|
+
{
|
100
|
+
'use strict';
|
101
|
+
|
102
|
+
if (this === void 0 || this === null)
|
103
|
+
throw new TypeError();
|
104
|
+
|
105
|
+
var t = Object(this);
|
106
|
+
var len = t.length >>> 0;
|
107
|
+
if (typeof fun !== 'function')
|
108
|
+
throw new TypeError();
|
109
|
+
|
110
|
+
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
|
111
|
+
for (var i = 0; i < len; i++)
|
112
|
+
{
|
113
|
+
if (i in t && fun.call(thisArg, t[i], i, t))
|
114
|
+
return true;
|
115
|
+
}
|
116
|
+
|
117
|
+
return false;
|
118
|
+
};
|
119
|
+
}
|
data/i18n-js.gemspec
CHANGED
@@ -17,9 +17,11 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
18
|
s.require_paths = ["lib"]
|
19
19
|
|
20
|
-
s.add_dependency "i18n"
|
21
|
-
s.add_development_dependency "
|
22
|
-
s.add_development_dependency "
|
20
|
+
s.add_dependency "i18n", "~> 0.6"
|
21
|
+
s.add_development_dependency "appraisal", "~> 1.0"
|
22
|
+
s.add_development_dependency "activesupport", ">= 3"
|
23
|
+
s.add_development_dependency "rspec", "~> 3.0"
|
23
24
|
s.add_development_dependency "rake"
|
24
25
|
s.add_development_dependency "pry-meta"
|
26
|
+
s.add_development_dependency "gem-release", ">= 0.7"
|
25
27
|
end
|
data/lib/i18n/js.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require "i18n"
|
2
|
-
require "
|
2
|
+
require "fileutils"
|
3
3
|
|
4
4
|
module I18n
|
5
5
|
module JS
|
6
|
-
|
6
|
+
require "i18n/js/dependencies"
|
7
|
+
if JS::Dependencies.rails?
|
7
8
|
require "i18n/js/middleware"
|
8
9
|
require "i18n/js/engine"
|
9
10
|
end
|
@@ -13,12 +14,6 @@ module I18n
|
|
13
14
|
Hash === v1 && Hash === v2 ? v1.merge(v2, &MERGER) : v2
|
14
15
|
end
|
15
16
|
|
16
|
-
# Detect if Rails app has asset pipeline support.
|
17
|
-
#
|
18
|
-
def self.has_asset_pipeline?
|
19
|
-
Rails.configuration.respond_to?(:assets) && Rails.configuration.assets.enabled
|
20
|
-
end
|
21
|
-
|
22
17
|
# The configuration file. This defaults to the `config/i18n-js.yml` file.
|
23
18
|
#
|
24
19
|
def self.config_file
|
@@ -35,7 +30,8 @@ module I18n
|
|
35
30
|
|
36
31
|
def self.segments_per_locale(pattern, scope)
|
37
32
|
I18n.available_locales.each_with_object({}) do |locale, segments|
|
38
|
-
|
33
|
+
scope = [scope] unless scope.respond_to?(:each)
|
34
|
+
result = scoped_translations(scope.collect{|s| "#{locale}.#{s}"})
|
39
35
|
next if result.empty?
|
40
36
|
|
41
37
|
segment_name = ::I18n.interpolate(pattern,{:locale => locale})
|
@@ -87,7 +83,8 @@ module I18n
|
|
87
83
|
# custom output directory
|
88
84
|
def self.config
|
89
85
|
if config?
|
90
|
-
(
|
86
|
+
erb = ERB.new(File.read(config_file)).result
|
87
|
+
(YAML.load(erb) || {}).with_indifferent_access
|
91
88
|
else
|
92
89
|
{}
|
93
90
|
end
|
@@ -103,9 +100,10 @@ module I18n
|
|
103
100
|
FileUtils.mkdir_p File.dirname(file)
|
104
101
|
|
105
102
|
File.open(file, "w+") do |f|
|
106
|
-
f << %(I18n.translations = )
|
107
|
-
|
108
|
-
|
103
|
+
f << %(I18n.translations || (I18n.translations = {});\n)
|
104
|
+
translations.each do |locale, translations_for_locale|
|
105
|
+
f << %(I18n.translations["#{locale}"] = #{translations_for_locale.to_json};\n);
|
106
|
+
end
|
109
107
|
end
|
110
108
|
end
|
111
109
|
|
@@ -132,7 +130,7 @@ module I18n
|
|
132
130
|
results[scope.to_sym] = tmp unless tmp.nil?
|
133
131
|
end
|
134
132
|
return results
|
135
|
-
elsif translations.has_key?(scope.to_sym)
|
133
|
+
elsif translations.respond_to?(:has_key?) && translations.has_key?(scope.to_sym)
|
136
134
|
return {scope.to_sym => scopes.empty? ? translations[scope.to_sym] : filter(translations[scope.to_sym], scopes)}
|
137
135
|
end
|
138
136
|
nil
|
@@ -142,7 +140,7 @@ module I18n
|
|
142
140
|
def self.translations
|
143
141
|
::I18n.backend.instance_eval do
|
144
142
|
init_translations unless initialized?
|
145
|
-
translations
|
143
|
+
translations.slice(*::I18n.available_locales)
|
146
144
|
end
|
147
145
|
end
|
148
146
|
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module I18n
|
2
|
+
module JS
|
3
|
+
module Dependencies
|
4
|
+
class << self
|
5
|
+
def rails3?
|
6
|
+
safe_gem_check("rails", "~> 3") && running_rails3?
|
7
|
+
end
|
8
|
+
|
9
|
+
def rails4?
|
10
|
+
safe_gem_check("rails", "~> 4") && running_rails4?
|
11
|
+
end
|
12
|
+
|
13
|
+
def rails?
|
14
|
+
rails_available? && running_rails?
|
15
|
+
end
|
16
|
+
|
17
|
+
def rails_available?
|
18
|
+
safe_gem_check("rails", '>= 3')
|
19
|
+
end
|
20
|
+
|
21
|
+
def using_asset_pipeline?
|
22
|
+
assets_pipeline_available =
|
23
|
+
(rails3? || rails4?) &&
|
24
|
+
Rails.respond_to?(:application) &&
|
25
|
+
Rails.application.respond_to?(:assets)
|
26
|
+
rails3_assets_enabled =
|
27
|
+
rails3? &&
|
28
|
+
assets_pipeline_available &&
|
29
|
+
Rails.application.config.assets.enabled != false
|
30
|
+
|
31
|
+
assets_pipeline_available && (rails4? || rails3_assets_enabled)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def running_rails3?
|
37
|
+
running_rails? && Rails.version.to_i == 3
|
38
|
+
end
|
39
|
+
|
40
|
+
def running_rails4?
|
41
|
+
running_rails? && Rails.version.to_i == 4
|
42
|
+
end
|
43
|
+
|
44
|
+
def running_rails?
|
45
|
+
defined?(Rails) && Rails.respond_to?(:version)
|
46
|
+
end
|
47
|
+
|
48
|
+
def safe_gem_check(gem_name, version_string)
|
49
|
+
if Gem::Specification.respond_to?(:find_by_name)
|
50
|
+
Gem::Specification.find_by_name(gem_name, version_string)
|
51
|
+
elsif Gem.respond_to?(:available?)
|
52
|
+
Gem.available?(gem_name, version_string)
|
53
|
+
end
|
54
|
+
rescue Gem::LoadError
|
55
|
+
false
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/i18n/js/engine.rb
CHANGED
@@ -4,15 +4,14 @@ module I18n
|
|
4
4
|
module JS
|
5
5
|
class Engine < ::Rails::Engine
|
6
6
|
initializer :after => "sprockets.environment" do
|
7
|
-
|
8
|
-
|
9
|
-
next unless Rails.configuration.assets.compile
|
7
|
+
next unless JS::Dependencies.using_asset_pipeline?
|
8
|
+
next unless Rails.configuration.assets.compile
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
::I18n.load_path.each {|path| context.depend_on(path)}
|
14
|
-
source
|
10
|
+
Rails.application.assets.register_preprocessor "application/javascript", :"i18n-js_dependencies" do |context, source|
|
11
|
+
if context.logical_path == "i18n/filtered"
|
12
|
+
::I18n.load_path.each {|path| context.depend_on(File.expand_path(path))}
|
15
13
|
end
|
14
|
+
source
|
16
15
|
end
|
17
16
|
end
|
18
17
|
end
|
data/lib/i18n/js/middleware.rb
CHANGED
@@ -13,7 +13,11 @@ module I18n
|
|
13
13
|
|
14
14
|
private
|
15
15
|
def cache_path
|
16
|
-
@cache_path ||=
|
16
|
+
@cache_path ||= cache_dir.join("i18n-js.yml")
|
17
|
+
end
|
18
|
+
|
19
|
+
def cache_dir
|
20
|
+
@cache_dir ||= Rails.root.join("tmp/cache")
|
17
21
|
end
|
18
22
|
|
19
23
|
def cache
|
@@ -26,6 +30,13 @@ module I18n
|
|
26
30
|
end
|
27
31
|
end
|
28
32
|
|
33
|
+
def save_cache(new_cache)
|
34
|
+
FileUtils.mkdir_p(cache_dir)
|
35
|
+
File.open(cache_path, "w+") do |file|
|
36
|
+
file << new_cache.to_yaml
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
29
40
|
# Check if translations should be regenerated.
|
30
41
|
# ONLY REGENERATE when these conditions are met:
|
31
42
|
#
|
@@ -48,9 +59,7 @@ module I18n
|
|
48
59
|
|
49
60
|
return if valid_cache.all?
|
50
61
|
|
51
|
-
|
52
|
-
file << new_cache.to_yaml
|
53
|
-
end
|
62
|
+
save_cache(new_cache)
|
54
63
|
|
55
64
|
::I18n::JS.export
|
56
65
|
end
|
data/lib/i18n/js/version.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
module I18n
|
2
|
+
module Js
|
3
|
+
class ConfigGenerator < Rails::Generators::Base
|
4
|
+
# Copied files come from templates folder
|
5
|
+
source_root File.expand_path('../templates', __FILE__)
|
6
|
+
|
7
|
+
# Generator desc
|
8
|
+
desc <<-DESC
|
9
|
+
Creates a default i18n-js.yml configuration file in your app's config
|
10
|
+
folder. This file allows you to customize i18n:js:export rake task
|
11
|
+
outputted files.
|
12
|
+
DESC
|
13
|
+
|
14
|
+
def copy_initializer_file
|
15
|
+
copy_file "i18n-js.yml", "config/i18n-js.yml"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Split context in several files.
|
2
|
+
#
|
3
|
+
# By default only one file with all translations is exported and
|
4
|
+
# no configuration is required. Your settings for asset pipeline
|
5
|
+
# are automatically recognized.
|
6
|
+
#
|
7
|
+
# If you want to split translations into several files or specify
|
8
|
+
# locale contexts that will be exported, just use this file to do
|
9
|
+
# so.
|
10
|
+
#
|
11
|
+
# For more informations about the export options with this file, please
|
12
|
+
# refer to the `Export Configuration` section in the README at :
|
13
|
+
# https://github.com/fnando/i18n-js#export-configuration
|
14
|
+
#
|
15
|
+
#
|
16
|
+
# If you're going to use the Rails 3.1 asset pipeline, change
|
17
|
+
# the following configuration to something like this:
|
18
|
+
#
|
19
|
+
# translations:
|
20
|
+
# - file: "app/assets/javascripts/i18n/translations.js"
|
21
|
+
#
|
22
|
+
# If you're running an old version, you can use something
|
23
|
+
# like this:
|
24
|
+
#
|
25
|
+
# translations:
|
26
|
+
# - file: "app/assets/javascripts/i18n/translations.js"
|
27
|
+
# only: "*"
|
28
|
+
#
|
data/spec/fixtures/locales.yml
CHANGED
data/spec/i18n_js_spec.rb
CHANGED
@@ -51,6 +51,20 @@ describe I18n::JS do
|
|
51
51
|
|
52
52
|
file_should_exist "bitsnpieces.js"
|
53
53
|
end
|
54
|
+
|
55
|
+
it "exports with multiple conditions to a JS file per available locale" do
|
56
|
+
allow(::I18n).to receive(:available_locales){ [:en, :fr] }
|
57
|
+
|
58
|
+
set_config "multiple_conditions_per_locale.yml"
|
59
|
+
|
60
|
+
result = I18n::JS.translation_segments
|
61
|
+
result.keys.should eql(["tmp/i18n-js/bits.en.js", "tmp/i18n-js/bits.fr.js"])
|
62
|
+
|
63
|
+
%w{en fr}.each do |lang|
|
64
|
+
result["tmp/i18n-js/bits.#{lang}.js"].keys.should eql([lang.to_sym])
|
65
|
+
result["tmp/i18n-js/bits.#{lang}.js"][lang.to_sym].keys.sort.should eql([:date, :number])
|
66
|
+
end
|
67
|
+
end
|
54
68
|
end
|
55
69
|
|
56
70
|
context "filters" do
|
@@ -93,15 +107,46 @@ describe I18n::JS do
|
|
93
107
|
end
|
94
108
|
end
|
95
109
|
|
110
|
+
context "I18n.available_locales" do
|
111
|
+
context "when I18n.available_locales is not set" do
|
112
|
+
it "should allow all locales" do
|
113
|
+
result = I18n::JS.scoped_translations("*.admin.*.title")
|
114
|
+
|
115
|
+
result[:en][:admin][:show][:title].should eql("Show")
|
116
|
+
result[:fr][:admin][:show][:title].should eql("Visualiser")
|
117
|
+
result[:ja][:admin][:show][:title].should eql("Ignore me")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context "when I18n.available_locales is set" do
|
122
|
+
before { allow(::I18n).to receive(:available_locales){ [:en, :fr] } }
|
123
|
+
|
124
|
+
it "should ignore non-valid locales" do
|
125
|
+
result = I18n::JS.scoped_translations("*.admin.*.title")
|
126
|
+
|
127
|
+
result[:en][:admin][:show][:title].should eql("Show")
|
128
|
+
result[:fr][:admin][:show][:title].should eql("Visualiser")
|
129
|
+
result.keys.include?(:ja).should eql(false)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
96
134
|
context "general" do
|
97
135
|
it "sets export directory" do
|
98
136
|
I18n::JS.export_dir.should eql("public/javascripts")
|
99
137
|
end
|
100
138
|
|
101
139
|
it "sets empty hash as configuration when no file is found" do
|
102
|
-
I18n::JS.config?.should
|
140
|
+
I18n::JS.config?.should eql(false)
|
103
141
|
I18n::JS.config.should eql({})
|
104
142
|
end
|
143
|
+
|
144
|
+
it "executes erb in config file" do
|
145
|
+
set_config "erb.yml"
|
146
|
+
|
147
|
+
config_entry = I18n::JS.config["translations"].first
|
148
|
+
config_entry["only"].should eq("*.date.formats")
|
149
|
+
end
|
105
150
|
end
|
106
151
|
|
107
152
|
context "hash merging" do
|
data/spec/js/dates.spec.js
CHANGED
@@ -47,6 +47,10 @@ describe("Dates", function(){
|
|
47
47
|
actual = I18n.parseDate("2011-07-20T12:51:55+0000");
|
48
48
|
expect(actual.toString()).toEqual(expected.toString());
|
49
49
|
|
50
|
+
expected = new Date(Date.UTC(2011, 6, 20, 12, 51, 55));
|
51
|
+
actual = I18n.parseDate("2011-07-20T12:51:55+00:00");
|
52
|
+
expect(actual.toString()).toEqual(expected.toString());
|
53
|
+
|
50
54
|
expected = new Date(Date.UTC(2011, 6, 20, 13, 03, 39));
|
51
55
|
actual = I18n.parseDate("Wed Jul 20 13:03:39 +0000 2011");
|
52
56
|
expect(actual.toString()).toEqual(expected.toString());
|
@@ -54,6 +58,21 @@ describe("Dates", function(){
|
|
54
58
|
expected = new Date(Date.UTC(2009, 0, 24, 15, 33, 44));
|
55
59
|
actual = I18n.parseDate("2009-01-24T15:33:44Z");
|
56
60
|
expect(actual.toString()).toEqual(expected.toString());
|
61
|
+
|
62
|
+
expected = new Date(Date.UTC(2009, 0, 24, 15, 34, 44, 200));
|
63
|
+
actual = I18n.parseDate("2009-01-24T15:34:44.200Z");
|
64
|
+
expect(actual.toString()).toEqual(expected.toString());
|
65
|
+
expect(actual.getMilliseconds()).toEqual(expected.getMilliseconds())
|
66
|
+
|
67
|
+
expected = new Date(Date.UTC(2009, 0, 24, 15, 34, 45, 200));
|
68
|
+
actual = I18n.parseDate("2009-01-24T15:34:45.200+0000");
|
69
|
+
expect(actual.toString()).toEqual(expected.toString());
|
70
|
+
expect(actual.getMilliseconds()).toEqual(expected.getMilliseconds())
|
71
|
+
|
72
|
+
expected = new Date(Date.UTC(2009, 0, 24, 15, 34, 46, 200));
|
73
|
+
actual = I18n.parseDate("2009-01-24T15:34:46.200+00:00");
|
74
|
+
expect(actual.toString()).toEqual(expected.toString());
|
75
|
+
expect(actual.getMilliseconds()).toEqual(expected.getMilliseconds())
|
57
76
|
});
|
58
77
|
|
59
78
|
it("formats date", function(){
|
@@ -215,4 +234,25 @@ describe("Dates", function(){
|
|
215
234
|
var date = new Date(2009, 3, 26, 19, 35, 44);
|
216
235
|
expect(I18n.strftime(date, "%a")).toEqual("Sun");
|
217
236
|
});
|
237
|
+
|
238
|
+
it("applies locale fallback", function(){
|
239
|
+
I18n.defaultLocale = "en-US";
|
240
|
+
I18n.locale = "de";
|
241
|
+
|
242
|
+
var date = new Date(2009, 3, 26, 19, 35, 44);
|
243
|
+
expect(I18n.strftime(date, "%A")).toEqual("Sonntag");
|
244
|
+
|
245
|
+
date = new Date(2009, 3, 26, 19, 35, 44);
|
246
|
+
expect(I18n.strftime(date, "%a")).toEqual("Sun");
|
247
|
+
});
|
248
|
+
|
249
|
+
it("uses time as the meridian scope", function(){
|
250
|
+
I18n.locale = "de";
|
251
|
+
|
252
|
+
var date = new Date(2009, 3, 26, 19, 35, 44);
|
253
|
+
expect(I18n.strftime(date, "%p")).toEqual("de:PM");
|
254
|
+
|
255
|
+
date = new Date(2009, 3, 26, 7, 35, 44);
|
256
|
+
expect(I18n.strftime(date, "%p")).toEqual("de:AM");
|
257
|
+
});
|
218
258
|
});
|