i18n-js 0.1.6 → 1.0.0
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 +5 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +49 -0
- data/README.rdoc +24 -11
- data/Rakefile +9 -38
- data/i18n-js.gemspec +26 -0
- data/lib/i18n-js/version.rb +3 -3
- data/source/i18n.js +301 -266
- data/spec/i18n_spec.js +686 -0
- data/spec/i18n_spec.rb +169 -0
- data/{test → spec}/resources/custom_path.yml +0 -0
- data/{test → spec}/resources/default.yml +0 -0
- data/{test → spec}/resources/locales.yml +0 -0
- data/spec/resources/multiple_conditions.yml +6 -0
- data/{test → spec}/resources/multiple_files.yml +0 -0
- data/{test → spec}/resources/no_scope.yml +0 -0
- data/{test → spec}/resources/simple_scope.yml +0 -0
- data/{test/test_helper.rb → spec/spec_helper.rb} +6 -13
- metadata +103 -40
- data/init.rb +0 -1
- data/install.rb +0 -7
- data/test/i18n-test.html +0 -50
- data/test/i18n-test.js +0 -692
- data/test/i18n_js_test.rb +0 -154
- data/test/jsunittest/jsunittest.js +0 -1017
- data/test/jsunittest/unittest.css +0 -54
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
i18n-js (0.1.6)
|
5
|
+
i18n
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
activesupport (3.0.3)
|
11
|
+
archive-tar-minitar (0.5.2)
|
12
|
+
columnize (0.3.2)
|
13
|
+
diff-lcs (1.1.2)
|
14
|
+
fakeweb (1.3.0)
|
15
|
+
i18n (0.5.0)
|
16
|
+
linecache19 (0.5.11)
|
17
|
+
ruby_core_source (>= 0.1.4)
|
18
|
+
notifier (0.1.2)
|
19
|
+
rspec (2.5.0)
|
20
|
+
rspec-core (~> 2.5.0)
|
21
|
+
rspec-expectations (~> 2.5.0)
|
22
|
+
rspec-mocks (~> 2.5.0)
|
23
|
+
rspec-core (2.5.1)
|
24
|
+
rspec-expectations (2.5.0)
|
25
|
+
diff-lcs (~> 1.1.2)
|
26
|
+
rspec-mocks (2.5.0)
|
27
|
+
ruby-debug-base19 (0.11.24)
|
28
|
+
columnize (>= 0.3.1)
|
29
|
+
linecache19 (>= 0.5.11)
|
30
|
+
ruby_core_source (>= 0.1.4)
|
31
|
+
ruby-debug19 (0.11.6)
|
32
|
+
columnize (>= 0.3.1)
|
33
|
+
linecache19 (>= 0.5.11)
|
34
|
+
ruby-debug-base19 (>= 0.11.19)
|
35
|
+
ruby_core_source (0.1.4)
|
36
|
+
archive-tar-minitar (>= 0.5.2)
|
37
|
+
spec-js (0.1.0.beta.3)
|
38
|
+
notifier
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
ruby
|
42
|
+
|
43
|
+
DEPENDENCIES
|
44
|
+
activesupport (~> 3.0.0)
|
45
|
+
fakeweb
|
46
|
+
i18n-js!
|
47
|
+
rspec (~> 2.5.0)
|
48
|
+
ruby-debug19
|
49
|
+
spec-js (~> 0.1.0.beta.0)
|
data/README.rdoc
CHANGED
@@ -13,12 +13,6 @@ This library has been tested on:
|
|
13
13
|
|
14
14
|
=== Installation
|
15
15
|
|
16
|
-
You can use I18n-JS as plugin and gem. Choose what's best for you!
|
17
|
-
|
18
|
-
script/plugin install git://github.com/fnando/i18n-js.git
|
19
|
-
|
20
|
-
or
|
21
|
-
|
22
16
|
gem install i18n-js
|
23
17
|
|
24
18
|
=== Setting up
|
@@ -34,9 +28,9 @@ like this to your <tt>ApplicationController</tt>:
|
|
34
28
|
before_filter :export_i18n_messages
|
35
29
|
|
36
30
|
private
|
37
|
-
|
38
|
-
|
39
|
-
|
31
|
+
def export_i18n_messages
|
32
|
+
SimplesIdeias::I18n.export! if Rails.env.development?
|
33
|
+
end
|
40
34
|
end
|
41
35
|
|
42
36
|
==== Configuration
|
@@ -66,7 +60,14 @@ Set your locale is easy as
|
|
66
60
|
I18n.currentLocale();
|
67
61
|
// pt-BR
|
68
62
|
|
69
|
-
|
63
|
+
In practice, you'll have something like the following in your application.html.erb:
|
64
|
+
|
65
|
+
<script type="text/javascript">
|
66
|
+
I18n.defaultLocale = "<%= I18n.default_locale %>";
|
67
|
+
I18n.locale = "<%= I18n.locale %>";
|
68
|
+
</script>
|
69
|
+
|
70
|
+
You can use translate your messages:
|
70
71
|
|
71
72
|
I18n.t("some.scoped.translation");
|
72
73
|
|
@@ -201,7 +202,7 @@ The accepted formats are:
|
|
201
202
|
%Y - Year with century
|
202
203
|
%z - Timezone offset (+0545)
|
203
204
|
|
204
|
-
Check out <tt>vendor/plugins/i18n-js/
|
205
|
+
Check out <tt>vendor/plugins/i18n-js/spec/i18n_spec.js</tt> for more examples!
|
205
206
|
|
206
207
|
== Using I18nJS with other languages (Python, PHP, ...)
|
207
208
|
|
@@ -235,6 +236,18 @@ Once you've made your great commits:
|
|
235
236
|
|
236
237
|
Please respect the indentation rules. And use tabs, not spaces (on the JavaScript).
|
237
238
|
|
239
|
+
=== Running tests
|
240
|
+
|
241
|
+
To run Ruby tests, you need to install http://github.com/rspec/rspec
|
242
|
+
|
243
|
+
gem install rspec
|
244
|
+
|
245
|
+
To run JavaScript tests, you need to install http://github.com/fnando/spec-js
|
246
|
+
|
247
|
+
gem install specjs
|
248
|
+
|
249
|
+
Then just run `rake spec`.
|
250
|
+
|
238
251
|
== License
|
239
252
|
|
240
253
|
(The MIT License)
|
data/Rakefile
CHANGED
@@ -1,42 +1,13 @@
|
|
1
|
-
require
|
2
|
-
|
3
|
-
require 'rake/rdoctask'
|
4
|
-
require File.dirname(__FILE__) + '/lib/i18n-js/version'
|
1
|
+
require "bundler"
|
2
|
+
Bundler::GemHelper.install_tasks
|
5
3
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
desc 'Test the i18n-js plugin.'
|
10
|
-
Rake::TestTask.new(:test) do |t|
|
11
|
-
t.libs << 'lib'
|
12
|
-
t.libs << 'test'
|
13
|
-
t.pattern = 'test/**/*_test.rb'
|
14
|
-
t.verbose = true
|
15
|
-
end
|
16
|
-
|
17
|
-
desc 'Generate documentation for the i18n-js plugin.'
|
18
|
-
Rake::RDocTask.new(:rdoc) do |rdoc|
|
19
|
-
rdoc.rdoc_dir = 'doc'
|
20
|
-
rdoc.title = 'I18n for JavaScript'
|
21
|
-
rdoc.options << '--line-numbers' << '--inline-source'
|
22
|
-
rdoc.rdoc_files.include('README.rdoc')
|
23
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
4
|
+
require "spec_js/rake_task"
|
5
|
+
SpecJs::RakeTask.new do |t|
|
6
|
+
t.env_js = false
|
24
7
|
end
|
25
8
|
|
26
|
-
|
27
|
-
|
9
|
+
require "rspec/core/rake_task"
|
10
|
+
RSpec::Core::RakeTask.new(:"spec:ruby")
|
28
11
|
|
29
|
-
|
30
|
-
|
31
|
-
gem.email = "fnando.vieira@gmail.com"
|
32
|
-
gem.homepage = "http://github.com/fnando/i18n-js"
|
33
|
-
gem.authors = ["Nando Vieira"]
|
34
|
-
gem.version = SimplesIdeias::I18n::Version::STRING
|
35
|
-
gem.summary = "It's a small library to provide the Rails I18n translations on the Javascript."
|
36
|
-
gem.files = FileList["README.rdoc", "init.rb", "install.rb", "{lib,test,source}/**/*", "Rakefile"]
|
37
|
-
end
|
38
|
-
|
39
|
-
Jeweler::GemcutterTasks.new
|
40
|
-
rescue LoadError => e
|
41
|
-
puts "[JEWELER] You can't build a gem until you install jeweler with `gem install jeweler`"
|
42
|
-
end
|
12
|
+
desc "Run all specs"
|
13
|
+
task :spec => [:"spec:ruby", :"spec:js"]
|
data/i18n-js.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "i18n-js/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "i18n-js"
|
7
|
+
s.version = SimplesIdeias::I18n::Version::STRING
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Nando Vieira"]
|
10
|
+
s.email = ["fnando.vieira@gmail.com"]
|
11
|
+
s.homepage = "http://rubygems.org/gems/i18n-js"
|
12
|
+
s.summary = "It's a small library to provide the Rails I18n translations on the Javascript."
|
13
|
+
s.description = s.summary
|
14
|
+
|
15
|
+
s.files = `git ls-files`.split("\n")
|
16
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
17
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
|
20
|
+
s.add_dependency "i18n"
|
21
|
+
s.add_development_dependency "fakeweb"
|
22
|
+
s.add_development_dependency "activesupport", "~> 3.0.0"
|
23
|
+
s.add_development_dependency "rspec", "~> 2.5.0"
|
24
|
+
s.add_development_dependency "ruby-debug19"
|
25
|
+
s.add_development_dependency "spec-js", "~> 0.1.0.beta.0"
|
26
|
+
end
|
data/lib/i18n-js/version.rb
CHANGED
data/source/i18n.js
CHANGED
@@ -14,340 +14,375 @@ I18n.locale = null;
|
|
14
14
|
I18n.PLACEHOLDER = /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm;
|
15
15
|
|
16
16
|
I18n.lookup = function(scope, options) {
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
var translations = this.prepareOptions(I18n.translations);
|
18
|
+
var messages = translations[I18n.currentLocale()];
|
19
|
+
options = this.prepareOptions(options);
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
if (!messages) {
|
22
|
+
return;
|
23
|
+
}
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
if (typeof(scope) == "object") {
|
26
|
+
scope = scope.join(this.defaultSeparator);
|
27
|
+
}
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
if (options.scope) {
|
30
|
+
scope = options.scope.toString() + this.defaultSeparator + scope;
|
31
|
+
}
|
32
32
|
|
33
|
-
|
33
|
+
scope = scope.split(this.defaultSeparator);
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
while (scope.length > 0) {
|
36
|
+
var currentScope = scope.shift();
|
37
|
+
messages = messages[currentScope];
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
if (!messages) {
|
40
|
+
break;
|
41
|
+
}
|
42
|
+
}
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
if (!messages && options.defaultValue != null && options.defaultValue != undefined) {
|
45
|
+
messages = options.defaultValue;
|
46
|
+
}
|
47
47
|
|
48
|
-
|
48
|
+
return messages;
|
49
49
|
};
|
50
50
|
|
51
51
|
// Merge serveral hash options, checking if value is set before
|
52
52
|
// overwriting any value. The precedence is from left to right.
|
53
53
|
//
|
54
|
-
//
|
55
|
-
//
|
54
|
+
// I18n.prepareOptions({name: "John Doe"}, {name: "Mary Doe", role: "user"});
|
55
|
+
// #=> {name: "John Doe", role: "user"}
|
56
56
|
//
|
57
57
|
I18n.prepareOptions = function() {
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
var options = {};
|
59
|
+
var opts;
|
60
|
+
var count = arguments.length;
|
61
61
|
|
62
|
-
|
63
|
-
|
62
|
+
for (var i = 0; i < count; i++) {
|
63
|
+
opts = arguments[i];
|
64
64
|
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
if (!opts) {
|
66
|
+
continue;
|
67
|
+
}
|
68
68
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
69
|
+
for (var key in opts) {
|
70
|
+
if (options[key] == undefined || options[key] == null) {
|
71
|
+
options[key] = opts[key];
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
75
|
|
76
|
-
|
76
|
+
return options;
|
77
77
|
};
|
78
78
|
|
79
79
|
I18n.interpolate = function(message, options) {
|
80
|
-
|
81
|
-
|
80
|
+
options = this.prepareOptions(options);
|
81
|
+
var matches = message.match(this.PLACEHOLDER);
|
82
82
|
|
83
|
-
|
84
|
-
|
85
|
-
|
83
|
+
if (!matches) {
|
84
|
+
return message;
|
85
|
+
}
|
86
86
|
|
87
|
-
|
87
|
+
var placeholder, value, name;
|
88
88
|
|
89
|
-
|
90
|
-
|
89
|
+
for (var i = 0; placeholder = matches[i]; i++) {
|
90
|
+
name = placeholder.replace(this.PLACEHOLDER, "$1");
|
91
91
|
|
92
|
-
|
92
|
+
value = options[name];
|
93
93
|
|
94
|
-
|
95
|
-
|
96
|
-
|
94
|
+
if (options[name] == null || options[name] == undefined) {
|
95
|
+
value = "[missing " + placeholder + " value]";
|
96
|
+
}
|
97
97
|
|
98
|
-
|
99
|
-
|
100
|
-
|
98
|
+
regex = new RegExp(placeholder.replace(/\{/gm, "\\{").replace(/\}/gm, "\\}"));
|
99
|
+
message = message.replace(regex, value);
|
100
|
+
}
|
101
101
|
|
102
|
-
|
102
|
+
return message;
|
103
103
|
};
|
104
104
|
|
105
105
|
I18n.translate = function(scope, options) {
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
106
|
+
options = this.prepareOptions(options);
|
107
|
+
var translation = this.lookup(scope, options);
|
108
|
+
|
109
|
+
try {
|
110
|
+
if (typeof(translation) == "object") {
|
111
|
+
if (typeof(options.count) == "number") {
|
112
|
+
return this.pluralize(options.count, scope, options);
|
113
|
+
} else {
|
114
|
+
return translation;
|
115
|
+
}
|
116
|
+
} else {
|
117
|
+
return this.interpolate(translation, options);
|
118
|
+
}
|
119
|
+
} catch(err) {
|
120
|
+
return this.missingTranslation(scope);
|
121
|
+
}
|
122
122
|
};
|
123
123
|
|
124
124
|
I18n.localize = function(scope, value) {
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
125
|
+
switch (scope) {
|
126
|
+
case "currency":
|
127
|
+
return this.toCurrency(value);
|
128
|
+
case "number":
|
129
|
+
scope = this.lookup("number.format");
|
130
|
+
return this.toNumber(value, scope);
|
131
|
+
case "percentage":
|
132
|
+
return this.toPercentage(value);
|
133
|
+
default:
|
134
|
+
if (scope.match(/^(date|time)/)) {
|
135
|
+
return this.toTime(scope, value);
|
136
|
+
} else {
|
137
|
+
return value.toString();
|
138
|
+
}
|
139
|
+
}
|
140
140
|
};
|
141
141
|
|
142
142
|
I18n.parseDate = function(d) {
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
143
|
+
var matches, date;
|
144
|
+
matches = d.toString().match(/(\d{4})-(\d{2})-(\d{2})(?:[ |T](\d{2}):(\d{2}):(\d{2}))?(Z)?/);
|
145
|
+
|
146
|
+
if (matches) {
|
147
|
+
// date/time strings: yyyy-mm-dd hh:mm:ss or yyyy-mm-dd or yyyy-mm-ddThh:mm:ssZ
|
148
|
+
for (var i = 1; i <= 6; i++) {
|
149
|
+
matches[i] = parseInt(matches[i], 10) || 0;
|
150
|
+
}
|
151
|
+
|
152
|
+
// month starts on 0
|
153
|
+
matches[2] -= 1;
|
154
|
+
|
155
|
+
if (matches[7]) {
|
156
|
+
date = new Date(Date.UTC(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6]));
|
157
|
+
} else {
|
158
|
+
date = new Date(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6]);
|
159
|
+
}
|
160
|
+
} else if (typeof(d) == "number") {
|
161
|
+
// UNIX timestamp
|
162
|
+
date = new Date();
|
163
|
+
date.setTime(d);
|
164
|
+
} else {
|
165
|
+
// an arbitrary javascript string
|
166
|
+
date = new Date();
|
167
|
+
date.setTime(Date.parse(d));
|
168
|
+
}
|
169
|
+
|
170
|
+
return date;
|
171
171
|
};
|
172
172
|
|
173
173
|
I18n.toTime = function(scope, d) {
|
174
|
-
|
175
|
-
|
174
|
+
var date = this.parseDate(d);
|
175
|
+
var format = this.lookup(scope);
|
176
176
|
|
177
|
-
|
178
|
-
|
179
|
-
|
177
|
+
if (date.toString().match(/invalid/i)) {
|
178
|
+
return date.toString();
|
179
|
+
}
|
180
180
|
|
181
|
-
|
182
|
-
|
183
|
-
|
181
|
+
if (!format) {
|
182
|
+
return date.toString();
|
183
|
+
}
|
184
184
|
|
185
|
-
|
185
|
+
return this.strftime(date, format);
|
186
186
|
};
|
187
187
|
|
188
188
|
I18n.strftime = function(date, format) {
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
189
|
+
var options = this.lookup("date");
|
190
|
+
|
191
|
+
if (!options) {
|
192
|
+
return date.toString();
|
193
|
+
}
|
194
|
+
|
195
|
+
var weekDay = date.getDay();
|
196
|
+
var day = date.getDate();
|
197
|
+
var year = date.getFullYear();
|
198
|
+
var month = date.getMonth() + 1;
|
199
|
+
var hour = date.getHours();
|
200
|
+
var hour12 = hour;
|
201
|
+
var meridian = hour > 12? "PM" : "AM";
|
202
|
+
var secs = date.getSeconds();
|
203
|
+
var mins = date.getMinutes();
|
204
|
+
var offset = date.getTimezoneOffset();
|
205
|
+
var absOffsetHours = Math.floor(Math.abs(offset / 60));
|
206
|
+
var absOffsetMinutes = Math.abs(offset) - (absOffsetHours * 60);
|
207
|
+
var timezoneoffset = (offset > 0 ? "-" : "+") + (absOffsetHours.toString().length < 2 ? "0" + absOffsetHours : absOffsetHours) + (absOffsetMinutes.toString().length < 2 ? "0" + absOffsetMinutes : absOffsetMinutes);
|
208
|
+
|
209
|
+
if (hour12 > 12) {
|
210
|
+
hour12 = hour12 - 12;
|
211
|
+
}
|
212
|
+
|
213
|
+
var padding = function(n) {
|
214
|
+
var s = "0" + n.toString();
|
215
|
+
return s.substr(s.length - 2);
|
216
|
+
};
|
217
|
+
|
218
|
+
var f = format;
|
219
|
+
f = f.replace("%a", options["abbr_day_names"][weekDay]);
|
220
|
+
f = f.replace("%A", options["day_names"][weekDay]);
|
221
|
+
f = f.replace("%b", options["abbr_month_names"][month]);
|
222
|
+
f = f.replace("%B", options["month_names"][month]);
|
223
|
+
f = f.replace("%d", padding(day));
|
224
|
+
f = f.replace("%-d", day);
|
225
|
+
f = f.replace("%H", padding(hour));
|
226
|
+
f = f.replace("%-H", hour);
|
227
|
+
f = f.replace("%I", padding(hour12));
|
228
|
+
f = f.replace("%-I", hour12);
|
229
|
+
f = f.replace("%m", padding(month));
|
230
|
+
f = f.replace("%-m", month);
|
231
|
+
f = f.replace("%M", padding(mins));
|
232
|
+
f = f.replace("%-M", mins);
|
233
|
+
f = f.replace("%p", meridian);
|
234
|
+
f = f.replace("%S", padding(secs));
|
235
|
+
f = f.replace("%-S", secs);
|
236
|
+
f = f.replace("%w", weekDay);
|
237
|
+
f = f.replace("%y", padding(year));
|
238
|
+
f = f.replace("%-y", padding(year).replace(/^0+/, ""));
|
239
|
+
f = f.replace("%Y", year);
|
240
|
+
f = f.replace("%z", timezoneoffset);
|
241
|
+
|
242
|
+
return f;
|
243
243
|
};
|
244
244
|
|
245
245
|
I18n.toNumber = function(number, options) {
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
246
|
+
options = this.prepareOptions(
|
247
|
+
options,
|
248
|
+
this.lookup("number.format"),
|
249
|
+
{precision: 3, separator: ".", delimiter: ","}
|
250
|
+
);
|
251
|
+
|
252
|
+
var negative = number < 0;
|
253
|
+
var string = Math.abs(number).toFixed(options["precision"]).toString();
|
254
|
+
var parts = string.split(".");
|
255
|
+
|
256
|
+
number = parts[0];
|
257
|
+
var precision = parts[1];
|
258
|
+
|
259
|
+
var n = [];
|
260
|
+
|
261
|
+
while (number.length > 0) {
|
262
|
+
n.unshift(number.substr(Math.max(0, number.length - 3), 3));
|
263
|
+
number = number.substr(0, number.length -3);
|
264
|
+
}
|
265
|
+
|
266
|
+
var formattedNumber = n.join(options["delimiter"]);
|
267
|
+
|
268
|
+
if (options["precision"] > 0) {
|
269
|
+
formattedNumber += options["separator"] + parts[1];
|
270
|
+
}
|
271
|
+
|
272
|
+
if (negative) {
|
273
|
+
formattedNumber = "-" + formattedNumber;
|
274
|
+
}
|
275
|
+
|
276
|
+
return formattedNumber;
|
277
277
|
};
|
278
278
|
|
279
279
|
I18n.toCurrency = function(number, options) {
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
280
|
+
options = this.prepareOptions(
|
281
|
+
options,
|
282
|
+
this.lookup("number.currency.format"),
|
283
|
+
this.lookup("number.format"),
|
284
|
+
{unit: "$", precision: 2, format: "%u%n", delimiter: ",", separator: "."}
|
285
|
+
);
|
286
|
+
|
287
|
+
number = this.toNumber(number, options);
|
288
|
+
number = options["format"]
|
289
|
+
.replace("%u", options["unit"])
|
290
|
+
.replace("%n", number);
|
291
|
+
|
292
|
+
return number;
|
293
|
+
};
|
294
|
+
|
295
|
+
I18n.toHumanSize = function(number, options) {
|
296
|
+
var kb = 1024
|
297
|
+
, size = number
|
298
|
+
, iterations = 0
|
299
|
+
, unit
|
300
|
+
, precision;
|
301
|
+
|
302
|
+
while (size >= kb && iterations < 4) {
|
303
|
+
size = size / kb;
|
304
|
+
iterations += 1;
|
305
|
+
};
|
306
|
+
|
307
|
+
switch (iterations) {
|
308
|
+
case 0:
|
309
|
+
unit = this.t("number.human.storage_units.units.byte", {count: size});
|
310
|
+
precision = 0;
|
311
|
+
break;
|
312
|
+
default:
|
313
|
+
unit = this.t("number.human.storage_units.units." + [null, "kb", "mb", "gb", "tb"][iterations]);
|
314
|
+
precision = (size - Math.floor(size) == 0) ? 0 : 1;
|
315
|
+
};
|
316
|
+
|
317
|
+
options = this.prepareOptions(
|
318
|
+
options,
|
319
|
+
{precision: precision, format: "%n%u", delimiter: ""}
|
320
|
+
);
|
321
|
+
|
322
|
+
number = this.toNumber(size, options);
|
323
|
+
number = options["format"]
|
324
|
+
.replace("%u", unit)
|
325
|
+
.replace("%n", number);
|
326
|
+
|
327
|
+
return number;
|
293
328
|
};
|
294
329
|
|
295
330
|
I18n.toPercentage = function(number, options) {
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
331
|
+
options = this.prepareOptions(
|
332
|
+
options,
|
333
|
+
this.lookup("number.percentage.format"),
|
334
|
+
this.lookup("number.format"),
|
335
|
+
{precision: 3, separator: ".", delimiter: ""}
|
336
|
+
);
|
337
|
+
|
338
|
+
number = this.toNumber(number, options);
|
339
|
+
return number + "%";
|
305
340
|
};
|
306
341
|
|
307
342
|
I18n.pluralize = function(count, scope, options) {
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
343
|
+
var translation;
|
344
|
+
|
345
|
+
try {
|
346
|
+
translation = this.lookup(scope, options);
|
347
|
+
} catch (error) {}
|
348
|
+
|
349
|
+
if (!translation) {
|
350
|
+
return this.missingTranslation(scope);
|
351
|
+
}
|
352
|
+
|
353
|
+
var message;
|
354
|
+
options = this.prepareOptions(options);
|
355
|
+
options["count"] = count.toString();
|
356
|
+
|
357
|
+
switch(Math.abs(count)) {
|
358
|
+
case 0:
|
359
|
+
message = translation["zero"] || translation["none"] || translation["other"] || this.missingTranslation(scope, "zero");
|
360
|
+
break;
|
361
|
+
case 1:
|
362
|
+
message = translation["one"] || this.missingTranslation(scope, "one");
|
363
|
+
break;
|
364
|
+
default:
|
365
|
+
message = translation["other"] || this.missingTranslation(scope, "other");
|
366
|
+
}
|
367
|
+
|
368
|
+
return this.interpolate(message, options);
|
334
369
|
};
|
335
370
|
|
336
371
|
I18n.missingTranslation = function() {
|
337
|
-
|
338
|
-
|
372
|
+
var message = '[missing "' + this.currentLocale();
|
373
|
+
var count = arguments.length;
|
339
374
|
|
340
|
-
|
341
|
-
|
342
|
-
|
375
|
+
for (var i = 0; i < count; i++) {
|
376
|
+
message += "." + arguments[i];
|
377
|
+
}
|
343
378
|
|
344
|
-
|
379
|
+
message += '" translation]';
|
345
380
|
|
346
|
-
|
381
|
+
return message;
|
347
382
|
};
|
348
383
|
|
349
384
|
I18n.currentLocale = function() {
|
350
|
-
|
385
|
+
return (I18n.locale || I18n.defaultLocale);
|
351
386
|
};
|
352
387
|
|
353
388
|
// shortcuts
|