i18n-js 3.0.0.rc5 → 3.0.0.rc6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.travis.yml +10 -0
- data/Appraisals +4 -0
- data/CHANGELOG.md +27 -0
- data/README.md +101 -20
- data/Rakefile +12 -1
- data/app/assets/javascripts/i18n.js +146 -33
- data/app/assets/javascripts/i18n/{translations.js.erb → filtered.js.erb} +1 -3
- data/app/assets/javascripts/i18n/shims.js +26 -0
- data/app/assets/javascripts/i18n/translations.js +3 -0
- data/gemfiles/i18n_0_6.gemfile +7 -0
- data/i18n-js.gemspec +5 -3
- data/lib/i18n/js.rb +13 -15
- data/lib/i18n/js/dependencies.rb +61 -0
- data/lib/i18n/js/engine.rb +6 -7
- data/lib/i18n/js/middleware.rb +13 -4
- data/lib/i18n/js/version.rb +1 -1
- data/lib/rails/generators/i18n/js/config/config_generator.rb +19 -0
- data/lib/rails/generators/i18n/js/config/templates/i18n-js.yml +28 -0
- data/lib/tasks/export.rake +8 -0
- data/spec/fixtures/erb.yml +4 -0
- data/spec/fixtures/locales.yml +6 -0
- data/spec/fixtures/multiple_conditions_per_locale.yml +5 -0
- data/spec/i18n_js_spec.rb +46 -1
- data/spec/js/dates.spec.js +40 -0
- data/spec/js/specs.html +1 -1
- data/spec/js/translate.spec.js +58 -0
- data/spec/js/translations.js +12 -1
- data/spec/spec_helper.rb +10 -2
- metadata +86 -16
- data/Gemfile.lock +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37f6e669f9c581fd9b82bf2141dc6829b1a32d21
|
4
|
+
data.tar.gz: 5203d02a3ce1445054f036930c7cca0bf2103809
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65ee86cbca52f2b511e9f39511308ae0640d0c1fb3099f685687eabe9d2cad4b4f28e08a389fd1b8c70bd3f71c5b475f4d1d8fa28ca07e4a4820fdfc8a496bfb
|
7
|
+
data.tar.gz: a0f657c665ddc48f6c49b25321dd3ed15fa66407a9baa24ee91386604f98bd1fbf1bc40fdab23460f2c4246e12f8a63512ea6dd12b172c5f256651264a118aaf
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/Appraisals
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
## 3.0.0.rc6
|
2
|
+
|
3
|
+
### enhancements
|
4
|
+
|
5
|
+
- You can now assign `I18n.locale` & `I18n.default_locale` before loading `i18n.js` in `application.html.*`
|
6
|
+
(merged to `i18n-js-pika` already)
|
7
|
+
- You can include ERB in `config/i18n-js.yml`(https://github.com/fnando/i18n-js/pull/224)
|
8
|
+
- Add support for +00:00 style time zone designator (https://github.com/fnando/i18n-js/pull/167)
|
9
|
+
- Add back rake task for export (`rake i18n:js:export`)
|
10
|
+
- Not overriding translation when manually run `I18n::JS.export` (https://github.com/fnando/i18n-js/pull/171)
|
11
|
+
- Move missing placeholder text generation into its own function (for easier debugging) (https://github.com/fnando/i18n-js/pull/169)
|
12
|
+
- Add support for milliseconds (`lll` in `yyyy-mm-ddThh:mm:ss.lllZ`) (https://github.com/fnando/i18n-js/pull/192)
|
13
|
+
- Add back i18n-js.yml config file generator : `rails generate i18n:js:config` (https://github.com/fnando/i18n-js/pull/225)
|
14
|
+
|
15
|
+
### bug fixes
|
16
|
+
|
17
|
+
- `I18n::JS.export` no longer exports locales other than those in `I18n.available_locales`, if `I18n.available_locales` is set
|
18
|
+
- I18.t supports the base scope through the options argument
|
19
|
+
- I18.t accepts an array as the scope
|
20
|
+
- Fix regression: asset not being reloaded in development when translation changed
|
21
|
+
- Requires `i18n` to be `~> 0.6`, `0.5` does not work at all
|
22
|
+
- Fix using multi-star scope with top-level translation key (https://github.com/fnando/i18n-js/pull/221)
|
23
|
+
|
24
|
+
|
25
|
+
## Before 3.0.0.rc5
|
26
|
+
|
27
|
+
- Things happened.
|
data/README.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# I18n.js
|
2
2
|
|
3
|
-
|
3
|
+
[![Build Status](https://travis-ci.org/fnando/i18n-js.svg?branch=master)](https://travis-ci.org/fnando/i18n-js)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/fnando/i18n-js.png)](https://codeclimate.com/github/fnando/i18n-js)
|
5
|
+
|
6
|
+
It's a small library to provide the Rails I18n translations on the JavaScript.
|
4
7
|
|
5
8
|
Features:
|
6
9
|
|
@@ -19,23 +22,32 @@ Features:
|
|
19
22
|
|
20
23
|
Add the gem to your Gemfile.
|
21
24
|
|
22
|
-
source
|
25
|
+
source "https://rubygems.org"
|
23
26
|
gem "rails", "3.2.3"
|
24
27
|
gem "i18n-js"
|
25
28
|
|
29
|
+
#### Rails app with [Asset Pipeline](http://guides.rubyonrails.org/asset_pipeline.html)
|
30
|
+
|
26
31
|
If you're using the [asset pipeline](http://guides.rubyonrails.org/asset_pipeline.html),
|
27
32
|
then you must add the following line to your `app/assets/javascripts/application.js`.
|
28
33
|
|
29
|
-
|
34
|
+
```javascript
|
35
|
+
//= require i18n/translations
|
36
|
+
```
|
37
|
+
|
38
|
+
#### Rails app without [Asset Pipeline](http://guides.rubyonrails.org/asset_pipeline.html)
|
30
39
|
|
31
40
|
If you're not using the asset pipeline, download the JavaScript file at
|
32
41
|
<https://github.com/fnando/i18n-js/tree/master/lib/i18n.js> and load it on your page.
|
33
42
|
Also load the `translations.js` file.
|
34
43
|
|
35
|
-
|
44
|
+
```erb
|
45
|
+
<%= javascript_include_tag "i18n", "translations" %>
|
46
|
+
```
|
36
47
|
|
37
48
|
This `translations.js` file can be automatically generated by the `I18n::JS::Middleware`.
|
38
49
|
Just add it to your `config/application.rb` file.
|
50
|
+
Don't add this middleware if you are using [asset pipeline](http://guides.rubyonrails.org/asset_pipeline.html)!
|
39
51
|
|
40
52
|
config.middleware.use I18n::JS::Middleware
|
41
53
|
|
@@ -44,10 +56,53 @@ it by running the following command. Move the middleware line to your
|
|
44
56
|
`config/environments/development.rb` file and run the following command before
|
45
57
|
deploying.
|
46
58
|
|
47
|
-
$
|
59
|
+
$ rake i18n:js:export
|
48
60
|
|
49
61
|
This will export all translation files, including the custom scopes you may have
|
50
|
-
defined on `config/i18n-js.yml`.
|
62
|
+
defined on `config/i18n-js.yml`. If `I18n.available_locales` is set (e.g. in your
|
63
|
+
Rails `config/application.rb` file) then only the specified locales will be exported.
|
64
|
+
|
65
|
+
#### Export Configuration
|
66
|
+
|
67
|
+
Exported translation files generated by `I18n::JS::Middleware` or `rake i18n:js:export` can be customized with config file `config/i18n-js.yml` (use `rails generate i18n:js:config` to create it). You can even get more files generated to different folders and with different translations to best suit your needs. But this does not affect anything if you use Asset Pipeline.
|
68
|
+
|
69
|
+
Examples:
|
70
|
+
```yaml
|
71
|
+
translations:
|
72
|
+
- file: 'public/javascripts/path-to-your-messages-file.js'
|
73
|
+
only: '*.date.formats'
|
74
|
+
- file: 'public/javascripts/path-to-your-second-file.js'
|
75
|
+
only: ['*.activerecord', '*.admin.*.title']
|
76
|
+
```
|
77
|
+
|
78
|
+
If `only` is omitted all the translations will be saved. Also, make sure you add that initial `*`; it specifies that all languages will be exported. If you want to export only one language, you can do something like this:
|
79
|
+
```yaml
|
80
|
+
translations:
|
81
|
+
- file: 'public/javascripts/en.js'
|
82
|
+
only: 'en.*'
|
83
|
+
- file: 'public/javascripts/pt-BR.js'
|
84
|
+
only: 'pt-BR.*'
|
85
|
+
```
|
86
|
+
|
87
|
+
Optionally, you can auto generate a translation file per available locale if you specify the `%{locale}` placeholder.
|
88
|
+
```yaml
|
89
|
+
translations:
|
90
|
+
- file: "public/javascripts/i18n/%{locale}.js"
|
91
|
+
only: '*'
|
92
|
+
- file: "public/javascripts/frontend/i18n/%{locale}.js"
|
93
|
+
only: ['frontend', 'users']
|
94
|
+
```
|
95
|
+
|
96
|
+
You can also include ERB in your config file.
|
97
|
+
```yaml
|
98
|
+
translations:
|
99
|
+
<% Widgets.each do |widget| %>
|
100
|
+
- file: <%= "'#{widget.file}'" %>
|
101
|
+
only: <%= "'#{widget.only}'" %>
|
102
|
+
<% end %>
|
103
|
+
```
|
104
|
+
|
105
|
+
To find more examples on how to use the configuration file please refer to the tests.
|
51
106
|
|
52
107
|
#### Vanilla JavaScript
|
53
108
|
|
@@ -59,13 +114,24 @@ by hand or using your favorite programming language. More info below.
|
|
59
114
|
You **don't** need to set up a thing. The default settings will work just okay. But if you want to split translations into several files or specify specific contexts, you can follow the rest of this setting up section.
|
60
115
|
|
61
116
|
Set your locale is easy as
|
117
|
+
```javascript
|
118
|
+
I18n.defaultLocale = "pt-BR";
|
119
|
+
I18n.locale = "pt-BR";
|
120
|
+
I18n.currentLocale();
|
121
|
+
// pt-BR
|
122
|
+
```
|
62
123
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
124
|
+
**NOTE:** You can now apply your configuration **before I18n** is loaded like this:
|
125
|
+
```javascript
|
126
|
+
I18n = {} // You must define this object in top namespace, which should be `window`
|
127
|
+
I18n.defaultLocale = "pt-BR";
|
128
|
+
I18n.locale = "pt-BR";
|
67
129
|
|
68
|
-
|
130
|
+
// Load I18n from `i18n.js`, `application.js` or whatever
|
131
|
+
|
132
|
+
I18n.currentLocale();
|
133
|
+
// pt-BR
|
134
|
+
```
|
69
135
|
|
70
136
|
In practice, you'll have something like the following in your `application.html.erb`:
|
71
137
|
|
@@ -77,7 +143,7 @@ In practice, you'll have something like the following in your `application.html.
|
|
77
143
|
You can use translate your messages:
|
78
144
|
|
79
145
|
I18n.t("some.scoped.translation");
|
80
|
-
// or translate with
|
146
|
+
// or translate with explicit setting of locale
|
81
147
|
I18n.t("some.scoped.translation", {locale: "fr"});
|
82
148
|
|
83
149
|
You can also interpolate values:
|
@@ -92,6 +158,21 @@ You can set default values for missing scopes:
|
|
92
158
|
// with interpolation
|
93
159
|
I18n.t("noun", {defaultValue: "I'm a {{noun}}", noun: "Mac"});
|
94
160
|
|
161
|
+
You can also provide a list of default fallbacks for missing scopes:
|
162
|
+
|
163
|
+
// As a scope
|
164
|
+
I18n.t("some.missing.scope", {defaults: [{scope: "some.existing.scope"}]});
|
165
|
+
|
166
|
+
// As a simple translation
|
167
|
+
I18n.t("some.missing.scope", {defaults: [{message: "some.existing.scope"}]});
|
168
|
+
|
169
|
+
Default values must be provided as an array of hashs where the key is the
|
170
|
+
type of translation desired, a `scope` or a `message`. The translation returned
|
171
|
+
will be either the first scope recognized, or the first message defined.
|
172
|
+
|
173
|
+
The translation will fallback to the `defaultValue` translation if no scope
|
174
|
+
in `defaults` matches and if no default of type `message` is found.
|
175
|
+
|
95
176
|
Translation fallback can be enabled by enabling the `I18n.fallbacks` option:
|
96
177
|
|
97
178
|
<script type="text/javascript">
|
@@ -114,7 +195,7 @@ are three different ways of doing it so:
|
|
114
195
|
I18n.locales.no = "nb";
|
115
196
|
I18n.locales.no = function(locale){ return ["nb"]; };
|
116
197
|
|
117
|
-
Pluralization is possible as well and by default provides
|
198
|
+
Pluralization is possible as well and by default provides English rules:
|
118
199
|
|
119
200
|
I18n.t("inbox.counting", {count: 10}); // You have 10 messages
|
120
201
|
|
@@ -127,7 +208,7 @@ The sample above expects the following translation:
|
|
127
208
|
other: You have {{count}} new messages
|
128
209
|
zero: You have no messages
|
129
210
|
|
130
|
-
**NOTE:**
|
211
|
+
**NOTE:** Rails I18n recognizes the `zero` option.
|
131
212
|
|
132
213
|
If you need special rules just define them for your language, for example Russian, just add a new pluralizer:
|
133
214
|
|
@@ -232,7 +313,6 @@ The accepted formats are:
|
|
232
313
|
%A - The full weekday name (Sunday)
|
233
314
|
%b - The abbreviated month name (Jan)
|
234
315
|
%B - The full month name (January)
|
235
|
-
%c - The preferred local date and time representation
|
236
316
|
%d - Day of the month (01..31)
|
237
317
|
%-d - Day of the month (1..31)
|
238
318
|
%H - Hour of the day, 24-hour clock (00..23)
|
@@ -256,7 +336,7 @@ Check out `spec/*.spec.js` files for more examples!
|
|
256
336
|
|
257
337
|
## Using I18n.js with other languages (Python, PHP, ...)
|
258
338
|
|
259
|
-
The JavaScript library is language agnostic; so you can use it with PHP, Python, [
|
339
|
+
The JavaScript library is language agnostic; so you can use it with PHP, Python, [your favorite language here].
|
260
340
|
The only requirement is that you need to set the `translations` attribute like following:
|
261
341
|
|
262
342
|
I18n.translations = {};
|
@@ -278,10 +358,11 @@ The only requirement is that you need to set the `translations` attribute like f
|
|
278
358
|
Once you've made your great commits:
|
279
359
|
|
280
360
|
1. [Fork](http://help.github.com/forking/) I18n.js
|
281
|
-
2. Create a
|
282
|
-
3.
|
283
|
-
4.
|
284
|
-
5.
|
361
|
+
2. Create a branch with a clear name
|
362
|
+
3. Make your changes (Please also add/change spec, README and CHANGELOG if applicable)
|
363
|
+
4. Push changes to the created branch
|
364
|
+
5. [Create an Pull Request](http://github.com/fnando/i18n-js/pulls)
|
365
|
+
6. That's it!
|
285
366
|
|
286
367
|
Please respect the indentation rules and code style.
|
287
368
|
And use 2 spaces, not tabs. And don't touch the versioning thing.
|
data/Rakefile
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
+
require "appraisal"
|
2
|
+
require "rubygems"
|
1
3
|
require "bundler"
|
4
|
+
require "rspec/core/rake_task"
|
5
|
+
|
2
6
|
Bundler::GemHelper.install_tasks
|
3
7
|
|
4
|
-
require "rspec/core/rake_task"
|
5
8
|
RSpec::Core::RakeTask.new(:"spec:ruby")
|
6
9
|
|
7
10
|
desc "Run JavaScript specs"
|
@@ -11,3 +14,11 @@ end
|
|
11
14
|
|
12
15
|
desc "Run all specs"
|
13
16
|
task :spec => ["spec:ruby", "spec:js"]
|
17
|
+
|
18
|
+
if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
|
19
|
+
task :default do
|
20
|
+
sh "appraisal install && rake appraisal spec"
|
21
|
+
end
|
22
|
+
else
|
23
|
+
task :default => :spec
|
24
|
+
end
|
@@ -23,11 +23,12 @@
|
|
23
23
|
};
|
24
24
|
|
25
25
|
// Set default days/months translations.
|
26
|
-
var
|
26
|
+
var DATE = {
|
27
27
|
day_names: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
|
28
28
|
, abbr_day_names: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
|
29
29
|
, month_names: [null, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
|
30
30
|
, abbr_month_names: [null, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
31
|
+
, meridian: ["AM", "PM"]
|
31
32
|
};
|
32
33
|
|
33
34
|
// Set default number format.
|
@@ -57,30 +58,59 @@
|
|
57
58
|
// Set default size units.
|
58
59
|
var SIZE_UNITS = [null, "kb", "mb", "gb", "tb"];
|
59
60
|
|
60
|
-
//
|
61
|
-
var
|
61
|
+
// Other default options
|
62
|
+
var DEFAULT_OPTIONS = {
|
63
|
+
defaultLocale: "en",
|
64
|
+
locale: "en",
|
65
|
+
defaultSeparator: ".",
|
66
|
+
placeholder: /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm,
|
67
|
+
fallbacks: false,
|
68
|
+
translations: {},
|
69
|
+
};
|
62
70
|
|
63
71
|
I18n.reset = function() {
|
64
72
|
// Set default locale. This locale will be used when fallback is enabled and
|
65
73
|
// the translation doesn't exist in a particular locale.
|
66
|
-
this.defaultLocale =
|
74
|
+
this.defaultLocale = DEFAULT_OPTIONS.defaultLocale;
|
67
75
|
|
68
76
|
// Set the current locale to `en`.
|
69
|
-
this.locale =
|
77
|
+
this.locale = DEFAULT_OPTIONS.locale;
|
70
78
|
|
71
79
|
// Set the translation key separator.
|
72
|
-
this.defaultSeparator =
|
80
|
+
this.defaultSeparator = DEFAULT_OPTIONS.defaultSeparator;
|
73
81
|
|
74
82
|
// Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
|
75
|
-
this.placeholder =
|
83
|
+
this.placeholder = DEFAULT_OPTIONS.placeholder;
|
76
84
|
|
77
85
|
// Set if engine should fallback to the default locale when a translation
|
78
86
|
// is missing.
|
79
|
-
this.fallbacks =
|
87
|
+
this.fallbacks = DEFAULT_OPTIONS.fallbacks;
|
80
88
|
|
81
89
|
// Set the default translation object.
|
82
|
-
this.translations =
|
90
|
+
this.translations = DEFAULT_OPTIONS.translations;
|
91
|
+
};
|
92
|
+
|
93
|
+
// Much like `reset`, but only assign options if not already assigned
|
94
|
+
I18n.initializeOptions = function() {
|
95
|
+
if (typeof(this.defaultLocale) === "undefined" && this.defaultLocale !== null)
|
96
|
+
this.defaultLocale = DEFAULT_OPTIONS.defaultLocale;
|
97
|
+
|
98
|
+
if (typeof(this.locale) === "undefined" && this.locale !== null)
|
99
|
+
this.locale = DEFAULT_OPTIONS.locale;
|
100
|
+
|
101
|
+
if (typeof(this.defaultSeparator) === "undefined" && this.defaultSeparator !== null)
|
102
|
+
this.defaultSeparator = DEFAULT_OPTIONS.defaultSeparator;
|
103
|
+
|
104
|
+
if (typeof(this.placeholder) === "undefined" && this.placeholder !== null)
|
105
|
+
this.placeholder = DEFAULT_OPTIONS.placeholder;
|
106
|
+
|
107
|
+
if (typeof(this.fallbacks) === "undefined" && this.fallbacks !== null)
|
108
|
+
this.fallbacks = DEFAULT_OPTIONS.fallbacks;
|
109
|
+
|
110
|
+
if (typeof(this.translations) === "undefined" && this.translations !== null)
|
111
|
+
this.translations = DEFAULT_OPTIONS.translations;
|
83
112
|
};
|
113
|
+
I18n.initializeOptions();
|
84
114
|
|
85
115
|
// Return a list of all locales that must be tried before returning the
|
86
116
|
// missing translation message. By default, this will consider the inline option,
|
@@ -181,10 +211,6 @@
|
|
181
211
|
}
|
182
212
|
};
|
183
213
|
|
184
|
-
// Reset all default attributes. This is specially useful
|
185
|
-
// while running tests.
|
186
|
-
I18n.reset();
|
187
|
-
|
188
214
|
// Return current locale. If no locale has been set, then
|
189
215
|
// the current locale will be the default locale.
|
190
216
|
I18n.currentLocale = function() {
|
@@ -209,6 +235,19 @@
|
|
209
235
|
, translations
|
210
236
|
;
|
211
237
|
|
238
|
+
// Deal with the scope as an array.
|
239
|
+
if (scope.constructor === Array) {
|
240
|
+
scope = scope.join(this.defaultSeparator);
|
241
|
+
}
|
242
|
+
|
243
|
+
// Deal with the scope option provided through the second argument.
|
244
|
+
//
|
245
|
+
// I18n.t('hello', {scope: 'greetings'});
|
246
|
+
//
|
247
|
+
if (options.scope) {
|
248
|
+
scope = [options.scope, scope].join(this.defaultSeparator);
|
249
|
+
}
|
250
|
+
|
212
251
|
while (locales.length) {
|
213
252
|
locale = locales.shift();
|
214
253
|
scopes = scope.split(this.defaultSeparator);
|
@@ -236,6 +275,24 @@
|
|
236
275
|
}
|
237
276
|
};
|
238
277
|
|
278
|
+
// Rails changed the way the meridian is stored.
|
279
|
+
// It started with `date.meridian` returning an array,
|
280
|
+
// then it switched to `time.am` and `time.pm`.
|
281
|
+
// This function abstracts this difference and returns
|
282
|
+
// the correct meridian or the default value when none is provided.
|
283
|
+
I18n.meridian = function() {
|
284
|
+
var time = this.lookup("time");
|
285
|
+
var date = this.lookup("date");
|
286
|
+
|
287
|
+
if (time && time.am && time.pm) {
|
288
|
+
return [time.am, time.pm];
|
289
|
+
} else if (date && date.meridian) {
|
290
|
+
return date.meridian;
|
291
|
+
} else {
|
292
|
+
return DATE.meridian;
|
293
|
+
}
|
294
|
+
};
|
295
|
+
|
239
296
|
// Merge serveral hash options, checking if value is set before
|
240
297
|
// overwriting any value. The precedence is from left to right.
|
241
298
|
//
|
@@ -271,12 +328,51 @@
|
|
271
328
|
return options;
|
272
329
|
};
|
273
330
|
|
331
|
+
// Generate a list of translation options for default fallbacks.
|
332
|
+
// `defaultValue` is also deleted from options as it is returned as part of
|
333
|
+
// the translationOptions array.
|
334
|
+
I18n.createTranslationOptions = function(scope, options) {
|
335
|
+
var translationOptions = [{scope: scope}];
|
336
|
+
|
337
|
+
// Defaults should be an array of hashes containing either
|
338
|
+
// fallback scopes or messages
|
339
|
+
if (this.isSet(options.defaults)) {
|
340
|
+
translationOptions = translationOptions.concat(options.defaults);
|
341
|
+
}
|
342
|
+
|
343
|
+
// Maintain support for defaultValue. Since it is always a message
|
344
|
+
// insert it in to the translation options as such.
|
345
|
+
if (this.isSet(options.defaultValue)) {
|
346
|
+
translationOptions.push({ message: options.defaultValue });
|
347
|
+
delete options.defaultValue;
|
348
|
+
}
|
349
|
+
|
350
|
+
return translationOptions;
|
351
|
+
};
|
352
|
+
|
274
353
|
// Translate the given scope with the provided options.
|
275
354
|
I18n.translate = function(scope, options) {
|
276
355
|
options = this.prepareOptions(options);
|
277
|
-
var translation = this.lookup(scope, options);
|
278
356
|
|
279
|
-
|
357
|
+
var translationOptions = this.createTranslationOptions(scope, options);
|
358
|
+
|
359
|
+
var translation;
|
360
|
+
// Iterate through the translation options until a translation
|
361
|
+
// or message is found.
|
362
|
+
var translationFound =
|
363
|
+
translationOptions.some(function(translationOption) {
|
364
|
+
if (this.isSet(translationOption.scope)) {
|
365
|
+
translation = this.lookup(translationOption.scope, options);
|
366
|
+
} else if (this.isSet(translationOption.message)) {
|
367
|
+
translation = translationOption.message;
|
368
|
+
}
|
369
|
+
|
370
|
+
if (translation !== undefined && translation !== null) {
|
371
|
+
return true;
|
372
|
+
}
|
373
|
+
}, this);
|
374
|
+
|
375
|
+
if (!translationFound) {
|
280
376
|
return this.missingTranslation(scope);
|
281
377
|
}
|
282
378
|
|
@@ -306,17 +402,17 @@
|
|
306
402
|
while (matches.length) {
|
307
403
|
placeholder = matches.shift();
|
308
404
|
name = placeholder.replace(this.placeholder, "$1");
|
309
|
-
value = options[name];
|
405
|
+
value = options[name].toString().replace(/\$/gm, "_#$#_");
|
310
406
|
|
311
407
|
if (!this.isSet(options[name])) {
|
312
|
-
value =
|
408
|
+
value = this.missingPlaceholder(placeholder, message);
|
313
409
|
}
|
314
410
|
|
315
411
|
regex = new RegExp(placeholder.replace(/\{/gm, "\\{").replace(/\}/gm, "\\}"));
|
316
412
|
message = message.replace(regex, value);
|
317
413
|
}
|
318
414
|
|
319
|
-
return message;
|
415
|
+
return message.replace("_#$#_", "$");
|
320
416
|
};
|
321
417
|
|
322
418
|
// Pluralize the given scope using the `count` value.
|
@@ -363,6 +459,11 @@
|
|
363
459
|
return message;
|
364
460
|
};
|
365
461
|
|
462
|
+
// Return a missing placeholder message for given parameters
|
463
|
+
I18n.missingPlaceholder = function(placeholder, message) {
|
464
|
+
return "[missing " + placeholder + " value]";
|
465
|
+
};
|
466
|
+
|
366
467
|
// Format number using localization rules.
|
367
468
|
// The options will be retrieved from the `number.format` scope.
|
368
469
|
// If this isn't present, then the following options will be used:
|
@@ -481,16 +582,17 @@
|
|
481
582
|
// yyyy-mm-dd[ T]hh:mm::ss
|
482
583
|
// yyyy-mm-dd[ T]hh:mm::ssZ
|
483
584
|
// yyyy-mm-dd[ T]hh:mm::ss+0000
|
585
|
+
// yyyy-mm-dd[ T]hh:mm::ss+00:00
|
586
|
+
// yyyy-mm-dd[ T]hh:mm::ss.123Z
|
484
587
|
//
|
485
588
|
I18n.parseDate = function(date) {
|
486
|
-
var matches, convertedDate;
|
487
|
-
|
589
|
+
var matches, convertedDate, fraction;
|
488
590
|
// we have a date, so just return it.
|
489
591
|
if (typeof(date) == "object") {
|
490
592
|
return date;
|
491
593
|
};
|
492
594
|
|
493
|
-
matches = date.toString().match(/(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2}))?(Z|\+
|
595
|
+
matches = date.toString().match(/(\d{4})-(\d{2})-(\d{2})(?:[ T](\d{2}):(\d{2}):(\d{2})([\.,]\d{1,3})?)?(Z|\+00:?00)?/);
|
494
596
|
|
495
597
|
if (matches) {
|
496
598
|
for (var i = 1; i <= 6; i++) {
|
@@ -500,19 +602,28 @@
|
|
500
602
|
// month starts on 0
|
501
603
|
matches[2] -= 1;
|
502
604
|
|
503
|
-
|
504
|
-
|
605
|
+
fraction = matches[7] ? 1000 * ("0" + matches[7]) : null;
|
606
|
+
|
607
|
+
if (matches[8]) {
|
608
|
+
convertedDate = new Date(Date.UTC(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6], fraction));
|
505
609
|
} else {
|
506
|
-
convertedDate = new Date(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6]);
|
610
|
+
convertedDate = new Date(matches[1], matches[2], matches[3], matches[4], matches[5], matches[6], fraction);
|
507
611
|
}
|
508
612
|
} else if (typeof(date) == "number") {
|
509
613
|
// UNIX timestamp
|
510
614
|
convertedDate = new Date();
|
511
615
|
convertedDate.setTime(date);
|
616
|
+
} else if (date.match(/([A-Z][a-z]{2}) ([A-Z][a-z]{2}) (\d+) (\d+:\d+:\d+) ([+-]\d+) (\d+)/)) {
|
617
|
+
// This format `Wed Jul 20 13:03:39 +0000 2011` is parsed by
|
618
|
+
// webkit/firefox, but not by IE, so we must parse it manually.
|
619
|
+
convertedDate = new Date();
|
620
|
+
convertedDate.setTime(Date.parse([
|
621
|
+
RegExp.$1, RegExp.$2, RegExp.$3, RegExp.$6, RegExp.$4, RegExp.$5
|
622
|
+
].join(" ")));
|
512
623
|
} else if (date.match(/\d+ \d+:\d+:\d+ [+-]\d+ \d+/)) {
|
513
624
|
// a valid javascript format with timezone info
|
514
625
|
convertedDate = new Date();
|
515
|
-
convertedDate.setTime(Date.parse(date))
|
626
|
+
convertedDate.setTime(Date.parse(date));
|
516
627
|
} else {
|
517
628
|
// an arbitrary javascript string
|
518
629
|
convertedDate = new Date();
|
@@ -553,15 +664,15 @@
|
|
553
664
|
// %z - Timezone offset (+0545)
|
554
665
|
//
|
555
666
|
I18n.strftime = function(date, format) {
|
556
|
-
var options = this.lookup("date")
|
667
|
+
var options = this.lookup("date")
|
668
|
+
, meridianOptions = I18n.meridian()
|
669
|
+
;
|
557
670
|
|
558
671
|
if (!options) {
|
559
|
-
options =
|
672
|
+
options = {};
|
560
673
|
}
|
561
674
|
|
562
|
-
|
563
|
-
options.meridian = MERIDIAN;
|
564
|
-
}
|
675
|
+
options = this.prepareOptions(options, DATE);
|
565
676
|
|
566
677
|
var weekDay = date.getDay()
|
567
678
|
, day = date.getDate()
|
@@ -575,7 +686,9 @@
|
|
575
686
|
, offset = date.getTimezoneOffset()
|
576
687
|
, absOffsetHours = Math.floor(Math.abs(offset / 60))
|
577
688
|
, absOffsetMinutes = Math.abs(offset) - (absOffsetHours * 60)
|
578
|
-
, timezoneoffset = (offset > 0 ? "-" : "+") +
|
689
|
+
, timezoneoffset = (offset > 0 ? "-" : "+") +
|
690
|
+
(absOffsetHours.toString().length < 2 ? "0" + absOffsetHours : absOffsetHours) +
|
691
|
+
(absOffsetMinutes.toString().length < 2 ? "0" + absOffsetMinutes : absOffsetMinutes)
|
579
692
|
;
|
580
693
|
|
581
694
|
if (hour12 > 12) {
|
@@ -599,7 +712,7 @@
|
|
599
712
|
format = format.replace("%-m", month);
|
600
713
|
format = format.replace("%M", padding(mins));
|
601
714
|
format = format.replace("%-M", mins);
|
602
|
-
format = format.replace("%p",
|
715
|
+
format = format.replace("%p", meridianOptions[meridian]);
|
603
716
|
format = format.replace("%S", padding(secs));
|
604
717
|
format = format.replace("%-S", secs);
|
605
718
|
format = format.replace("%w", weekDay);
|
@@ -681,4 +794,4 @@
|
|
681
794
|
I18n.t = I18n.translate;
|
682
795
|
I18n.l = I18n.localize;
|
683
796
|
I18n.p = I18n.pluralize;
|
684
|
-
})(typeof(exports) === "undefined" ? (this.I18n = {}) : exports);
|
797
|
+
})(typeof(exports) === "undefined" ? (this.I18n || (this.I18n = {})) : exports);
|