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 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