twitter_cldr 2.0.2 → 2.1.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.
Files changed (128) hide show
  1. data/History.txt +9 -0
  2. data/NOTICE +29 -1
  3. data/README.md +4 -11
  4. data/lib/twitter_cldr/formatters/calendars/date_formatter.rb +6 -1
  5. data/lib/twitter_cldr/formatters/calendars/datetime_formatter.rb +10 -1
  6. data/lib/twitter_cldr/formatters/calendars/time_formatter.rb +6 -1
  7. data/lib/twitter_cldr/formatters/calendars/timespan_formatter.rb +12 -2
  8. data/lib/twitter_cldr/formatters/numbers/currency_formatter.rb +12 -3
  9. data/lib/twitter_cldr/formatters/numbers/number_formatter.rb +9 -1
  10. data/lib/twitter_cldr/formatters/plurals/rules.rb +8 -3
  11. data/lib/twitter_cldr/localized/localized_date.rb +13 -0
  12. data/lib/twitter_cldr/localized/localized_datetime.rb +20 -7
  13. data/lib/twitter_cldr/localized/localized_object.rb +1 -1
  14. data/lib/twitter_cldr/localized/localized_string.rb +14 -0
  15. data/lib/twitter_cldr/localized/localized_time.rb +12 -0
  16. data/lib/twitter_cldr/localized/localized_timespan.rb +1 -1
  17. data/lib/twitter_cldr/parsers/number_parser.rb +113 -0
  18. data/lib/twitter_cldr/parsers.rb +10 -0
  19. data/lib/twitter_cldr/resources/loader.rb +49 -2
  20. data/lib/twitter_cldr/resources/locales_resources_importer.rb +22 -2
  21. data/lib/twitter_cldr/shared/calendar.rb +95 -12
  22. data/lib/twitter_cldr/shared/currencies.rb +18 -15
  23. data/lib/twitter_cldr/shared/languages.rb +4 -4
  24. data/lib/twitter_cldr/shared/numbers.rb +1 -1
  25. data/lib/twitter_cldr/shared/territories.rb +63 -0
  26. data/lib/twitter_cldr/shared.rb +2 -1
  27. data/lib/twitter_cldr/tokenizers/base.rb +10 -15
  28. data/lib/twitter_cldr/tokenizers/calendars/additional_date_format_selector.rb +6 -1
  29. data/lib/twitter_cldr/tokenizers/calendars/datetime_tokenizer.rb +11 -2
  30. data/lib/twitter_cldr/tokenizers/calendars/timespan_tokenizer.rb +12 -9
  31. data/lib/twitter_cldr/tokenizers/numbers/number_tokenizer.rb +2 -2
  32. data/lib/twitter_cldr/utils/territories.rb +56 -0
  33. data/lib/twitter_cldr/utils.rb +4 -3
  34. data/lib/twitter_cldr/version.rb +1 -1
  35. data/lib/twitter_cldr.rb +60 -8
  36. data/resources/collation/tailoring/hr.yml +32 -0
  37. data/resources/collation/tailoring/is.yml +30 -0
  38. data/resources/collation/tries/hr.dump +0 -0
  39. data/resources/collation/tries/is.dump +0 -0
  40. data/resources/custom/locales/he/units.yml +150 -13
  41. data/resources/custom/locales/hr/units.yml +9 -0
  42. data/resources/locales/af/territories.yml +262 -0
  43. data/resources/locales/ar/territories.yml +262 -0
  44. data/resources/locales/be/territories.yml +239 -0
  45. data/resources/locales/bg/territories.yml +262 -0
  46. data/resources/locales/bn/territories.yml +262 -0
  47. data/resources/locales/ca/territories.yml +262 -0
  48. data/resources/locales/cs/territories.yml +262 -0
  49. data/resources/locales/cy/territories.yml +5 -0
  50. data/resources/locales/da/territories.yml +262 -0
  51. data/resources/locales/de/territories.yml +262 -0
  52. data/resources/locales/el/territories.yml +262 -0
  53. data/resources/locales/en/territories.yml +262 -0
  54. data/resources/locales/es/territories.yml +262 -0
  55. data/resources/locales/eu/territories.yml +262 -0
  56. data/resources/locales/fa/territories.yml +262 -0
  57. data/resources/locales/fi/territories.yml +262 -0
  58. data/resources/locales/fil/territories.yml +262 -0
  59. data/resources/locales/fr/territories.yml +262 -0
  60. data/resources/locales/ga/territories.yml +251 -0
  61. data/resources/locales/gl/territories.yml +262 -0
  62. data/resources/locales/he/territories.yml +262 -0
  63. data/resources/locales/hi/territories.yml +262 -0
  64. data/resources/locales/hr/calendars.yml +299 -0
  65. data/resources/locales/hr/currencies.yml +1490 -0
  66. data/resources/locales/hr/languages.yml +576 -0
  67. data/resources/locales/hr/layout.yml +4 -0
  68. data/resources/locales/hr/lists.yml +7 -0
  69. data/resources/locales/hr/numbers.yml +59 -0
  70. data/resources/locales/hr/plurals.yml +5 -0
  71. data/resources/locales/hr/territories.yml +262 -0
  72. data/resources/locales/hr/units.yml +164 -0
  73. data/resources/locales/hu/territories.yml +262 -0
  74. data/resources/locales/id/territories.yml +262 -0
  75. data/resources/locales/is/calendars.yml +243 -0
  76. data/resources/locales/is/currencies.yml +478 -0
  77. data/resources/locales/is/languages.yml +495 -0
  78. data/resources/locales/is/layout.yml +4 -0
  79. data/resources/locales/is/lists.yml +7 -0
  80. data/resources/locales/is/numbers.yml +57 -0
  81. data/resources/locales/is/plurals.yml +3 -0
  82. data/resources/locales/is/territories.yml +262 -0
  83. data/resources/locales/is/units.yml +108 -0
  84. data/resources/locales/it/territories.yml +262 -0
  85. data/resources/locales/ja/territories.yml +262 -0
  86. data/resources/locales/ko/territories.yml +262 -0
  87. data/resources/locales/lv/territories.yml +262 -0
  88. data/resources/locales/ms/territories.yml +262 -0
  89. data/resources/locales/nb/territories.yml +262 -0
  90. data/resources/locales/nl/territories.yml +262 -0
  91. data/resources/locales/pl/territories.yml +262 -0
  92. data/resources/locales/pt/territories.yml +262 -0
  93. data/resources/locales/ro/territories.yml +262 -0
  94. data/resources/locales/ru/territories.yml +262 -0
  95. data/resources/locales/sk/territories.yml +262 -0
  96. data/resources/locales/sq/territories.yml +159 -0
  97. data/resources/locales/sr/territories.yml +262 -0
  98. data/resources/locales/sv/territories.yml +262 -0
  99. data/resources/locales/ta/territories.yml +262 -0
  100. data/resources/locales/th/territories.yml +262 -0
  101. data/resources/locales/tr/territories.yml +262 -0
  102. data/resources/locales/uk/territories.yml +262 -0
  103. data/resources/locales/ur/territories.yml +262 -0
  104. data/resources/locales/vi/territories.yml +262 -0
  105. data/resources/locales/zh/territories.yml +262 -0
  106. data/resources/locales/zh-Hant/territories.yml +262 -0
  107. data/resources/shared/iso_currency_symbols.yml +475 -0
  108. data/spec/formatters/numbers/currency_formatter_spec.rb +11 -2
  109. data/spec/formatters/plurals/rules_spec.rb +1 -1
  110. data/spec/localized/localized_date_spec.rb +22 -24
  111. data/spec/localized/localized_object_spec.rb +1 -1
  112. data/spec/localized/localized_string_spec.rb +33 -0
  113. data/spec/localized/localized_symbol_spec.rb +1 -1
  114. data/spec/normalization/base_spec.rb +1 -0
  115. data/spec/parsers/number_parser_spec.rb +189 -0
  116. data/spec/readme_spec.rb +10 -11
  117. data/spec/resources/loader_spec.rb +75 -1
  118. data/spec/shared/calendar_spec.rb +123 -1
  119. data/spec/shared/currencies_spec.rb +20 -24
  120. data/spec/shared/languages_spec.rb +27 -27
  121. data/spec/shared/numbers_spec.rb +1 -1
  122. data/spec/shared/territories_spec.rb +120 -0
  123. data/spec/spec_helper.rb +19 -2
  124. data/spec/twitter_cldr_spec.rb +234 -9
  125. data/spec/utils/territories_spec.rb +16 -0
  126. data/spec/utils_spec.rb +1 -1
  127. metadata +131 -37
  128. data/resources/shared/currencies.yml +0 -448
