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.
@@ -1,4 +1,2 @@
1
- //= require i18n/shims
2
- //= require i18n
3
- //= require_self
1
+ <%# encoding: utf-8 %>
4
2
  ;I18n.translations = <%= I18n::JS.filtered_translations.to_json %>;
@@ -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
+ }
@@ -0,0 +1,3 @@
1
+ //= require i18n/shims
2
+ //= require i18n
3
+ //= require i18n/filtered
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "i18n", "0.6.9"
6
+
7
+ gemspec :path => "../"
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 "activesupport"
22
- s.add_development_dependency "rspec"
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 "FileUtils" unless defined?(FileUtils)
2
+ require "fileutils"
3
3
 
4
4
  module I18n
5
5
  module JS
6
- if defined?(Rails)
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
- result = scoped_translations("#{locale}.#{scope}")
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
- (YAML.load_file(config_file) || {}).with_indifferent_access
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
- f << translations.to_json
108
- f << %(;)
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
@@ -4,15 +4,14 @@ module I18n
4
4
  module JS
5
5
  class Engine < ::Rails::Engine
6
6
  initializer :after => "sprockets.environment" do
7
- ActiveSupport.on_load(:after_initialize, :yield => true) do
8
- next unless JS.has_asset_pipeline?
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
- Rails.application.assets.register_preprocessor "application/javascript", :"i18n-js_dependencies" do |context, source|
12
- next source unless context.logical_path == "i18n/translations"
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
@@ -13,7 +13,11 @@ module I18n
13
13
 
14
14
  private
15
15
  def cache_path
16
- @cache_path ||= Rails.root.join("tmp/cache/i18n-js.yml")
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
- File.open(cache_path, "w+") do |file|
52
- file << new_cache.to_yaml
53
- end
62
+ save_cache(new_cache)
54
63
 
55
64
  ::I18n::JS.export
56
65
  end
@@ -4,7 +4,7 @@ module I18n
4
4
  MAJOR = 3
5
5
  MINOR = 0
6
6
  PATCH = 0
7
- STRING = "#{MAJOR}.#{MINOR}.#{PATCH}.rc5"
7
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}.rc6"
8
8
  end
9
9
  end
10
10
  end
@@ -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
+ #
@@ -0,0 +1,8 @@
1
+ namespace :i18n do
2
+ namespace :js do
3
+ desc "Export translations to JS file(s)"
4
+ task :export => :environment do
5
+ I18n::JS.export
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ # Find more details about this configuration file at http://github.com/fnando/i18n-js
2
+ translations:
3
+ - file: "tmp/i18n-js/translations.js"
4
+ only: '<%= "*." + "date." + "formats" %>'
@@ -34,6 +34,7 @@ en:
34
34
  note: "more details"
35
35
  edit:
36
36
  title: "Edit"
37
+ foo: "Foo"
37
38
 
38
39
  fr:
39
40
  date:
@@ -74,3 +75,8 @@ fr:
74
75
  note: "plus de détails"
75
76
  edit:
76
77
  title: "Editer"
78
+
79
+ ja:
80
+ admin:
81
+ show:
82
+ title: "Ignore me"
@@ -0,0 +1,5 @@
1
+ translations:
2
+ - file: "tmp/i18n-js/bits.%{locale}.js"
3
+ only:
4
+ - "date.formats"
5
+ - "number.currency"
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 be_false
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
@@ -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
  });