twitter_cldr 2.0.2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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