data/History.txt CHANGED
@@ -1,3 +1,12 @@
1
+ == 2.1.0
2
+
3
+ * Significant performance improvements (memoization, resource preloading).
4
+ * Number parsing.
5
+ * Custom Hebrew units (thanks @yarons!)
6
+ * Icelandic and Croatian support.
7
+ * Global locale setter and fallbacks.
8
+ * Support for territories from CLDR.
9
+
1
10
  == 2.0.2
2
11
 
3
12
  * Added support for Vietnamese.
data/NOTICE CHANGED
@@ -151,4 +151,32 @@ OR PERFORMANCE OF THIS SOFTWARE.
151
151
 
152
152
  Except as contained in this notice, the name of a copyright holder shall not be
153
153
  used in advertising or otherwise to promote the sale, use or other dealings in
154
- this Software without prior written authorization of the copyright holder.
154
+ this Software without prior written authorization of the copyright holder.
155
+
156
+
157
+
158
+
159
+
160
+ The currencies data in twitter-cldr-rb has been adapted from the currencies gem.
161
+ Here's the license that accompanied that code:
162
+
163
+ Copyright (c) 2009 hexorx
164
+
165
+ Permission is hereby granted, free of charge, to any person obtaining
166
+ a copy of this software and associated documentation files (the
167
+ "Software"), to deal in the Software without restriction, including
168
+ without limitation the rights to use, copy, modify, merge, publish,
169
+ distribute, sublicense, and/or sell copies of the Software, and to
170
+ permit persons to whom the Software is furnished to do so, subject to
171
+ the following conditions:
172
+
173
+ The above copyright notice and this permission notice shall be
174
+ included in all copies or substantial portions of the Software.
175
+
176
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
177
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
178
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
179
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
180
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
181
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
182
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -42,7 +42,6 @@ TwitterCldr patches core Ruby objects like `Fixnum` and `Date` to make localizat
42
42
  # currencies, default USD
