twitter_cldr_js 3.2.0 → 3.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f742c2e22d518081be5a938b080d64766cc4a125f55e75f4c8e75c4d2e9f7f14
4
- data.tar.gz: 2168845da6ba9b3a7aee973176a70baa5585a7d58ed1c86b91a6f9b1a717c43e
3
+ metadata.gz: c7fa717f3763a3f4ca2593e5ff7104fea5f2cb56959bc89fc93f93219f34b82a
4
+ data.tar.gz: 2a1a5fe1a2f32f4eaf80f78b5aefe081b6fc85cce453940dfbe254a11d86becf
5
5
  SHA512:
6
- metadata.gz: f85ecdbdc0b8ba32057c1f053636bfa11ff83f9db712a82ebf7da61971b0bc56847c36e5557348d221579c007d2adf923abf9956d8ba2356743d7bceaf403933
7
- data.tar.gz: 4d8022ebbfca34498ae0d62d6d4efc25c6e8f3b928d0a3b92525b2674fb37a632638cef04496cbbc0a8f88957e9095f8d53fc0880587462038432d524a4b60bd
6
+ metadata.gz: 77e9dd6b9439d03d11c26de9027dc7080a5dcbd46519f58623931a864c2f09c11654ff8cc79855eb8e175b329613ea744aa24db235748fa03aff40f610b20040
7
+ data.tar.gz: 30a80da24b9d490da60530f0d0470264f766748d4fc2756235f2ee6edce5bf070831a5ed5c61b08b06bad732aca44f34b34499168fc1ab5a5d8f5f2a912a893f
data/Gemfile CHANGED
@@ -3,7 +3,7 @@ source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  group :test do
6
- gem 'rspec', '~> 2.11.0'
6
+ gem 'rspec', '~> 3.0'
7
7
  gem 'rr', '~> 1.0.4'
8
8
  end
9
9
 
data/README.md CHANGED
@@ -297,7 +297,7 @@ formatter.format(123, 'OrdinalRules', 'digits-ordinal')
297
297
  // '123rd'
298
298
  ```
299
299
 
300
- In comparision, here is what the Spanish formatting looks like
300
+ In comparison, here is what the Spanish formatting looks like
301
301
  ```javascript
302
302
  // include the es data bundle for the Spanish RBNF Formatter
303
303
  var formatter = new TwitterCldr.RBNF()
@@ -397,7 +397,7 @@ TwitterCldr.TerritoriesContainment.contains('419', 'FR') // false
397
397
 
398
398
  ### Unicode Regular Expressions
399
399
 
