i18n-js 0.1.6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ doc
2
+ coverage
3
+ pkg
4
+ spec/tmp
5
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
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
- def export_i18n_messages
38
- SimplesIdeias::I18n.export! if Rails.env.development?
39
- end
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
- You can use it to translate your messages:
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/test/i18n-test.js</tt> for more examples!
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 'rake'
2
- require 'rake/testtask'
3
- require 'rake/rdoctask'
4
- require File.dirname(__FILE__) + '/lib/i18n-js/version'
1
+ require "bundler"
2
+ Bundler::GemHelper.install_tasks
5
3
 
6
- desc 'Default: run unit tests.'
7
- task :default => :test
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
- begin
27
- require 'jeweler'
9
+ require "rspec/core/rake_task"
10
+ RSpec::Core::RakeTask.new(:"spec:ruby")
28
11
 
29
- JEWEL = Jeweler::Tasks.new do |gem|
30
- gem.name = "i18n-js"
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
@@ -1,9 +1,9 @@
1
1
  module SimplesIdeias
2
2
  module I18n
3
3
  module Version
4
- MAJOR = 0
5
- MINOR = 1
6
- PATCH = 6
4
+ MAJOR = 1
5
+ MINOR = 0
6
+ PATCH = 0
7
7
  STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
8
8
  end
9
9
  end
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
- var translations = this.prepareOptions(I18n.translations);
18
- var messages = translations[I18n.currentLocale()];
19
- options = this.prepareOptions(options);
17
+ var translations = this.prepareOptions(I18n.translations);
18
+ var messages = translations[I18n.currentLocale()];
19
+ options = this.prepareOptions(options);
20
20
 
21
- if (!messages) {
22
- return;
23
- }
21
+ if (!messages) {
22
+ return;
23
+ }
24
24
 
25
- if (typeof(scope) == "object") {
26
- scope = scope.join(this.defaultSeparator);
27
- }
25
+ if (typeof(scope) == "object") {
26
+ scope = scope.join(this.defaultSeparator);
27
+ }
28
28
 
29
- if (options.scope) {
30
- scope = options.scope.toString() + this.defaultSeparator + scope;
31
- }
29
+ if (options.scope) {
30
+ scope = options.scope.toString() + this.defaultSeparator + scope;
31
+ }
32
32
 
33
- scope = scope.split(this.defaultSeparator);
33
+ scope = scope.split(this.defaultSeparator);
34
34
 
35
- while (scope.length > 0) {
36
- var currentScope = scope.shift();
37
- messages = messages[currentScope];
35
+ while (scope.length > 0) {
36
+ var currentScope = scope.shift();
37
+ messages = messages[currentScope];
38
38
 
39
- if (!messages) {
40
- break;
41
- }
42
- }
39
+ if (!messages) {
40
+ break;
41
+ }
42
+ }
43
43
 
44
- if (!messages && options.defaultValue != null && options.defaultValue != undefined) {
45
- messages = options.defaultValue;
46
- }
44
+ if (!messages && options.defaultValue != null && options.defaultValue != undefined) {
45
+ messages = options.defaultValue;
46
+ }
47
47
 
48
- return messages;
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
- // I18n.prepareOptions({name: "John Doe"}, {name: "Mary Doe", role: "user"});
55
- // #=> {name: "John Doe", role: "user"}
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
- var options = {};
59
- var opts;
60
- var count = arguments.length;
58
+ var options = {};
59
+ var opts;
60
+ var count = arguments.length;
61
61
 