43
43
  1337.localize(:es).to_currency.to_s # 1.337,00 $
44
44
  1337.localize(:es).to_currency.to_s(:currency => "EUR") # 1.337,00 €
45
- 1337.localize(:es).to_currency.to_s(:currency => "Peru") # 1.337,00 S/.
46
45
 
47
46
  # percentages
48
47
  1337.localize(:es).to_percent.to_s # 1.337%
@@ -63,20 +62,14 @@ num.to_currency.to_s # ...etc
63
62
 
64
63
  #### More on Currencies
65
64
 
66
- If you're looking for a list of supported countries and currencies, use the `TwitterCldr::Shared::Currencies` class:
65
+ If you're looking for a list of supported currencies, use the `TwitterCldr::Shared::Currencies` class:
67
66
 
68
67
  ```ruby
69
- # all supported countries
70
- TwitterCldr::Shared::Currencies.countries # ["Lithuania", "Philippines", ... ]
71
-
72
68
  # all supported currency codes
73
69
  TwitterCldr::Shared::Currencies.currency_codes # ["LTL", "PHP" ... ]
74
70
 
75
- # data for a specific country
76
- TwitterCldr::Shared::Currencies.for_country("Canada") # { :currency => "Dollar", :symbol => "$", :code => "CAD" }
77
-
78
71
  # data for a specific currency code
79
- TwitterCldr::Shared::Currencies.for_code("CAD") # { :currency => "Dollar", :symbol => "$", :country => "Canada"}
72
+ TwitterCldr::Shared::Currencies.for_code("CAD") # { :currency => "Canadian dollar", :symbol => "$", :code_points => [36], :cldr_symbol => "CA$", :country => "Canada" }
80
73
  ```
81
74
 
82
75
  #### Short / Long Decimals
@@ -126,7 +119,7 @@ dt.to_short_s # ...etc
126
119
  Besides the default date formats, CLDR supports a number of additional ones. The list of available formats varys for each locale. To get a full list, use the `additional_formats_for` method:
127
120
 
128
121
  ```ruby
129
- # ["EEEEd", "Ed", "GGGGyMd", "H", "Hm", "Hms", "M", "MEd", "MMM", "MMMEEEEd", "MMMEd", ... ]
122
+ # ["EEEEd", "Ed", "GGGGyMd", "H", "Hm", "Hms", "M", "MEd", "MMM", "MMMEEEEd", "MMMEd", ... ]
130
123
  TwitterCldr::Formatters::DateTimeFormatter.additional_formats_for(:ja)
131
124
  ```
132
125
 
@@ -620,7 +613,7 @@ TwitterCldr.convert_locale(:msa) # :ms
620
613
  TwitterCldr.convert_locale(:ms) # :ms