400
- Unicode regular expressions are an implmentaion of regular expressions that support all Unicode characters in the [BMP](http://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane). They provide support for multi-character strings, Unicode character escapes, set operations (unions, intersections, and differences), and character sets.
400
+ Unicode regular expressions are an implementaion of regular expressions that support all Unicode characters in the [BMP](http://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane). They provide support for multi-character strings, Unicode character escapes, set operations (unions, intersections, and differences), and character sets.
401
401
 
402
402
  #### Changes to Character Classes
403
403
 
@@ -429,7 +429,7 @@ regex3 = TwitterCldr.UnicodeRegex.compile("[[a-z]-[d-g]]+", "g");
429
429
  //supports the JavaScript RegExp modifiers
430
430
  ```
431
431
 
432
- Once compiled, instances of `UnicodeRegex` behave just like normal javascript regexes and support the `match` method:
432
+ Once compiled, instances of `UnicodeRegex` can be directly used to match against a string:
433
433
 
434
434
  ```javascript
435
435
 
@@ -438,6 +438,15 @@ regex2.match("ABCDfooABC"); // ["ABCD", "ABC"]
438
438
  regex3.match("dog"); // ["o"]
439
439
  ```
440
440
 
441
+ Alternatively, you can convert a `UnicodeRegex` into a native JavaScript regex by calling its `to_regexp` method:
442
+
443
+ ```javascript
444
+
445
+ regex3.to_regexp(); // /(?:[\u0061-\u0063]|[\u0068-\u007a])+/g
446
+ regex3.to_regexp().test("a"); // true
447
+ regex3.to_regexp().test("d"); // false
448
+ ```
449
+
441
450
  Protip: Try to avoid negation in character classes (eg. [^abc] and \P{Lu}) as it tends to negatively affect both performance when constructing regexes as well as matching.
442
451
 
443
452
  ### Text Segmentation
@@ -16,10 +16,11 @@
16
16
  /*_lib/twitter_cldr_*/
17
17
 
18
18
  (function() {
19
- var TwitterCldr, key, obj, root,
19
+ var TwitterCldr, get_with_data_isolation, key, obj, proxy_or_primitive, root, with_data_isolation,
20
20
  __hasProp = {}.hasOwnProperty,
21
21
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
22
- __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
22
+ __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
23
+ __slice = [].slice;
23
24
 
24
25
  TwitterCldr = {};
25
26
 
@@ -3607,7 +3608,7 @@
3607
3608
  };
3608
3609
 
3609
3610
  NumberFormatter.prototype.format = function(number, options) {
3610
- var fraction, fraction_format, integer_format, intg, key, opts, prefix, result, sign, suffix, tokens, tokens_sample, truncated_number, val, _ref, _ref1;
3611
+ var fraction, fraction_format, integer_format, intg, key, number_part, opts, prefix, result, rounded_num, sign, suffix, tokens, tokens_sample, truncated_number, val, _ref, _ref1;
3611
3612
  if (options == null) {
3612
3613
  options = {};
3613
3614
  }
@@ -3616,27 +3617,38 @@
3616
3617
  val = options[key];
3617
3618
  opts[key] = options[key] != null ? options[key] : opts[key];
3618
3619
  }
3620
+ number = this.round_to(number, opts.precision || 0);
3619
3621
  tokens = this.get_tokens(number, opts);
3620
3622
  if (tokens != null) {
3621
3623
  if (!(tokens instanceof Array)) {
3622
3624
  tokens_sample = tokens[Object.keys(tokens)[0]];
3623
3625
  truncated_number = this.truncate_number(number, tokens_sample[1].length);
3626
+ rounded_num = Number(this.parse_number(truncated_number, opts)[0]) * Number(this.get_key(number)) / (Math.pow(10, tokens_sample[1].length - 1));
3627
+ if (!opts._stack_depth && this.get_key(rounded_num) !== this.get_key(number)) {
3628
+ return this.format(rounded_num, Object.assign(opts, {
3629
+ _stack_depth: 1
3630
+ }));
3631
+ }
3624
3632
  if (opts.precision === 0) {
3625
3633
  truncated_number = Math.floor(truncated_number);
3626
3634
  }
3627
3635
  tokens = tokens[TwitterCldr.PluralRules.rule_for(truncated_number)];
3628
3636
  }
3629
3637
  _ref = this.partition_tokens(tokens), prefix = _ref[0], suffix = _ref[1], integer_format = _ref[2], fraction_format = _ref[3];
3630
- number = this.truncate_number(number, integer_format.format.length);
3631
- _ref1 = this.parse_number(number, opts), intg = _ref1[0], fraction = _ref1[1];
3638
+ number_part = this.truncate_number(number, integer_format.format.length);
3639
+ _ref1 = this.parse_number(number_part, opts), intg = _ref1[0], fraction = _ref1[1];
3632
3640
  result = integer_format.apply(parseFloat(intg), opts);
3633
3641
  if (fraction) {
3634
3642
  result += fraction_format.apply(fraction, opts);
3635
3643
  }
3636
- sign = number < 0 && prefix !== "-" ? this.symbols().minus_sign || this.default_symbols.minus_sign : "";
3644
+ sign = number_part < 0 && prefix !== "-" ? this.symbols().minus_sign || this.default_symbols.minus_sign : "";
3637
3645
  return "" + prefix + result + suffix;
3638
3646
  } else {
3639
- return number.toString();
3647
+ if (!(this instanceof TwitterCldr.DecimalFormatter)) {
3648
+ return new TwitterCldr.DecimalFormatter().format(number, opts);
3649
+ } else {
3650
+ return number.toString();
3651
+ }
3640
3652
  }
3641
3653
  };
3642
3654
 
@@ -3679,7 +3691,7 @@
3679
3691
  };
3680
3692
 
3681
3693
  NumberFormatter.prototype.get_tokens = function() {
3682
- throw "get_tokens() not implemented - use a derived class like PercentFormatter.";
3694
+ throw new Error("get_tokens() not implemented - use a derived class like PercentFormatter.");
3683
3695
  };
3684
3696
 
3685
3697
  return NumberFormatter;
@@ -3746,7 +3758,7 @@
3746
3758
  return result;
3747
3759
  } catch (_error) {
3748
3760
  error = _error;
3749
- return number;
3761
+ return number.toString();
3750
3762
  }
3751
3763
  };
3752
3764
 
@@ -5447,6 +5459,292 @@
5447
5459
 
5448
5460
  })();
5449
5461
 
5462
+ with_data_isolation = function(data) {
5463
+ return function(fn) {
5464
+ var original, result;
5465
+ original = TwitterCldr.data;
5466
+ TwitterCldr.data = data;
5467
+ result = fn();
5468
+ TwitterCldr.data = original;
5469
+ return result;
5470
+ };
5471
+ };
5472
+
5473
+ get_with_data_isolation = function(data) {
5474
+ return function(target, property_key, receiver) {
5475
+ var isolate_data;
5476
+ isolate_data = with_data_isolation(data);
5477
+ return isolate_data(function() {
5478
+ var fn, result;
5479
+ result = Reflect.get(target, property_key, receiver);
5480
+ if (typeof result === 'function') {
5481
+ fn = result;
5482
+ result = function() {
5483
+ var args;
5484
+ args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
5485
+ return isolate_data(function() {
5486
+ return Reflect.apply(fn, target, args);
5487
+ });
5488
+ };
5489
+ }
5490
+ return result;
5491
+ });
5492
+ };
5493
+ };
5494
+
5495
+ proxy_or_primitive = function(value, handlers) {
5496
+ if (value instanceof Object) {
5497
+ return new Proxy(value, handlers);
5498
+ } else {
5499
+ return value;
5500
+ }
5501
+ };
5502
+
5503
+ TwitterCldr.clone = function(data) {
5504
+ var get, isolate_data;
5505
+ if (!data) {
5506
+ throw new Error('Cannot create a clone with no data');
5507
+ }
5508
+ get = get_with_data_isolation(data);
5509
+ isolate_data = with_data_isolation(data);
5510
+ return proxy_or_primitive(root, {
5511
+ get: function(target, property_key, receiver) {
5512
+ switch (property_key) {
5513
+ case 'set_data':
5514
+ return function() {
5515
+ throw new Error('Cannot set data on a TwitterCldr clone');
5516
+ };
5517
+ default:
5518
+ return isolate_data(function() {
5519
+ return proxy_or_primitive(Reflect.get(target, property_key, receiver), {
5520
+ get: get,
5521
+ apply: function() {
5522
+ var args;
5523
+ args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
5524
+ return isolate_data(function() {
5525
+ return Reflect.apply.apply(Reflect, args);
5526
+ });
5527
+ },
5528
+ construct: function() {
5529
+ var args;
5530
+ args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
5531
+ return isolate_data(function() {
5532
+ return proxy_or_primitive(Reflect.construct.apply(Reflect, args), {
5533
+ get: get
5534
+ });
5535
+ });
5536
+ }
5537
+ });
5538
+ });
5539
+ }
5540
+ },
5541
+ set: function() {
5542
+ throw new Error('Cannot set properties on a TwitterCldr clone');
5543
+ }
5544
+ });
5545
+ };
5546
+
5547
+ TwitterCldr.get_available_locales = function() {
5548
+ return [
5549
+ {
5550
+ "locale": "af",
5551
+ "file_name": "af"
5552
+ }, {
5553
+ "locale": "ar",
5554
+ "file_name": "ar"
5555
+ }, {
5556
+ "locale": "be",
5557
+ "file_name": "be"
5558
+ }, {
5559
+ "locale": "bg",
5560
+ "file_name": "bg"
5561
+ }, {
5562
+ "locale": "bn",
5563
+ "file_name": "bn"
5564
+ }, {
5565
+ "locale": "ca",
5566
+ "file_name": "ca"
5567
+ }, {
5568
+ "locale": "cs",
5569
+ "file_name": "cs"
5570
+ }, {
5571
+ "locale": "cy",
5572
+ "file_name": "cy"
5573
+ }, {
5574
+ "locale": "da",
5575
+ "file_name": "da"
5576
+ }, {
5577
+ "locale": "de",
5578
+ "file_name": "de"
5579
+ }, {
5580
+ "locale": "de-CH",
5581
+ "file_name": "de-CH"
5582
+ }, {
5583
+ "locale": "el",
5584
+ "file_name": "el"
5585
+ }, {
5586
+ "locale": "en",
5587
+ "file_name": "en"
5588
+ }, {
5589
+ "locale": "en-150",
5590
+ "file_name": "en-150"
5591
+ }, {
5592
+ "locale": "en-AU",
5593
+ "file_name": "en-AU"
5594
+ }, {
5595
+ "locale": "en-CA",
5596
+ "file_name": "en-CA"
5597
+ }, {
5598
+ "locale": "en-GB",
5599
+ "file_name": "en-GB"
5600
+ }, {
5601
+ "locale": "en-IE",
5602
+ "file_name": "en-IE"
5603
+ }, {
5604
+ "locale": "en-SG",
5605
+ "file_name": "en-SG"
5606
+ }, {
5607
+ "locale": "en-ZA",
5608
+ "file_name": "en-ZA"
5609
+ }, {
5610
+ "locale": "es",
5611
+ "file_name": "es"
5612
+ }, {
5613
+ "locale": "es-419",
5614
+ "file_name": "es-419"
5615
+ }, {
5616
+ "locale": "es-CO",
5617
+ "file_name": "es-CO"
5618
+ }, {
5619
+ "locale": "es-MX",
5620
+ "file_name": "es-MX"
5621
+ }, {
5622
+ "locale": "es-US",
5623
+ "file_name": "es-US"
5624
+ }, {
5625
+ "locale": "eu",
5626
+ "file_name": "eu"
5627
+ }, {
5628
+ "locale": "fa",
5629
+ "file_name": "fa"
5630
+ }, {
5631
+ "locale": "fi",
5632
+ "file_name": "fi"
5633
+ }, {
5634
+ "locale": "fil",
5635
+ "file_name": "fil"
5636
+ }, {
5637
+ "locale": "fr",
5638
+ "file_name": "fr"
5639
+ }, {
5640
+ "locale": "fr-BE",
5641
+ "file_name": "fr-BE"
5642
+ }, {
5643
+ "locale": "fr-CA",
5644
+ "file_name": "fr-CA"
5645
+ }, {
5646
+ "locale": "fr-CH",
5647
+ "file_name": "fr-CH"
5648
+ }, {
5649
+ "locale": "ga",
5650
+ "file_name": "ga"
5651
+ }, {
5652
+ "locale": "gl",
5653
+ "file_name": "gl"
5654
+ }, {
5655
+ "locale": "he",
5656
+ "file_name": "he"
5657
+ }, {
5658
+ "locale": "hi",
5659
+ "file_name": "hi"
5660
+ }, {
5661
+ "locale": "hr",
5662
+ "file_name": "hr"
5663
+ }, {
5664
+ "locale": "hu",
5665
+ "file_name": "hu"
5666
+ }, {
5667
+ "locale": "id",
5668
+ "file_name": "id"
5669
+ }, {
5670
+ "locale": "is",
5671
+ "file_name": "is"
5672
+ }, {
5673
+ "locale": "it",
5674
+ "file_name": "it"
5675
+ }, {
5676
+ "locale": "it-CH",
5677
+ "file_name": "it-CH"
5678
+ }, {
5679
+ "locale": "ja",
5680
+ "file_name": "ja"
5681
+ }, {
5682
+ "locale": "ko",
5683
+ "file_name": "ko"
5684
+ }, {
5685
+ "locale": "lv",
5686
+ "file_name": "lv"
5687
+ }, {
5688
+ "locale": "ms",
5689
+ "file_name": "msa"
5690
+ }, {
5691
+ "locale": "nb",
5692
+ "file_name": "no"
5693
+ }, {
5694
+ "locale": "nl",
5695
+ "file_name": "nl"
5696
+ }, {
5697
+ "locale": "pl",
5698
+ "file_name": "pl"
5699
+ }, {
5700
+ "locale": "pt",
5701
+ "file_name": "pt"
5702
+ }, {
5703
+ "locale": "ro",
5704
+ "file_name": "ro"
5705
+ }, {
5706
+ "locale": "ru",
5707
+ "file_name": "ru"
5708
+ }, {
5709
+ "locale": "sk",
5710
+ "file_name": "sk"
5711
+ }, {
5712
+ "locale": "sq",
5713
+ "file_name": "sq"
5714
+ }, {
5715
+ "locale": "sr",
5716
+ "file_name": "sr"
5717
+ }, {
5718
+ "locale": "sv",
5719
+ "file_name": "sv"
5720
+ }, {
5721
+ "locale": "ta",
5722
+ "file_name": "ta"
5723
+ }, {
5724
+ "locale": "th",
5725
+ "file_name": "th"
5726
+ }, {
5727
+ "locale": "tr",
5728
+ "file_name": "tr"
5729
+ }, {
5730
+ "locale": "uk",
5731
+ "file_name": "uk"
5732
+ }, {
5733
+ "locale": "ur",
5734
+ "file_name": "ur"
5735
+ }, {
5736
+ "locale": "vi",
5737
+ "file_name": "vi"
5738
+ }, {
5739
+ "locale": "zh",
5740
+ "file_name": "zh-cn"
5741
+ }, {
5742
+ "locale": "zh-Hant",
5743
+ "file_name": "zh-tw"
5744
+ }
5745
+ ];
5746
+ };
5747
+
5450
5748
  TwitterCldr.set_data = function(bundle) {
5451
5749
  TwitterCldr.data = bundle;
5452
5750
  return null;
@@ -89,6 +89,16 @@ module TwitterCldr
89
89
  def compile_implementation(options = {})
90
90
  bundle = TwitterCldr::Js::Renderers::Bundle.new
91
91
  bundle[:locale] = TwitterCldr::DEFAULT_LOCALE
92
+
93
+ available_locales = @locales.map do |locale|
94
+ {
95
+ locale: locale,
96
+ file_name: TwitterCldr.twitter_locale(locale),
97
+ }
98
+ end
99
+
100
+ bundle[:available_locales] = available_locales.sort_by { |x| x[:locale] }.to_json
101
+
92
102
  file = compile_bundle(bundle, @features, implementation_renderers, options)
93
103
 
94
104
  file.source
@@ -152,7 +162,8 @@ module TwitterCldr
152
162
  :plural => TwitterCldr::Js::Renderers::Implementation::Numbers::RBNF::PluralRenderer,
153
163
  :range => TwitterCldr::Js::Renderers::Implementation::Utils::RangeRenderer,
154
164
  :range_set => TwitterCldr::Js::Renderers::Implementation::Utils::RangeSetRenderer,
155
- :code_points => TwitterCldr::Js::Renderers::Implementation::Utils::CodePointsRenderer
165
+ :code_points => TwitterCldr::Js::Renderers::Implementation::Utils::CodePointsRenderer,
166
+ :clone => TwitterCldr::Js::Renderers::Implementation::Clone::CloneRenderer,
156
167
  }
157
168
  end
158
169
 
@@ -23,6 +23,8 @@ TwitterCldr = {}
23
23
  {{> utilities}}
24
24
  {{{contents}}}
25
25
 
26
+ TwitterCldr.get_available_locales = -> {{{available_locales}}}
27
+
26
28
  TwitterCldr.set_data = (bundle) ->
27
29
  TwitterCldr.data = bundle
28
30
  null
@@ -0,0 +1,58 @@
1
+ with_data_isolation = (data) -> (fn) ->
2
+ original = TwitterCldr.data
3
+ TwitterCldr.data = data
4
+ result = fn()
5
+ TwitterCldr.data = original
6
+ result
7
+
8
+ get_with_data_isolation = (data) -> (target, property_key, receiver) ->
9
+ isolate_data = with_data_isolation(data)
10
+
11
+ isolate_data(->
12
+ result = Reflect.get(target, property_key, receiver)
13
+
14
+ if typeof result == 'function'
15
+ fn = result
16
+
17
+ result = (args...) -> isolate_data(-> Reflect.apply(fn, target, args))
18
+
19
+ result
20
+ )
21
+
22
+ proxy_or_primitive = (value, handlers) ->
23
+ if value instanceof Object
24
+ new Proxy(value, handlers)
25
+ else
26
+ value
27
+
28
+ TwitterCldr.clone = (data) ->
29
+ if !data
30
+ throw new Error('Cannot create a clone with no data')
31
+
32
+ get = get_with_data_isolation(data)
33
+ isolate_data = with_data_isolation(data)
34
+
35
+ proxy_or_primitive(
36
+ root,
37
+ get: (target, property_key, receiver) ->
38
+ switch property_key
39
+ when 'set_data'
40
+ return -> throw new Error('Cannot set data on a TwitterCldr clone')
41
+ else
42
+ isolate_data(
43
+ -> proxy_or_primitive(
44
+ Reflect.get(target, property_key, receiver), {
45
+ get,
46
+ apply: (args...) ->
47
+ isolate_data(
48
+ -> Reflect.apply(args...)
49
+ )
50
+ construct: (args...) ->
51
+ isolate_data(
52
+ -> proxy_or_primitive(Reflect.construct(args...), { get })
53
+ )
54
+ }
55
+ )
56
+ )
57
+ set: () -> throw new Error('Cannot set properties on a TwitterCldr clone')
58
+ )
@@ -21,30 +21,47 @@ class TwitterCldr.NumberFormatter
21
21
  @constructor.data().symbols
22
22
 
23
23
  format: (number, options = {}) ->
24
- opts = this.default_format_options_for(number)
24
+ opts = @default_format_options_for(number)
25
25
 
26
26
  for key, val of options
27
27
  opts[key] = if options[key]? then options[key] else opts[key]
28
28
 
29
- tokens = this.get_tokens(number, opts)
29
+ number = @round_to(number, opts.precision || 0)
30
+
31
+ tokens = @get_tokens(number, opts)
30
32
 
31
33
  if tokens?
32
34
  if tokens not instanceof Array
33
35
  tokens_sample = tokens[Object.keys(tokens)[0]]
34
36
  truncated_number = @truncate_number(number, tokens_sample[1].length)
37
+
38
+ rounded_num = Number(@parse_number(truncated_number, opts)[0]) * Number(@get_key(number)) / (10 ** (tokens_sample[1].length - 1))
39
+
40
+ # Checking _stack_depth should be a redundant condition, as
41
+ # @get_key(rounded_num) should always equal @get_key(number) the second
42
+ # time around. We only check it to prevent infinite loops in case of
43
+ # bugs
44
+ if !opts._stack_depth && @get_key(rounded_num) != @get_key(number)
45
+ return @format(rounded_num, Object.assign(opts, { _stack_depth: 1 }))
46
+
35
47
  truncated_number = Math.floor(truncated_number) if opts.precision == 0
36
48
  tokens = tokens[TwitterCldr.PluralRules.rule_for(truncated_number)]
37
49
 
38
- [prefix, suffix, integer_format, fraction_format] = this.partition_tokens(tokens)
39
- number = this.truncate_number(number, integer_format.format.length)
40
- [intg, fraction] = this.parse_number(number, opts)
50
+ [prefix, suffix, integer_format, fraction_format] = @partition_tokens(tokens)
51
+ number_part = @truncate_number(number, integer_format.format.length)
52
+ [intg, fraction] = @parse_number(number_part, opts)
41
53
  result = integer_format.apply(parseFloat(intg), opts)
42
54
  result += fraction_format.apply(fraction, opts) if fraction
43
- sign = if number < 0 && prefix != "-" then @symbols().minus_sign || @default_symbols.minus_sign else ""
55
+ sign = if number_part < 0 && prefix != "-" then @symbols().minus_sign || @default_symbols.minus_sign else ""
44
56
  "#{prefix}#{result}#{suffix}"
45
57
  else
46
- # there's no specific formatting pattern for this number in current locale
47
- number.toString()
58
+ unless @ instanceof TwitterCldr.DecimalFormatter
59
+ # No specific formatting pattern for this number in current locale, so
60
+ # we fall back to DecimalFormatter
61
+ new TwitterCldr.DecimalFormatter().format(number, opts)
62
+ else
63
+ # Use default toString if current instance is already a DecimalFormatter
64
+ number.toString()
48
65
 
49
66
  truncate_number: (number, decimal_digits) ->
50
67
  number # noop for base class
@@ -75,7 +92,7 @@ class TwitterCldr.NumberFormatter
75
92
  Math.round(number * factor) / factor
76
93
 
77
94
  get_tokens: ->
78
- throw "get_tokens() not implemented - use a derived class like PercentFormatter."
95
+ throw new Error("get_tokens() not implemented - use a derived class like PercentFormatter.")
79
96
 
80
97
  class TwitterCldr.PercentFormatter extends TwitterCldr.NumberFormatter
81
98
  constructor: (options = {}) ->
@@ -106,7 +123,7 @@ class TwitterCldr.DecimalFormatter extends TwitterCldr.NumberFormatter
106
123
  result = transliterator.transliterate(result)
107
124
  result
108
125
  catch error
109
- number
126
+ number.toString()
110
127
 
111
128
  default_format_options_for: (number) ->
112
129
  precision: this.precision_from(number)
@@ -0,0 +1,20 @@
1
+ # encoding: UTF-8
2
+
3
+ # Copyright 2012 Twitter, Inc
4
+ # http://www.apache.org/licenses/LICENSE-2.0
5
+
6
+ module TwitterCldr
7
+ module Js
8
+ module Renderers
9
+ module Implementation
10
+ module Clone
11
+
12
+ class CloneRenderer < TwitterCldr::Js::Renderers::Base
13
+ set_template "mustache/implementation/clone/clone.coffee"
14
+ end
15
+
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -19,6 +19,7 @@ module TwitterCldr
19
19
  autoload :Numbers, 'twitter_cldr/js/renderers/implementation/numbers'
20
20
  autoload :Parsers, 'twitter_cldr/js/renderers/implementation/parsers'
21
21
  autoload :Tokenizers, 'twitter_cldr/js/renderers/implementation/tokenizers'
22
+ autoload :Clone, 'twitter_cldr/js/renderers/implementation/clone'
22
23
 
23
24
  module Shared
24
25
  autoload :BidiRenderer, 'twitter_cldr/js/renderers/implementation/shared/bidi_renderer'
@@ -5,6 +5,6 @@
5
5
 
6
6
  module TwitterCldr
7
7
  module Js
8
- VERSION = "3.2.0"
8
+ VERSION = "3.3.0"
9
9
  end
10
10
  end
@@ -0,0 +1,234 @@
1
+ const locales = "en,ar,ko,ru,hi".split(",");
2
+ const date = new Date(2000, 1, 1);
3
+
4
+ // Updated version of
5
+ // https://github.com/twitter/twitter-cldr-npm/blob/master/twitter_cldr.js
6
+ // that clones by default
7
+ const load = function (locale, options) {
8
+ var defaultOptions = { clone: true };
9
+ options = options || {};
10
+
11
+ for (var k in defaultOptions) {
12
+ if (!(k in options)) {
13
+ options[k] = defaultOptions[k];
14
+ }
15
+ }
16
+
17
+ var TwitterCldr = require("../../../lib/assets/javascripts/twitter_cldr/core");
18
+ var data = require("../../../lib/assets/javascripts/twitter_cldr/" + locale);
19
+
20
+ if (options.clone) {
21
+ return TwitterCldr.clone(data);
22
+ } else {
23
+ TwitterCldr.set_data(data);
24
+ return TwitterCldr;
25
+ }
26
+ };
27
+
28
+ const checkDataIsolation = ({ class: klass, ctorParams, methods, staticMethods, loadOptions }) => {
29
+ methods = methods || {}
30
+ staticMethods = staticMethods || {}
31
+ ctorParams = ctorParams || []
32
+
33
+ describe(klass, () => {
34
+ const allMethods = [
35
+ ...(Object.entries(methods)).map(x => [false, ...x]),
36
+ ...(Object.entries(staticMethods)).map(x => [true, ...x]),
37
+ ]
38
+
39
+ for (let [static, name, { params, compare }] of allMethods) {
40
+ params = params || []
41
+ compare = compare || ((x) => x)
42
+
43
+ describe(`${static ? "." : "#"}${name}`, () => {
44
+ const twitterCldrs = locales.map((locale) => {
45
+ const params = [locale, loadOptions].filter((x) => x != null);
46
+ const TwitterCldr = load(...params);
47
+
48
+ return { locale, TwitterCldr };
49
+ });
50
+
51
+ const formatters = twitterCldrs.map(({ locale, TwitterCldr }) => {
52
+ const formatter = static ? TwitterCldr[klass] : new TwitterCldr[klass](...ctorParams)
53
+
54
+ return { locale, formatter };
55
+ });
56
+
57
+ const formatFns = formatters.map(({ locale, formatter }) => ({
58
+ locale,
59
+ format: formatter[name].bind(formatter),
60
+ }));
61
+
62
+ const results = formatFns.map(({ locale, format }) => ({
63
+ locale,
64
+ result: compare(format(...params)),
65
+ }));
66
+
67
+ it(`sanity check - result for same locale is equal`, () => {
68
+ const { formatter } = formatters[0];
69
+ const format = formatter[name].bind(formatter);
70
+
71
+ expect(compare(format(...params))).toBe(compare(format(...params)));
72
+ });
73
+
74
+ for (const [idx, { locale, result }] of results.entries()) {
75
+ const prevs = results.slice(0, idx);
76
+
77
+ if (!prevs.length) continue;
78
+
79
+ for (const prev of prevs) {
80
+ it(`result for "${locale}" differs from result for "${prev.locale}"`, () => {
81
+ expect(result).not.toBe(prev.result);
82
+ });
83
+ }
84
+ }
85
+ });
86
+ }
87
+ });
88
+ };
89
+
90
+ const tests = [
91
+ {
92
+ class: "DateTimeFormatter",
93
+ methods: {
94
+ format: { params: [date, { type: "full" }] },
95
+ weekday_local_stand_alone: { params: [date, "cc", 2] },
96
+ },
97
+ },
98
+ {
99
+ class: "Languages",
100
+ staticMethods: {
101
+ from_code: { params: ["en"] },
102
+ all: { params: [], compare: (x) => x.ja },
103
+ },
104
+ },
105
+ {
106
+ class: "RBNF",
107
+ methods: {
108
+ format: { params: [1, "SpelloutRules", "spellout-numbering"] },
109
+ },
110
+ }
111
+ ];
112
+
113
+ describe("data isolation", () => {
114
+ for (const loadOptions of [
115
+ undefined, // no options param supplied
116
+ {}, // empty options - defaults to clone=true
117
+ { clone: true }, // explicitly specify clone=true
118
+ ]) {
119
+ tests.map((x) => ({ ...x, loadOptions })).forEach(checkDataIsolation);
120
+ }
121
+ });
122
+
123
+ describe("clone behavior", () => {
124
+ const TwitterCldr = require("../../../lib/assets/javascripts/twitter_cldr/core");
125
+ const en = require("../../../lib/assets/javascripts/twitter_cldr/en");
126
+ const ja = require("../../../lib/assets/javascripts/twitter_cldr/ja");
127
+
128
+ beforeEach(() => {
129
+ TwitterCldr.set_data(undefined);
130
+ })
131
+
132
+ afterEach(() => {
133
+ TwitterCldr.set_data(undefined);
134
+ });
135
+
136
+ const locale = (clone) => clone.get_data().Settings.locale;
137
+
138
+ it("can be cloned from base that has no data", () => {
139
+ const clone = TwitterCldr.clone(en);
140
+
141
+ expect(locale(clone)).toBe("en");
142
+ expect(TwitterCldr.is_data_set()).toBe(false);
143
+ expect(clone.is_data_set()).toBe(true);
144
+ });
145
+
146
+ it("returns undefined for properties not present on `root`", () => {
147
+ TwitterCldr.set_data(en);
148
+ const clone = TwitterCldr.clone(en);
149
+
150
+ expect(TwitterCldr.data).toBe(undefined);
151
+ expect(clone.data).toBe(undefined);
152
+ });
153
+
154
+ it("doesn't affect data of the base TwitterCldr", () => {
155
+ TwitterCldr.set_data(ja);
156
+ TwitterCldr.clone(en);
157
+
158
+ expect(locale(TwitterCldr)).toBe("ja");
159
+ });
160
+
161
+
162
+ it("isn't affected by data of the base TwitterCldr", () => {
163
+ const clone = TwitterCldr.clone(en);
164
+ TwitterCldr.set_data(ja);
165
+
166
+ expect(locale(clone)).toBe("en");
167
+ });
168
+
169
+ it("can be cloned indefinitely", () => {
170
+ const cloneEn1 = TwitterCldr.clone(en);
171
+ const cloneEn2 = cloneEn1.clone(en);
172
+ const cloneJa = cloneEn2.clone(ja);
173
+
174
+ expect(locale(cloneEn1)).toBe("en");
175
+ expect(locale(cloneEn2)).toBe(locale(cloneEn1));
176
+ expect(locale(cloneJa)).toBe("ja");
177
+ });
178
+
179
+ it("throws if attempting to create a clone with no data", () => {
180
+ expect(() => TwitterCldr.clone()).toThrow();
181
+ expect(() => TwitterCldr.clone(undefined)).toThrow();
182
+ expect(() => TwitterCldr.clone(null)).toThrow();
183
+
184
+ expect(() => TwitterCldr.clone({})).not.toThrow();
185
+ });
186
+
187
+ describe("cloned version throws if attempting to set data", () => {
188
+ const clone = TwitterCldr.clone(en);
189
+
190
+ it("using `set_data`", () => {
191
+ expect(() => clone.set_data({})).toThrow();
192
+ });
193
+
194
+ it("using `data = `", () => {
195
+ expect(() => clone.data = {}).toThrow();
196
+ });
197
+ });
198
+ });
199
+
200
+ describe("load(..., false)", () => {
201
+ describe("continues to use global state", () => {
202
+ const results = locales.map((locale) => {
203
+ const TwitterCldr = load(locale, { clone: false });
204
+ return new TwitterCldr.DateTimeFormatter();
205
+ }).map((formatter) => formatter.format(date, { type: "full" }));
206
+
207
+ describe("DateTimeFormatter", () => {
208
+ it("#format", () => {
209
+ expect(new Set(results).size).toEqual(1);
210
+ });
211
+ });
212
+ });
213
+
214
+ describe("works in environments without `Proxy` support", () => {
215
+ const originalProxy = globalThis.Proxy;
216
+
217
+ beforeEach(() => {
218
+ globalThis.Proxy = undefined;
219
+ });
220
+
221
+ afterEach(() => {
222
+ globalThis.Proxy = originalProxy;
223
+ });
224
+
225
+ describe("DateTimeFormatter", () => {
226
+ it("#weekday_local_stand_alone", () => {
227
+ const TwitterCldr = load("en", { clone: false });
228
+ const formatter = new TwitterCldr.DateTimeFormatter();
229
+
230
+ expect(formatter.weekday_local_stand_alone(date, "cc", 2)).toEqual("Tue");
231
+ });
232
+ });
233
+ });
234
+ });
@@ -0,0 +1,77 @@
1
+ const TwitterCldr = require("../../../lib/assets/javascripts/twitter_cldr/core.js");
2
+
3
+ const testData = {
4
+ Long: {
5
+ "en": [
6
+ // edge cases
7
+ { raw: 999_499, precisions: ["999 thousand", "999.5 thousand"] },
8
+ { raw: 999_500, precisions: ["1 million", "999.5 thousand"] },
9
+ { raw: 1_000_000, precisions: ["1 million", "1.0 million"] },
10
+
11
+ // fractional
12
+ { raw: 999.49, precisions: ["999", "999.5"], default: "999.49" },
13
+ { raw: 999.5, precisions: ["1 thousand", "999.5"], default: "999.5" },
14
+
15
+ // negative
16
+ { raw: -1_000_000, precisions: ["-1,000,000"] },
17
+ { raw: -999_500, precisions: ["-999,500"] },
18
+ ],
19
+ "zh-cn": [
20
+ // edge cases
21
+ { raw: 9499, precisions: ["9千", "9.5千"] },
22
+ { raw: 9500, precisions: ["1万", "9.5千"] },
23
+ { raw: 10_000, precisions: ["1万", "1.0万"] },
24
+ ],
25
+ "es": [
26
+ // pluralization
27
+ { raw: 1e3, precisions: ["1 mil", "1,0 mil"] },
28
+ { raw: 2e3, precisions: ["2 mil", "2,0 mil"] },
29
+ { raw: 1e6, precisions: ["1 millón", "1,0 millón"] },
30
+ { raw: 2e6, precisions: ["2 millones", "2,0 millones"] },
31
+ { raw: 1e9, precisions: ["1 mil millones", "1,0 mil millones"] },
32
+
33
+ // fractional
34
+ { raw: 999.49, precisions: ["999", "999,5"], default: "999,49" },
35
+ { raw: 999.5, precisions: ["1 mil", "999,5"], default: "999,5" },
36
+
37
+ // negative
38
+ { raw: -1_000_000, precisions: ["-1.000.000"] },
39
+ { raw: -999_500, precisions: ["-999.500"] },
40
+ ],
41
+ },
42
+ Short: {
43
+ "en": [
44
+ // edge cases
45
+ { raw: 999_499, precisions: ["999K", "999.5K"] },
46
+ { raw: 999_500, precisions: ["1M", "999.5K"] },
47
+ { raw: 1_000_000, precisions: ["1M", "1.0M"] },
48
+ ],
49
+ },
50
+ };
51
+
52
+ for (const [kind, locales] of Object.entries(testData)) {
53
+ for (const [localeFileName, tests] of Object.entries(locales)) {
54
+ describe(`${kind}DecimalFormatter (${localeFileName})`, () => {
55
+ let formatter;
56
+
57
+ beforeEach(() => {
58
+ TwitterCldr.set_data(require(`../../../lib/assets/javascripts/twitter_cldr/${localeFileName}`));
59
+ formatter = new TwitterCldr[`${kind}DecimalFormatter`]();
60
+ });
61
+
62
+ describe("#format", () => {
63
+ for (const { raw, precisions, default: _default } of tests) {
64
+ it(`formats ${raw} with no options supplied`, () => {
65
+ expect(formatter.format(raw)).toEqual(_default ?? precisions[0]);
66
+ });
67
+
68
+ for (const [precision, expected] of precisions.entries()) {
69
+ it(`formats ${raw} to precision ${precision}`, () => {
70
+ expect(formatter.format(raw, { precision })).toEqual(expected);
71
+ });
72
+ }
73
+ }
74
+ });
75
+ });
76
+ }
77
+ }
@@ -14,12 +14,11 @@ Gem::Specification.new do |s|
14
14
  s.summary = "Text formatting using data from Unicode's Common Locale Data Repository (CLDR)."
15
15
 
16
16
  s.add_dependency 'json'
17
- s.add_dependency 'railties', '>= 3.0', '< 5.0'
17
+ s.add_dependency 'railties', '>= 3.0'
18
18
 
19
19
  s.add_development_dependency 'rake'
20
20
  s.add_development_dependency 'mustache', '~> 0.99.4'
21
21
  s.add_development_dependency 'ruby_parser', '~> 2.3.1'
22
- s.add_development_dependency 'therubyracer', '~> 0.12.0'
23
22
  s.add_development_dependency 'uglifier', '~> 1.2.4'
24
23
  s.add_development_dependency 'coffee-script', '~> 2.2.0'
25
24
  s.add_development_dependency 'coffee-script-source', '~> 1.8.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twitter_cldr_js
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cameron Dutro
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-26 00:00:00.000000000 Z
11
+ date: 2023-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -31,9 +31,6 @@ dependencies:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '3.0'
34
- - - "<"
35
- - !ruby/object:Gem::Version
36
- version: '5.0'
37
34
  type: :runtime
38
35
  prerelease: false
39
36
  version_requirements: !ruby/object:Gem::Requirement
@@ -41,9 +38,6 @@ dependencies:
41
38
  - - ">="
42
39
  - !ruby/object:Gem::Version
43
40
  version: '3.0'
44
- - - "<"
45
- - !ruby/object:Gem::Version
46
- version: '5.0'
47
41
  - !ruby/object:Gem::Dependency
48
42
  name: rake
49
43
  requirement: !ruby/object:Gem::Requirement
@@ -86,20 +80,6 @@ dependencies:
86
80
  - - "~>"
87
81
  - !ruby/object:Gem::Version
88
82
  version: 2.3.1
89
- - !ruby/object:Gem::Dependency
90
- name: therubyracer
91
- requirement: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - "~>"
94
- - !ruby/object:Gem::Version
95
- version: 0.12.0
96
- type: :development
97
- prerelease: false
98
- version_requirements: !ruby/object:Gem::Requirement
99
- requirements:
100
- - - "~>"
101
- - !ruby/object:Gem::Version
102
- version: 0.12.0
103
83
  - !ruby/object:Gem::Dependency
104
84
  name: uglifier
105
85
  requirement: !ruby/object:Gem::Requirement
@@ -257,6 +237,7 @@ files:
257
237
  - lib/twitter_cldr/js/mustache/implementation/calendars/additional_date_format_selector.coffee
258
238
  - lib/twitter_cldr/js/mustache/implementation/calendars/datetime.coffee
259
239
  - lib/twitter_cldr/js/mustache/implementation/calendars/timespan.coffee
240
+ - lib/twitter_cldr/js/mustache/implementation/clone/clone.coffee
260
241
  - lib/twitter_cldr/js/mustache/implementation/numbers/numbers.coffee
261
242
  - lib/twitter_cldr/js/mustache/implementation/numbers/rbnf/formatters.coffee
262
243
  - lib/twitter_cldr/js/mustache/implementation/numbers/rbnf/number_data_reader.coffee
@@ -327,6 +308,7 @@ files:
327
308
  - lib/twitter_cldr/js/renderers/data/shared/list_renderer.rb
328
309
  - lib/twitter_cldr/js/renderers/data_bundle.rb
329
310
  - lib/twitter_cldr/js/renderers/implementation/calendars.rb
311
+ - lib/twitter_cldr/js/renderers/implementation/clone.rb
330
312
  - lib/twitter_cldr/js/renderers/implementation/numbers.rb
331
313
  - lib/twitter_cldr/js/renderers/implementation/parsers.rb
332
314
  - lib/twitter_cldr/js/renderers/implementation/plurals.rb
@@ -352,6 +334,7 @@ files:
352
334
  - spec/js/calendars/datetime.spec.js
353
335
  - spec/js/calendars/timespan.ru.spec.js
354
336
  - spec/js/calendars/timespan.spec.js
337
+ - spec/js/clone/clone.spec.js
355
338
  - spec/js/numbers/abbreviated/abbreviated_number.spec.js
356
339
  - spec/js/numbers/abbreviated/long_decimal.ko.spec.js
357
340
  - spec/js/numbers/abbreviated/long_decimal.ru.spec.js
@@ -364,6 +347,7 @@ files:
364
347
  - spec/js/numbers/decimal.spec.js
365
348
  - spec/js/numbers/helpers/fraction.spec.js
366
349
  - spec/js/numbers/helpers/integer.spec.js
350
+ - spec/js/numbers/long_short_decimal.spec.js
367
351
  - spec/js/numbers/number.spec.js
368
352
  - spec/js/numbers/percent.spec.js
369
353
  - spec/js/numbers/rbnf.spec.js
@@ -416,7 +400,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
416
400
  - !ruby/object:Gem::Version
417
401
  version: '0'
418
402
  requirements: []
419
- rubygems_version: 3.0.4
403
+ rubygems_version: 3.1.6
420
404
  signing_key:
421
405
  specification_version: 4
422
406
  summary: Text formatting using data from Unicode's Common Locale Data Repository (CLDR).