62
- for (var i = 0; i < count; i++) {
63
- opts = arguments[i];
62
+ for (var i = 0; i < count; i++) {
63
+ opts = arguments[i];
64
64
 
65
- if (!opts) {
66
- continue;
67
- }
65
+ if (!opts) {
66
+ continue;
67
+ }
68
68
 
69
- for (var key in opts) {
70
- if (options[key] == undefined || options[key] == null) {
71
- options[key] = opts[key];
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
- return options;
76
+ return options;
77
77
  };
78
78
 
79
79
  I18n.interpolate = function(message, options) {
80
- options = this.prepareOptions(options);
81
- var matches = message.match(this.PLACEHOLDER);
80
+ options = this.prepareOptions(options);
81
+ var matches = message.match(this.PLACEHOLDER);
82
82
 
83
- if (!matches) {
84
- return message;
85
- }
83
+ if (!matches) {
84
+ return message;
85
+ }
86
86
 
87
- var placeholder, value, name;
87
+ var placeholder, value, name;
88
88
 
89
- for (var i = 0; placeholder = matches[i]; i++) {
90
- name = placeholder.replace(this.PLACEHOLDER, "$1");
89
+ for (var i = 0; placeholder = matches[i]; i++) {
90
+ name = placeholder.replace(this.PLACEHOLDER, "$1");
91
91
 
92
- value = options[name];
92
+ value = options[name];
93
93
 
94
- if (options[name] == null || options[name] == undefined) {
95
- value = "[missing " + placeholder + " value]";
96
- }
94
+ if (options[name] == null || options[name] == undefined) {
95
+ value = "[missing " + placeholder + " value]";
96
+ }
97
97
 
98
- regex = new RegExp(placeholder.replace(/\{/gm, "\\{").replace(/\}/gm, "\\}"));
99
- message = message.replace(regex, value);
100
- }
98
+ regex = new RegExp(placeholder.replace(/\{/gm, "\\{").replace(/\}/gm, "\\}"));
99
+ message = message.replace(regex, value);
100
+ }
101
101
 
102
- return message;
102
+ return message;
103
103
  };
104
104
 
105
105
  I18n.translate = function(scope, options) {
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
- }
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
- 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
- }
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
- 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;
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
- var date = this.parseDate(d);
175
- var format = this.lookup(scope);
174
+ var date = this.parseDate(d);
175
+ var format = this.lookup(scope);
176
176
 
177
- if (date.toString().match(/invalid/i)) {
178
- return date.toString();
179
- }
177
+ if (date.toString().match(/invalid/i)) {
178
+ return date.toString();
179
+ }
180
180
 
181
- if (!format) {
182
- return date.toString();
183
- }
181
+ if (!format) {
182
+ return date.toString();
183
+ }
184
184
 
185
- return this.strftime(date, format);
185
+ return this.strftime(date, format);
186
186
  };
187
187
 
188
188
  I18n.strftime = function(date, format) {
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;
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
- 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;
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
- 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;
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
- options = this.prepareOptions(
297
- options,
298
- this.lookup("number.percentage.format"),
299
- this.lookup("number.format"),
300
- {precision: 3, separator: ".", delimiter: ""}
301
- );
302
-
303
- number = this.toNumber(number, options);
304
- return number + "%";
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
- var translation;
309
-
310
- try {
311
- translation = this.lookup(scope, options);
312
- } catch (error) {}
313
-
314
- if (!translation) {
315
- return this.missingTranslation(scope);
316
- }
317
-
318
- var message;
319
- options = this.prepareOptions(options);
320
- options["count"] = count.toString();
321
-
322
- switch(Math.abs(count)) {
323
- case 0:
324
- message = translation["zero"] || translation["none"] || translation["other"] || this.missingTranslation(scope, "zero");
325
- break;
326
- case 1:
327
- message = translation["one"] || this.missingTranslation(scope, "one");
328
- break;
329
- default:
330
- message = translation["other"] || this.missingTranslation(scope, "other");
331
- }
332
-
333
- return this.interpolate(message, options);
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
- var message = '[missing "' + this.currentLocale();
338
- var count = arguments.length;
372
+ var message = '[missing "' + this.currentLocale();
373
+ var count = arguments.length;
339
374
 
340
- for (var i = 0; i < count; i++) {
341
- message += "." + arguments[i];
342
- }
375
+ for (var i = 0; i < count; i++) {
376
+ message += "." + arguments[i];
377
+ }
343
378
 
344
- message += '" translation]';
379
+ message += '" translation]';
345
380
 
346
- return message;
381
+ return message;
347
382
  };
348
383
 
349
384
  I18n.currentLocale = function() {
350
- return (I18n.locale || I18n.defaultLocale);
385
+ return (I18n.locale || I18n.defaultLocale);
351
386
  };
352
387
 
353
388
  // shortcuts