621
614
  ```
622
615
 
623
- There are a few functions in TwitterCLDR that don't require a locale code, and instead use the default locale by calling `TwitterCldr.get_locale`. The `get_locale` function defers to `FastGettext.locale` when the FastGettext library is available, and falls back on :en (English) when it's not. (Twitter uses the FastGettext gem to retrieve translations efficiently in Ruby).
616
+ There are a few functions in TwitterCLDR that don't require a locale code, and instead use the default locale by calling `TwitterCldr.locale`. The `locale` function defers to `FastGettext.locale` when the FastGettext library is available, and falls back on :en (English) when it's not. (Twitter uses the FastGettext gem to retrieve translations efficiently in Ruby).
624
617
 
625
618
  ```ruby
626
619
  TwitterCldr.get_locale # will return :en
@@ -7,7 +7,12 @@ module TwitterCldr
7
7
  module Formatters
8
8
  class DateFormatter < DateTimeFormatter
9
9
  def initialize(options = {})
10
- @tokenizer = TwitterCldr::Tokenizers::DateTokenizer.new(:locale => extract_locale(options), :calendar_type => options[:calendar_type])
10
+ locale = extract_locale(options)
11
+ cache_key = TwitterCldr::Utils.compute_cache_key("date", locale, options[:calendar_type])
12
+ @tokenizer = tokenizer_cache[cache_key] ||= TwitterCldr::Tokenizers::DateTokenizer.new(
13
+ :locale => locale,
14
+ :calendar_type => options[:calendar_type]
15
+ )
11
16
  end
12
17
  end
13
18
  end
@@ -41,7 +41,12 @@ module TwitterCldr
41
41
  }
42
42
 
43
43
  def initialize(options = {})
44
- @tokenizer = TwitterCldr::Tokenizers::DateTimeTokenizer.new(:locale => extract_locale(options), :calendar_type => options[:calendar_type])
44
+ locale = extract_locale(options)
45
+ cache_key = TwitterCldr::Utils.compute_cache_key("datetime", locale, options[:calendar_type])
46
+ @tokenizer = tokenizer_cache[cache_key] ||= TwitterCldr::Tokenizers::DateTimeTokenizer.new(
47
+ :locale => locale,
48
+ :calendar_type => options[:calendar_type]
49
+ )
45
50
  end
46
51
 
47
52
  def result_for_token(token, index, date)
@@ -58,6 +63,10 @@ module TwitterCldr
58
63
 
59
64
  protected
60
65
 
66
+ def tokenizer_cache
67
+ @@tokenizer_cache ||= {}
68
+ end
69
+
61
70
  # there is incomplete era data in CLDR for certain locales like Hindi
62
71
  # fall back if that happens
63
72
  def era(date, pattern, length)
@@ -7,7 +7,12 @@ module TwitterCldr
7
7
  module Formatters
8
8
  class TimeFormatter < DateTimeFormatter
9
9
  def initialize(options = {})
10
- @tokenizer = TwitterCldr::Tokenizers::TimeTokenizer.new(:locale => extract_locale(options), :calendar_type => options[:calendar_type])
10
+ locale = extract_locale(options)
11
+ cache_key = TwitterCldr::Utils.compute_cache_key("time", locale, options[:calendar_type])
12
+ @tokenizer = tokenizer_cache[cache_key] ||= TwitterCldr::Tokenizers::TimeTokenizer.new(
13
+ :locale => locale,
14
+ :calendar_type => options[:calendar_type]
15
+ )
11
16
  end
12
17
  end
13
18
  end
@@ -21,14 +21,18 @@ module TwitterCldr
21
21
  }
22
22
 
23
23
  def initialize(options = {})
24
+ locale = extract_locale(options)
24
25
  @direction = options[:direction]
25
- @tokenizer = TwitterCldr::Tokenizers::TimespanTokenizer.new(:locale => extract_locale(options))
26
+ cache_key = TwitterCldr::Utils.compute_cache_key(locale)
27
+ @tokenizer = tokenizer_cache[cache_key] ||= TwitterCldr::Tokenizers::TimespanTokenizer.new(
28
+ :locale => locale
29
+ )
26
30
  end
27
31
 
28
32
  def format(seconds, fmt_options = {})
29
33
  options = fmt_options.dup
30
34
  options[:type] ||= DEFAULT_TYPE
31
- options[:direction] ||= @direction || (seconds < 0 ? :ago : :until)
35
+ options[:direction] ||= (seconds < 0 ? :ago : :until)
32
36
  options[:unit] ||= calculate_unit(seconds.abs, options)
33
37
 
34
38
  options[:number] = calculate_time(seconds.abs, options[:unit])
@@ -38,6 +42,12 @@ module TwitterCldr
38
42
  strings.join.gsub(/\{[0-9]\}/, options[:number].to_s)
39
43
  end
40
44
 
