socialcast-i18n-js 4.0.0.rc1
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.
- data/.gitignore +13 -0
- data/.rspec +1 -0
- data/Gemfile +2 -0
- data/README.md +324 -0
- data/README.rdoc +320 -0
- data/Rakefile +13 -0
- data/app/assets/javascripts/i18n/translations.js.erb +6 -0
- data/app/assets/javascripts/i18n.js +661 -0
- data/config/i18n-js.yml +22 -0
- data/i18n-js.gemspec +28 -0
- data/lib/i18n/js/engine.rb +6 -0
- data/lib/i18n/js/file_dependency_processor.rb +17 -0
- data/lib/i18n/js/railtie.rb +17 -0
- data/lib/i18n/js/translator.rb +56 -0
- data/lib/i18n/js/version.rb +10 -0
- data/lib/i18n-js/engine.rb +63 -0
- data/lib/i18n-js/middleware.rb +59 -0
- data/lib/i18n-js/railtie.rb +13 -0
- data/lib/i18n-js/rake.rb +16 -0
- data/lib/i18n-js/version.rb +10 -0
- data/lib/i18n-js.rb +22 -0
- data/lib/tasks/i18n-js.rake +17 -0
- data/spec/file_dependency_processor_spec.rb +32 -0
- data/spec/fixtures/custom_path.yml +2 -0
- data/spec/fixtures/default.yml +2 -0
- data/spec/fixtures/js_file_per_locale.yml +1 -0
- data/spec/fixtures/locales.yml +76 -0
- data/spec/fixtures/multiple_conditions.yml +3 -0
- data/spec/fixtures/no_config.yml +2 -0
- data/spec/fixtures/simple_scope.yml +2 -0
- data/spec/i18n_js_spec.rb +11 -0
- data/spec/i18n_spec.js +820 -0
- data/spec/i18n_spec.rb +205 -0
- data/spec/js/currency.spec.js +60 -0
- data/spec/js/current_locale.spec.js +19 -0
- data/spec/js/dates.spec.js +218 -0
- data/spec/js/defaults.spec.js +23 -0
- data/spec/js/interpolation.spec.js +28 -0
- data/spec/js/jasmine/MIT.LICENSE +20 -0
- data/spec/js/jasmine/jasmine-html.js +190 -0
- data/spec/js/jasmine/jasmine.css +166 -0
- data/spec/js/jasmine/jasmine.js +2476 -0
- data/spec/js/jasmine/jasmine_favicon.png +0 -0
- data/spec/js/localization.spec.js +41 -0
- data/spec/js/numbers.spec.js +124 -0
- data/spec/js/placeholder.spec.js +24 -0
- data/spec/js/pluralization.spec.js +105 -0
- data/spec/js/prepare_options.spec.js +41 -0
- data/spec/js/specs.html +46 -0
- data/spec/js/translate.spec.js +119 -0
- data/spec/js/translations.js +115 -0
- data/spec/resources/custom_path.yml +4 -0
- data/spec/resources/default.yml +4 -0
- data/spec/resources/js_file_per_locale.yml +3 -0
- data/spec/resources/locales.yml +76 -0
- data/spec/resources/multiple_conditions.yml +6 -0
- data/spec/resources/multiple_files.yml +6 -0
- data/spec/resources/no_config.yml +2 -0
- data/spec/resources/no_scope.yml +3 -0
- data/spec/resources/simple_scope.yml +4 -0
- data/spec/spec_helper.rb +40 -0
- data/spec/translator_spec.rb +45 -0
- data/vendor/assets/javascripts/i18n/translations.js.erb +9 -0
- data/vendor/assets/javascripts/i18n.js +531 -0
- data/vendor/assets/javascripts/underscore.js +1059 -0
- metadata +240 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
require 'sprockets'
|
3
|
+
module I18n
|
4
|
+
module Js
|
5
|
+
class FileDependencyProcessor < Sprockets::Processor
|
6
|
+
def self.asset_path_regexp
|
7
|
+
@@asset_path_regexp ||= %r{#{I18n::Js.config[:asset_path]}}
|
8
|
+
end
|
9
|
+
def evaluate(context, locals)
|
10
|
+
return data unless context.logical_path =~ self.class.asset_path_regexp
|
11
|
+
::I18n.load_path.each {|path| context.depend_on(path)}
|
12
|
+
context.depend_on(I18n::Js.config_path)
|
13
|
+
data
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'i18n/js/engine'
|
2
|
+
|
3
|
+
module I18n
|
4
|
+
module Js
|
5
|
+
autoload :Translator, "i18n/js/translator"
|
6
|
+
autoload :FileDependencyProcessor, "i18n/js/file_dependency_processor"
|
7
|
+
|
8
|
+
class Railtie < ::Rails::Railtie
|
9
|
+
rake_tasks do
|
10
|
+
load "tasks/i18n-js.rake"
|
11
|
+
end
|
12
|
+
initializer "i18n-js.assetpipeline.environment", :after => "sprockets.environment" do |app|
|
13
|
+
app.assets.register_preprocessor("application/javascript", FileDependencyProcessor) if app.config.assets.enabled
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module I18n
|
2
|
+
module Js
|
3
|
+
class Translator
|
4
|
+
attr_accessor :scopes, :translations
|
5
|
+
def initialize(scopes)
|
6
|
+
@scopes = scopes
|
7
|
+
@translations = self.class.segment_for_scope(@scopes)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.segment_for_scope(scope)
|
11
|
+
if scope == "*"
|
12
|
+
translations
|
13
|
+
else
|
14
|
+
scoped_translations(scope)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.scoped_translations(scopes) # :nodoc:
|
19
|
+
result = {}
|
20
|
+
|
21
|
+
[scopes].flatten.each do |scope|
|
22
|
+
result.deep_merge!(filter(translations, scope))
|
23
|
+
end
|
24
|
+
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
# Filter translations according to the specified scope.
|
29
|
+
def self.filter(filter_translations, scopes)
|
30
|
+
scopes = scopes.split(".") if scopes.is_a?(String)
|
31
|
+
scopes = scopes.clone
|
32
|
+
scope = scopes.shift
|
33
|
+
|
34
|
+
if scope == "*"
|
35
|
+
results = {}
|
36
|
+
filter_translations.each do |filter_scope, filter_translation|
|
37
|
+
tmp = scopes.empty? ? filter_translation : filter(filter_translation, scopes)
|
38
|
+
results[filter_scope.to_sym] = tmp unless tmp.nil?
|
39
|
+
end
|
40
|
+
return results
|
41
|
+
elsif filter_translations.has_key?(scope.to_sym)
|
42
|
+
return {scope.to_sym => scopes.empty? ? filter_translations[scope.to_sym] : filter(filter_translations[scope.to_sym], scopes)}
|
43
|
+
end
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
# Initialize and return translations
|
48
|
+
def self.translations
|
49
|
+
::I18n.backend.instance_eval do
|
50
|
+
init_translations unless initialized?
|
51
|
+
translations
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module SimplesIdeias
|
2
|
+
module I18n
|
3
|
+
class Engine < ::Rails::Engine
|
4
|
+
I18N_TRANSLATIONS_ASSET = "i18n/translations"
|
5
|
+
|
6
|
+
initializer "i18n-js.asset_dependencies", :after => "sprockets.environment",
|
7
|
+
:before => "i18n-js.initialize" do
|
8
|
+
next unless SimplesIdeias::I18n.has_asset_pipeline?
|
9
|
+
|
10
|
+
config = I18n.config_file
|
11
|
+
cache_file = I18n::Engine.load_path_hash_cache
|
12
|
+
|
13
|
+
Rails.application.assets.register_preprocessor "application/javascript", :"i18n-js_dependencies" do |context, data|
|
14
|
+
if context.logical_path == I18N_TRANSLATIONS_ASSET
|
15
|
+
context.depend_on(config) if I18n.config?
|
16
|
+
# also set up dependencies on every locale file
|
17
|
+
::I18n.load_path.each {|path| context.depend_on(path)}
|
18
|
+
|
19
|
+
# Set up a dependency on the contents of the load path
|
20
|
+
# itself. In some situations it is possible to get here
|
21
|
+
# before the path hash cache file has been written; in
|
22
|
+
# this situation, write it now.
|
23
|
+
I18n::Engine.write_hash! unless File.exists?(cache_file)
|
24
|
+
context.depend_on(cache_file)
|
25
|
+
end
|
26
|
+
|
27
|
+
data
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# rewrite path cache hash at startup and before each request in development
|
32
|
+
config.to_prepare do
|
33
|
+
next unless SimplesIdeias::I18n.has_asset_pipeline?
|
34
|
+
SimplesIdeias::I18n::Engine.write_hash_if_changed unless Rails.env.production?
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.load_path_hash_cache
|
38
|
+
@load_path_hash_cache ||= Rails.root.join("tmp/i18n-js.cache")
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.write_hash_if_changed
|
42
|
+
load_path_hash = ::I18n.load_path.hash
|
43
|
+
|
44
|
+
if load_path_hash != cached_load_path_hash
|
45
|
+
self.cached_load_path_hash = load_path_hash
|
46
|
+
write_hash!
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.write_hash!
|
51
|
+
FileUtils.mkdir_p Rails.root.join("tmp")
|
52
|
+
|
53
|
+
File.open(load_path_hash_cache, "w+") do |f|
|
54
|
+
f.write(cached_load_path_hash)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class << self
|
59
|
+
attr_accessor :cached_load_path_hash
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module SimplesIdeias
|
2
|
+
module I18n
|
3
|
+
class Middleware
|
4
|
+
def initialize(app)
|
5
|
+
@app = app
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
@cache = nil
|
10
|
+
verify_locale_files!
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def cache_path
|
16
|
+
@cache_path ||= Rails.root.join("tmp/cache/i18n-js.yml")
|
17
|
+
end
|
18
|
+
|
19
|
+
def cache
|
20
|
+
@cache ||= begin
|
21
|
+
if cache_path.exist?
|
22
|
+
YAML.load_file(cache_path) || {}
|
23
|
+
else
|
24
|
+
{}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Check if translations should be regenerated.
|
30
|
+
# ONLY REGENERATE when these conditions are met:
|
31
|
+
#
|
32
|
+
# # Cache file doesn't exist
|
33
|
+
# # Translations and cache size are different (files were removed/added)
|
34
|
+
# # Translation file has been updated
|
35
|
+
#
|
36
|
+
def verify_locale_files!
|
37
|
+
valid_cache = []
|
38
|
+
new_cache = {}
|
39
|
+
|
40
|
+
valid_cache.push cache_path.exist?
|
41
|
+
valid_cache.push ::I18n.load_path.uniq.size == cache.size
|
42
|
+
|
43
|
+
::I18n.load_path.each do |path|
|
44
|
+
changed_at = File.mtime(path).to_i
|
45
|
+
valid_cache.push changed_at == cache[path]
|
46
|
+
new_cache[path] = changed_at
|
47
|
+
end
|
48
|
+
|
49
|
+
unless valid_cache.all?
|
50
|
+
File.open(cache_path, "w+") do |file|
|
51
|
+
file << new_cache.to_yaml
|
52
|
+
end
|
53
|
+
|
54
|
+
SimplesIdeias::I18n.export!
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module SimplesIdeias
|
2
|
+
module I18n
|
3
|
+
class Railtie < Rails::Railtie
|
4
|
+
rake_tasks do
|
5
|
+
require "i18n-js/rake"
|
6
|
+
end
|
7
|
+
|
8
|
+
initializer "i18n-js.initialize" do |app|
|
9
|
+
app.config.middleware.use(Middleware) if Rails.env.development? && !SimplesIdeias::I18n.has_asset_pipeline?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/i18n-js/rake.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
namespace "i18n:js" do
|
2
|
+
desc "Copy i18n.js and configuration file"
|
3
|
+
task :setup => :environment do
|
4
|
+
SimplesIdeias::I18n.setup!
|
5
|
+
end
|
6
|
+
|
7
|
+
desc "Export the messages files"
|
8
|
+
task :export => :environment do
|
9
|
+
SimplesIdeias::I18n.export!
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "Update the JavaScript library"
|
13
|
+
task :update => :environment do
|
14
|
+
SimplesIdeias::I18n.update!
|
15
|
+
end
|
16
|
+
end
|
data/lib/i18n-js.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'active_support/core_ext/hash'
|
2
|
+
|
3
|
+
require 'i18n'
|
4
|
+
require 'i18n/js/railtie' if defined?(Rails)
|
5
|
+
|
6
|
+
module I18n
|
7
|
+
module Js
|
8
|
+
def self.config_path
|
9
|
+
Rails.root.join("config", "i18n-js.yml")
|
10
|
+
end
|
11
|
+
def self.config?
|
12
|
+
File.exists?(config_path)
|
13
|
+
end
|
14
|
+
def self.config
|
15
|
+
@@config ||= if config?
|
16
|
+
YAML.load_file(config_path).with_indifferent_access
|
17
|
+
else
|
18
|
+
{}.with_indifferent_access
|
19
|
+
end.reverse_merge!(:asset_path => "i18n/translation", :only => "*")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
namespace :i18n do
|
2
|
+
namespace :js do
|
3
|
+
namespace :export do
|
4
|
+
task :assets => [:environment] do
|
5
|
+
require 'fileutils'
|
6
|
+
Dir.glob(Rails.application.assets.paths.map { |path| File.join(path, "#{I18n::Js.config[:asset_path]}*") }) do |asset_path|
|
7
|
+
asset = Rails.application.assets[asset_path]
|
8
|
+
export_path = Rails.root.join('public', asset.logical_path)
|
9
|
+
FileUtils.mkdir_p File.dirname(export_path)
|
10
|
+
File.open(export_path, 'w') do |file|
|
11
|
+
file.write(asset.to_a.map { |x| x.body }.join("\n"))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require 'i18n/js/file_dependency_processor'
|
3
|
+
|
4
|
+
describe I18n::Js::FileDependencyProcessor do
|
5
|
+
context "#evaluate" do
|
6
|
+
let(:dependency_processor) { I18n::Js::FileDependencyProcessor.new { @js } }
|
7
|
+
it "sets dependencies on the I18n load_paths and the I18n::Js config file" do
|
8
|
+
::I18n.stub(:load_path => ["/path/to/en.yml", "/path/to/es.yml"])
|
9
|
+
I18n::Js.stub(:config_path => "/path/to/i18n/js/config.yml")
|
10
|
+
context = double("context")
|
11
|
+
context.should_receive(:logical_path).and_return("i18n/translation-en.js")
|
12
|
+
context.should_receive(:depend_on).with("/path/to/en.yml")
|
13
|
+
context.should_receive(:depend_on).with("/path/to/es.yml")
|
14
|
+
context.should_receive(:depend_on).with("/path/to/i18n/js/config.yml")
|
15
|
+
locals = double("locals")
|
16
|
+
dependency_processor.evaluate(context, locals)
|
17
|
+
end
|
18
|
+
it "skips setting dependencies when the logical path doesn't match the asset_path_regexp" do
|
19
|
+
I18n::Js.stub(:config_path => "/path/to/i18n/js/config.yml")
|
20
|
+
context = double("context")
|
21
|
+
context.should_receive(:logical_path).and_return("not_i18n_translation.js")
|
22
|
+
context.should_not_receive(:depend_on)
|
23
|
+
locals = double("locals")
|
24
|
+
dependency_processor.evaluate(context, locals)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
context "#asset_path_regexp" do
|
28
|
+
it "returns a regex of asset_path" do
|
29
|
+
I18n::Js::FileDependencyProcessor.asset_path_regexp.should eql(%r{i18n/translation})
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
only: '*'
|
@@ -0,0 +1,76 @@
|
|
1
|
+
en:
|
2
|
+
number:
|
3
|
+
format:
|
4
|
+
separator: "."
|
5
|
+
delimiter: ","
|
6
|
+
precision: 3
|
7
|
+
currency:
|
8
|
+
format:
|
9
|
+
format: "%u%n"
|
10
|
+
unit: "$"
|
11
|
+
separator: "."
|
12
|
+
delimiter: ","
|
13
|
+
precision: 2
|
14
|
+
date:
|
15
|
+
formats:
|
16
|
+
default: "%Y-%m-%d"
|
17
|
+
short: "%b %d"
|
18
|
+
long: "%B %d, %Y"
|
19
|
+
day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday]
|
20
|
+
abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
|
21
|
+
month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December]
|
22
|
+
abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
|
23
|
+
# order: [ :year, :month, :day ]
|
24
|
+
time:
|
25
|
+
formats:
|
26
|
+
default: "%a, %d %b %Y %H:%M:%S %z"
|
27
|
+
short: "%d %b %H:%M"
|
28
|
+
long: "%B %d, %Y %H:%M"
|
29
|
+
am: "am"
|
30
|
+
pm: "pm"
|
31
|
+
admin:
|
32
|
+
show:
|
33
|
+
title: "Show"
|
34
|
+
note: "more details"
|
35
|
+
edit:
|
36
|
+
title: "Edit"
|
37
|
+
|
38
|
+
fr:
|
39
|
+
date:
|
40
|
+
formats:
|
41
|
+
default: "%d/%m/%Y"
|
42
|
+
short: "%e %b"
|
43
|
+
long: "%e %B %Y"
|
44
|
+
long_ordinal: "%e %B %Y"
|
45
|
+
only_day: "%e"
|
46
|
+
day_names: [dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi]
|
47
|
+
abbr_day_names: [dim, lun, mar, mer, jeu, ven, sam]
|
48
|
+
month_names: [~, janvier, février, mars, avril, mai, juin, juillet, août, septembre, octobre, novembre, décembre]
|
49
|
+
abbr_month_names: [~, jan., fév., mar., avr., mai, juin, juil., août, sept., oct., nov., déc.]
|
50
|
+
# order: [ :day, :month, :year ]
|
51
|
+
time:
|
52
|
+
formats:
|
53
|
+
default: "%d %B %Y %H:%M"
|
54
|
+
time: "%H:%M"
|
55
|
+
short: "%d %b %H:%M"
|
56
|
+
long: "%A %d %B %Y %H:%M:%S %Z"
|
57
|
+
long_ordinal: "%A %d %B %Y %H:%M:%S %Z"
|
58
|
+
only_second: "%S"
|
59
|
+
am: 'am'
|
60
|
+
pm: 'pm'
|
61
|
+
number:
|
62
|
+
format:
|
63
|
+
precision: 3
|
64
|
+
separator: ','
|
65
|
+
delimiter: ' '
|
66
|
+
currency:
|
67
|
+
format:
|
68
|
+
unit: '€'
|
69
|
+
precision: 2
|
70
|
+
format: '%n %u'
|
71
|
+
admin:
|
72
|
+
show:
|
73
|
+
title: "Visualiser"
|
74
|
+
note: "plus de détails"
|
75
|
+
edit:
|
76
|
+
title: "Editer"
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe I18n::Js do
|
4
|
+
context "general" do
|
5
|
+
it "sets empty hash as configuration when no file is found" do
|
6
|
+
I18n::Js.stub(:config_path => "/path/to/config/config.yml")
|
7
|
+
I18n::Js.config?.should be_false
|
8
|
+
I18n::Js.config.should eql({"asset_path" => "i18n/translation", "only" => "*"})
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|