45
+ protected
46
+
47
+ def tokenizer_cache
48
+ @@tokenizer_cache ||= {}
49
+ end
50
+
41
51
  def calculate_unit(seconds, unit_options = {})
42
52
  options = unit_options.dup
43
53
  options[:approximate] = false if options[:approximate].nil?
@@ -12,17 +12,26 @@ module TwitterCldr
12
12
  def format(number, options = {})
13
13
  options[:currency] ||= "USD"
14
14
  currency = TwitterCldr::Shared::Currencies.for_code(options[:currency])
15
- currency ||= TwitterCldr::Shared::Currencies.for_country(options[:currency])
16
- currency ||= { :symbol => options[:currency], :currency => options[:currency] }
15
+ currency ||= {
16
+ :currency => options[:currency],
17
+ :symbol => options[:currency],
18
+ :cldr_symbol => options[:currency]
19
+ }
20
+
21
+ # overwrite with explicit symbol if given
22
+ currency[:symbol] = options[:symbol] if options[:symbol]
17
23
 
18
24
  digits_and_rounding = resource(options[:currency])
19
25
  options[:precision] ||= digits_and_rounding[:digits]
20
26
  options[:rounding] ||= digits_and_rounding[:rounding]
21
27
 
22
- super(number, options).gsub('¤', (currency[:symbol] || currency[:currency].to_s))
28
+ symbol = options[:use_cldr_symbol] ? currency[:cldr_symbol] : currency[:symbol]
29
+ symbol ||= currency[:currency].to_s
30
+ super(number, options).gsub('¤', symbol)
23
31
  end
24
32
 
25
33
  private
34
+
26
35
  def resource(code)
27
36
  @resource ||= TwitterCldr.get_resource(:shared, :currency_digits_and_rounding)
28
37
  @resource[code.to_sym] || @resource[:DEFAULT]
@@ -11,7 +11,11 @@ module TwitterCldr
11
11
  DEFAULT_SYMBOLS = { :group => ',', :decimal => '.', :plus_sign => '+', :minus_sign => '-' }
12
12
 
13
13
  def initialize(options = {})
14
- @tokenizer = TwitterCldr::Tokenizers::NumberTokenizer.new(:locale => extract_locale(options))
14
+ locale = extract_locale(options)
15
+ cache_key = TwitterCldr::Utils.compute_cache_key(locale)
16
+ @tokenizer = tokenizer_cache[cache_key] ||= TwitterCldr::Tokenizers::NumberTokenizer.new(
17
+ :locale => locale
18
+ )
15
19
  @symbols = DEFAULT_SYMBOLS.merge(tokenizer.symbols)
16
20
  end
17
21
 
@@ -28,6 +32,10 @@ module TwitterCldr
28
32
 
29
33
  protected
30
34
 
35
+ def tokenizer_cache
36
+ @@tokenizer_cache ||= {}
37
+ end
38
+
31
39
  def transform_number(number)
32
40
  number # noop for base class
33
41
  end
@@ -11,7 +11,7 @@ module TwitterCldr
11
11
  class << self
12
12
 
13
13
  def all
14
- all_for(TwitterCldr.get_locale)
14
+ all_for(TwitterCldr.locale)
15
15
  end
16
16
 
17
17
  def all_for(locale)
@@ -20,7 +20,7 @@ module TwitterCldr
20
20
  nil
21
21
  end
22
22
 
23
- def rule_for(number, locale = TwitterCldr.get_locale)
23
+ def rule_for(number, locale = TwitterCldr.locale)
24
24
  get_resource(locale)[:rule].call(number)
25
25
  rescue
26
26
  :other
@@ -30,7 +30,12 @@ module TwitterCldr
30
30
 
31
31
  def get_resource(locale)
32
32
  locale = TwitterCldr.convert_locale(locale)
33
- eval(TwitterCldr.get_locale_resource(locale, :plurals)[locale])[locale][:i18n][:plural]
33
+ cache_key = TwitterCldr::Utils.compute_cache_key(locale)
34
+ locale_cache[cache_key] ||= eval(TwitterCldr.get_locale_resource(locale, :plurals)[locale])[locale][:i18n][:plural]
35
+ end
36
+
37
+ def locale_cache
38
+ @locale_cache ||= {}
34
39
  end
35
40
 
36
41
  end
@@ -12,6 +12,19 @@ module TwitterCldr
12
12
  LocalizedDateTime.new(DateTime.parse("#{@base_obj.strftime("%Y-%m-%d")}T#{time_obj.strftime("%H:%M:%S%z")}"), @locale, :calendar_type => @calendar_type)
13
13
  end
14
14
 
15
+ def to_time(base = Time.now)
16
+ time = Time.gm(
17
+ @base_obj.year,
18
+ @base_obj.month,
19
+ @base_obj.day,
20
+ base.hour,
21
+ base.min,
22
+ base.sec
23
+ )
24
+
25
+ LocalizedTime.new(time, @locale, :calendar_type => @calendar_type)
26
+ end
27
+
15
28
  protected
16
29
 
17
30
  def formatter_const
@@ -27,15 +27,15 @@ module TwitterCldr
27
27
  end
28
28
 
29
29
  def ago(options = {})
30
- base_time = options[:base_time] || Time.now
31
- seconds = self.to_time.base_obj.to_i - base_time.to_i
30
+ base_time = (options[:base_time] || Time.now).gmtime
31
+ seconds = self.to_time(base_time).base_obj.gmtime.to_i - base_time.to_i
32
32
  raise ArgumentError.new('Start date is after end date. Consider using "until" function.') if seconds > 0
33
33
  TwitterCldr::Localized::LocalizedTimespan.new(seconds, options.merge(:locale => @locale))
34
34
  end
35
35
 
36
36
  def until(options = {})
37
- base_time = options[:base_time] || Time.now
38
- seconds = self.to_time.base_obj.to_i - base_time.to_i
37
+ base_time = (options[:base_time] || Time.now).gmtime
38
+ seconds = self.to_time(base_time).base_obj.gmtime.to_i - base_time.to_i
39
39
  raise ArgumentError.new('End date is before start date. Consider using "ago" function.') if seconds < 0
40
40
  TwitterCldr::Localized::LocalizedTimespan.new(seconds, options.merge(:locale => @locale))
41
41
  end
@@ -49,11 +49,24 @@ module TwitterCldr
49
49
  end
50
50
 
51
51
  def to_date
52
- LocalizedDate.new(Date.parse(@base_obj.strftime("%Y-%m-%dT%H:%M:%S%z")), @locale, :calendar_type => @calendar_type)
52
+ date = Date.new(@base_obj.year, @base_obj.month, @base_obj.day)
53
+ LocalizedDate.new(date, @locale, :calendar_type => @calendar_type)
53
54
  end
54
55
 
55
- def to_time
56
- LocalizedTime.new(Time.parse(@base_obj.strftime("%Y-%m-%dT%H:%M:%S%z")), @locale, :calendar_type => @calendar_type)
56
+ def to_time(base = Time.now)
57
+ utc_dt = @base_obj.new_offset(0)
58
+
59
+ time = Time.gm(
60
+ utc_dt.year,
61
+ utc_dt.month,
62
+ utc_dt.day,
63
+ utc_dt.hour,
64
+ utc_dt.min,
65
+ utc_dt.sec,
66
+ utc_dt.sec_fraction * (RUBY_VERSION < '1.9' ? 86400000000 : 1000000)
67
+ )
68
+
69
+ LocalizedTime.new(time, @locale, :calendar_type => @calendar_type)
57
70
  end
58
71
 
59
72
  protected
@@ -27,7 +27,7 @@ module TwitterCldr
27
27
 
28
28
  def self.localize(klass)
29
29
  klass.class_eval <<-LOCALIZE, __FILE__, __LINE__ + 1
30
- def localize(locale = TwitterCldr.get_locale, options = {})
30
+ def localize(locale = TwitterCldr.locale, options = {})
31
31
  #{self}.new(self, locale, options)
32
32
  end
33
33
  LOCALIZE
@@ -36,6 +36,20 @@ module TwitterCldr
36
36
  @base_obj.dup
37
37
  end
38
38
 
39
+ def to_i(options = {})
40
+ to_f(options).to_i
41
+ end
42
+
43
+ def to_f(options = {})
44
+ if TwitterCldr::Parsers::NumberParser.is_numeric?(@base_obj)
45
+ TwitterCldr::Parsers::NumberParser.new(@locale).try_parse(@base_obj, options) do |result|
46
+ result || @base_obj.to_f
47
+ end
48
+ else
49
+ @base_obj.to_f
50
+ end
51
+ end
52
+
39
53
  def size
40
54
  code_points.size
41
55
  end
@@ -12,6 +12,18 @@ module TwitterCldr
12
12
  LocalizedDateTime.new(DateTime.parse("#{date_obj.strftime("%Y-%m-%d")}T#{@base_obj.strftime("%H:%M:%S%z")}"), @locale, :calendar_type => @calendar_type)
13
13
  end
14
14
 
15
+ def to_time(base_time = Time.now)
16
+ self
17
+ end
18
+
19
+ def gmtime
20
+ LocalizedTime.new(@base_obj.gmtime, @locale, :calendar_type => @calendar_type)
21
+ end
22
+
23
+ def localtime
24
+ LocalizedTime.new(@base_obj.localtime, @locale, :calendar_type => @calendar_type)
25
+ end
26
+
15
27
  protected
16
28
 
17
29
  def formatter_const
@@ -8,7 +8,7 @@ module TwitterCldr
8
8
 
9
9
  class LocalizedTimespan < LocalizedObject
10
10
  def initialize(seconds, options = {})
11
- super(seconds, options[:locale] || TwitterCldr.get_locale, options)
11
+ super(seconds, options[:locale] || TwitterCldr.locale, options)
12
12
  end
13
13
 
14
14
  def to_s(options = {})
@@ -0,0 +1,113 @@
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 Parsers
8
+
9
+ class InvalidNumberError < StandardError; end
10
+
11
+ class NumberParser
12
+
13
+ SEPARATOR_CHARS = ['.', ',', ' '].map do |char|
14
+ char == ' ' ? '\s' : Regexp.escape(char)
15
+ end.join
16
+
17
+ def initialize(locale = TwitterCldr.locale)
18
+ @locale = locale
19
+ end
20
+
21
+ def parse(number_text, options = {})
22
+ options[:strict] = true unless options.include?(:strict)
23
+ group, decimal = separators(options[:strict])
24
+ tokens = tokenize(number_text, group, decimal)
25
+
26
+ num_list, punct_list = tokens.partition { |t| t[:type] == :numeric }
27
+ raise InvalidNumberError unless punct_valid?(punct_list)
28
+ raise InvalidNumberError unless tokens.last && tokens.last[:type] == :numeric
29
+
30
+ if punct_list.last && punct_list.last[:type] == :decimal
31
+ result = num_list[0..-2].map { |num| num[:value] }.join.to_i
32
+ result + num_list.last[:value].to_i / (10.0 ** num_list.last[:value].size)
33
+ else
34
+ num_list.map { |num| num[:value] }.join.to_i
35
+ end
36
+ end
37
+
38
+ def try_parse(number_text, default = nil, options = {})
39
+ begin
40
+ result = parse(number_text, options)
41
+ rescue InvalidNumberError
42
+ result = nil
43
+ end
44
+
45
+ if block_given?
46
+ yield(result)
47
+ else
48
+ result || default
49
+ end
50
+ end
51
+
52
+ def valid?(number_text, options = {})
53
+ parse(number_text, options)
54
+ true
55
+ rescue
56
+ false
57
+ end
58
+
59
+ def self.is_numeric?(text, separators = SEPARATOR_CHARS)
60
+ !!(text =~ /\A[0-9#{separators}]+\Z/)
61
+ end
62
+
63
+ protected
64
+
65
+ def punct_valid?(punct_list)
66
+ # all group, allowed one decimal at end
67
+ punct_list.each_with_index.all? do |punct, index|
68
+ punct[:type] == :group || (index == (punct_list.size - 1) && punct[:type] == :decimal)
69
+ end
70
+ end
71
+
72
+ def separators(strict = false)
73
+ group = strict ? group_separator : SEPARATOR_CHARS
74
+ decimal = strict ? decimal_separator : SEPARATOR_CHARS
75
+ [group, decimal]
76
+ end
77
+
78
+ def tokenize(number_text, group, decimal)
79
+ match_data = number_text.scan(/([\d]*)([#{group}]{0,1})([\d]*)([#{decimal}]{0,1})([\d]*)/)
80
+ (match_data.flatten || []).reject(&:empty?).map { |match| identify(match, group, decimal) }
81
+ end
82
+
83
+ def identify(text, group, decimal)
84
+ result = { :value => text }
85
+ result[:type] = if self.class.is_numeric?(result[:value], "")
86
+ :numeric
87
+ else
88
+ if result[:value] =~ /[#{group}]/
89
+ :group
90
+ elsif result[:value] =~ /[#{decimal}]/
91
+ :decimal
92
+ else
93
+ nil
94
+ end
95
+ end
96
+ result
97
+ end
98
+
99
+ def decimal_separator
100
+ @decimal_separator ||= Regexp.escape(resource[:symbols][:decimal])
101
+ end
102
+
103
+ def group_separator
104
+ @group_separator ||= Regexp.escape(resource[:symbols][:group])
105
+ end
106
+
107
+ def resource
108
+ @resource ||= TwitterCldr.get_locale_resource(@locale, "numbers")[@locale][:numbers]
109
+ end
110
+
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,10 @@
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 Parsers
8
+ autoload :NumberParser, 'twitter_cldr/parsers/number_parser'
9
+ end
10
+ end
@@ -13,11 +13,58 @@ module TwitterCldr
13
13
  end
14
14
 
15
15
  def get_locale_resource(locale, resource_name)
16
- get_resource(:locales, TwitterCldr.convert_locale(locale), resource_name)
16
+ get_resource(*locale_resource_path(locale, resource_name))
17
+ end
18
+
19
+ def resource_loaded?(*path)
20
+ resources_cache.include?(resource_file_path(path))
21
+ end
22
+
23
+ def locale_resource_loaded?(locale, resource_name)
24
+ resource_loaded?(*locale_resource_path(locale, resource_name))
25
+ end
26
+
27
+ def resource_types
28
+ @resource_types ||= Dir.glob(File.join(RESOURCES_DIR, 'locales/en', '*')).map do |file|
29
+ File.basename(file).chomp(File.extname(file)).to_sym
30
+ end
31
+ end
32
+
33
+ def preload_resources_for_locale(locale, *resources)
34
+ if resources.size > 0
35
+ resources = resource_types if resources.first == :all
36
+ resources.each { |res| get_locale_resource(locale, res) }
37
+ end
38
+ nil
39
+ end
40
+
41
+ def preload_resource_for_locales(resource, *locales)
42
+ locales.each do |locale|
43
+ preload_resources_for_locale(locale, resource)
44
+ end
45
+ nil
46
+ end
47
+
48
+ def preload_resources_for_all_locales(*resources)
49
+ TwitterCldr.supported_locales.each do |locale|
50
+ preload_resources_for_locale(locale, *resources)
51
+ end
52
+ nil
53
+ end
54
+
55
+ def preload_all_resources
56
+ TwitterCldr.supported_locales.each do |locale|
57
+ preload_resources_for_locale(locale, :all)
58
+ end
59
+ nil
17
60
  end
18
61
 
19
62
  private
20
63
 
64
+ def locale_resource_path(locale, resource_name)
65
+ [:locales, TwitterCldr.convert_locale(locale), resource_name]
66
+ end
67
+
21
68
  def resources_cache
22
69
  @resources_cache ||= Hash.new { |hash, path| hash[path] = load_resource(path) }
23
70
  end
@@ -54,4 +101,4 @@ module TwitterCldr
54
101
  end
55
102
 
56
103
  end
57
- end
104
+ end
@@ -12,7 +12,7 @@ module TwitterCldr
12
12
 
13
13
  class LocalesResourcesImporter
14
14
 
15
- COMPONENTS = %w[calendars languages numbers units plurals lists layout currencies]
15
+ COMPONENTS = %w[calendars languages numbers units plurals lists layout currencies territories]
16
16
 
17
17
  # Arguments:
18
18
  #
@@ -49,6 +49,7 @@ module TwitterCldr
49
49
  Cldr::Export.export(:locales => TwitterCldr.supported_locales, :components => COMPONENTS, :target => File.join(@output_path, 'locales')) do |component, locale, path|
50
50
  add_buddhist_calendar(component, locale, path)
51
51
  process_plurals(component, locale, path)
52
+ downcase_territory_codes(component, locale, path)
52
53
  deep_symbolize(component, locale, path)
53
54
  end
54
55
 
@@ -68,6 +69,25 @@ module TwitterCldr
68
69
  end
69
70
  end
70
71
 
72
+ # CLDR stores territory codes uppercase. For consistency with how we
73
+ # handle territory codes in methods relating to phone and postal codes,
74
+ # we downcase them here.
75
+ #
76
+ # (There is also some trickery relating to three-digit UN "area codes"
77
+ # used by CLDR; see comment of Utils::Territories::deep_normalize_territory_code_keys.)
78
+ def downcase_territory_codes(component, locale, path)
79
+ return unless component == 'Territories'
80
+
81
+ data = YAML.load(File.read(path))
82
+ data.keys.each do |l|
83
+ data[l] = TwitterCldr::Utils::Territories.deep_normalize_territory_code_keys(data[l])
84
+ end
85
+
86
+ File.open(path, 'w:utf-8') do |output|
87
+ output.write(YAML.dump(data))
88
+ end
89
+ end
90
+
71
91
  def process_plurals(component, locale, path)
72
92
  return unless component == 'Plurals'
73
93
 
@@ -106,4 +126,4 @@ module TwitterCldr
106
126
  end
107
127
 
108
128
  end
109
- end
129
+ end