delocalize 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 [name of plugin creator]
1
+ Copyright (c) 2009 Clemens Kofler
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -0,0 +1,115 @@
1
+ delocalize
2
+ ==========
3
+
4
+ delocalize provides localized date/time and number parsing functionality for Rails.
5
+
6
+ Installation
7
+ ---------------
8
+
9
+ You can use delocalize either as a gem (preferred) or as a Rails plugin.
10
+
11
+ To use the gem version, put the following gem requirement in your `environment.rb`:
12
+
13
+ config.gem "delocalize", :source => 'http://gemcutter.org'
14
+
15
+ To install it as a plugin, fire up your terminal, go to your Rails app and type:
16
+
17
+ $ ruby script/plugin install git://github.com/clemens/delocalize.git
18
+
19
+
20
+ What does it do? And how do I use it?
21
+ ---------------------------------------------------
22
+
23
+ Delocalize, just as the name suggest, does pretty much the opposite of localize.
24
+
25
+ In the grey past, if you want your users to be able to input localized data, such as dates and numbers, you had to manually override attribute accessors:
26
+
27
+ def price=(price)
28
+ write_attribute(:price, price.gsub(',', '.'))
29
+ end
30
+
31
+ delocalize does this under the covers -- all you need is your regular translation data (as YAML or Ruby file) where you need Rails' standard translations:
32
+
33
+ de:
34
+ number:
35
+ format:
36
+ separator: ','
37
+ delimiter: '.'
38
+ date:
39
+ input:
40
+ formats: [:default, :long, :short] # <- this and ...
41
+
42
+ formats:
43
+ default: "%d.%m.%Y"
44
+ short: "%e. %b"
45
+ long: "%e. %B %Y"
46
+ only_day: "%e"
47
+
48
+ day_names: [Sonntag, Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag]
49
+ abbr_day_names: [So, Mo, Di, Mi, Do, Fr, Sa]
50
+ month_names: [~, Januar, Februar, März, April, Mai, Juni, Juli, August, September, Oktober, November, Dezember]
51
+ abbr_month_names: [~, Jan, Feb, Mär, Apr, Mai, Jun, Jul, Aug, Sep, Okt, Nov, Dez]
52
+ order: [ :day, :month, :year ]
53
+
54
+ time:
55
+ input:
56
+ formats: [:long, :medium, :short, :default, :time] # <- ... this are the only non-standard keys
57
+ formats:
58
+ default: "%A, %e. %B %Y, %H:%M Uhr"
59
+ short: "%e. %B, %H:%M Uhr"
60
+ long: "%A, %e. %B %Y, %H:%M Uhr"
61
+ time: "%H:%M"
62
+
63
+ am: "vormittags"
64
+ pm: "nachmittags"
65
+
66
+ For dates and times, you have to define input formats which are taken from the actual formats. The important thing here is to define input formats sorted by descending complexity; in other words: the format which contains the most (preferably non-numeric) information should be first in the list because it can produce the most reliable match. Exception: If you think there most complex format is not the one that most users will input, you can put the most-used in front so you save unnecessary iterations.
67
+
68
+ Careful with formats containing only numbers: It's very hard to produce reliable matches if you provide multiple strictly numeric formats!
69
+
70
+ delocalize then overrides `to_input_field_tag` in ActionView's `InstanceTag` so you can use localized text fields:
71
+
72
+ <% form_for @product do |f| %>
73
+ <%= f.text_field :name %>
74
+ <%= f.text_field :released_on %>
75
+ <%= f.text_field :price %>
76
+ <% end %>
77
+
78
+ In this example, a user can enter the release date and the price just like he's used to in his language, for example:
79
+
80
+ > Name: "Couch"
81
+ > Released on: "12. Oktober 2009"
82
+ > Price: "2.999,90"
83
+
84
+ When saved, ActiveRecord automatically converts these to a regular Ruby date and number.
85
+
86
+ Edit forms then also show localized dates/numbers. By default, dates and times are localized using the format named :default in your locale file. So with the above locale file, dates would use `%d.%m.%Y` and times would use `%A, %e. %B %Y, %H:%M Uhr`. Numbers are also formatted using your locale's thousands delimiter and decimal separator.
87
+
88
+ You can also customize the output using some options:
89
+
90
+ The price should always show two decimal digits and we don't need the delimiter:
91
+ <%= f.text_field :price, :precision => 2, :delimiter => '' %>
92
+
93
+ The `released_on` date should be shown in the `:full` format:
94
+ <%= f.text_field :released_on, :format => :full %>
95
+
96
+ Since `I18n.localize` supports localizing `strftime` strings, we can also do this:
97
+ <%= f.text_field :released_on, :format => "%B %Y" %>
98
+
99
+ ### Note
100
+
101
+ delocalize is most definitely not enterprise-ready! ;-)
102
+ Or as Yaroslav says: Contains small pieces. Not good for children of age 3 and less. Not enterprise-ready.
103
+
104
+ ### TODO
105
+
106
+ * Improve test coverage
107
+ * Separate Ruby/Rails stuff to make it usable outside Rails
108
+ * Verify correct behavior with time zones
109
+ * Decide on other ActionView hacks (e.g. `text_field_tag`)
110
+ * Implement AM/PM support
111
+ * Cleanup, cleanup, cleanup ...
112
+
113
+ Copyright (c) 2009-2010 Clemens Kofler &lt;clemens@railway.at&gt;
114
+ http://www.railway.at/
115
+ Released under the MIT license
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.5
1
+ 0.1.6
@@ -8,7 +8,8 @@ module Delocalize
8
8
  def parse(value)
9
9
  if value.is_a?(String)
10
10
  separator = I18n.t(:'number.format.separator')
11
- value = value.gsub(/[^0-9\-#{separator}]/, '').gsub(separator, '.')
11
+ delimiter = I18n.t(:'number.format.delimiter')
12
+ value = value.gsub(delimiter, '').gsub(separator, '.')
12
13
  end
13
14
  value
14
15
  end
@@ -22,7 +22,13 @@ ActionView::Helpers::InstanceTag.class_eval do
22
22
  # integers don't need a precision
23
23
  opts.merge!(:precision => 0) if column.type == :integer
24
24
 
25
- options[:value] = number_with_precision(value, opts)
25
+ hidden_for_integer = field_type == 'hidden' && column.type == :integer
26
+
27
+ # the number will be formatted only if it has no errors
28
+ if object.respond_to?(:errors) && !object.errors.invalid?(method_name)
29
+ # we don't format integer hidden fields because this breaks nested_attributes
30
+ options[:value] = number_with_precision(value, opts) unless hidden_for_integer
31
+ end
26
32
  elsif column.date? || column.time?
27
33
  options[:value] = value ? I18n.l(value, :format => options.delete(:format)) : nil
28
34
  end
@@ -45,4 +51,4 @@ end
45
51
  # end
46
52
  # original_text_field_tag(name, value, options)
47
53
  # end
48
- # end
54
+ # end
@@ -16,8 +16,6 @@ ActiveRecord::Base.class_eval do
16
16
  value = Date.parse_localized(value)
17
17
  elsif column.time?
18
18
  value = Time.parse_localized(value)
19
- elsif column.number?
20
- value = column.type_cast(convert_number_column_value_with_localization(value))
21
19
  end
22
20
  end
23
21
  write_attribute_without_localization(attr_name, value)
@@ -38,6 +36,24 @@ ActiveRecord::Base.class_eval do
38
36
  evaluate_attribute_method attr_name, method_body, "#{attr_name}="
39
37
  end
40
38
 
39
+ # overriding to convert numbers with localization
40
+ # this method belongs to Dirty module
41
+ def field_changed?(attr, old, value)
42
+ if column = column_for_attribute(attr)
43
+ if column.number? && column.null && (old.nil? || old == 0) && value.blank?
44
+ # For nullable numeric columns, NULL gets stored in database for blank (i.e. '') values.
45
+ # Hence we don't record it as a change if the value changes from nil to ''.
46
+ # If an old value of 0 is set to '' we want this to get changed to nil as otherwise it'll
47
+ # be typecast back to 0 (''.to_i => 0)
48
+ value = nil
49
+ else
50
+ value = column.type_cast(convert_number_column_value_with_localization(value))
51
+ end
52
+ end
53
+
54
+ old != value
55
+ end
56
+
41
57
  def convert_number_column_value_with_localization(value)
42
58
  value = convert_number_column_value_without_localization(value)
43
59
  value = Numeric.parse_localized(value) if I18n.delocalization_enabled?
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  require File.dirname(__FILE__) + '/test_helper'
2
4
 
3
5
  class DelocalizeActiveRecordTest < ActiveRecord::TestCase
@@ -32,7 +34,7 @@ class DelocalizeActiveRecordTest < ActiveRecord::TestCase
32
34
  end
33
35
 
34
36
  test "delocalizes localized datetime with year" do
35
- time = Time.local(2009, 3, 1, 12, 0, 0)
37
+ time = Time.gm(2009, 3, 1, 11, 0, 0).in_time_zone
36
38
 
37
39
  @product.published_at = 'Sonntag, 1. März 2009, 12:00 Uhr'
38
40
  assert_equal time, @product.published_at
@@ -42,7 +44,7 @@ class DelocalizeActiveRecordTest < ActiveRecord::TestCase
42
44
  end
43
45
 
44
46
  test "delocalizes localized datetime without year" do
45
- time = Time.local(Date.today.year, 3, 1, 12, 0, 0)
47
+ time = Time.gm(Date.today.year, 3, 1, 11, 0, 0).in_time_zone
46
48
 
47
49
  @product.published_at = '1. März, 12:00 Uhr'
48
50
  assert_equal time, @product.published_at
@@ -50,7 +52,7 @@ class DelocalizeActiveRecordTest < ActiveRecord::TestCase
50
52
 
51
53
  test "delocalizes localized time" do
52
54
  now = Time.current
53
- time = Time.local(now.year, now.month, now.day, 9, 0, 0)
55
+ time = Time.gm(now.year, now.month, now.day, 7, 0, 0).in_time_zone
54
56
  @product.cant_think_of_a_sensible_time_field = '09:00 Uhr'
55
57
  assert_equal time, @product.cant_think_of_a_sensible_time_field
56
58
  end
@@ -61,12 +63,12 @@ class DelocalizeActiveRecordTest < ActiveRecord::TestCase
61
63
  @product.released_on = '2009/10/19'
62
64
  assert_equal date, @product.released_on
63
65
 
64
- time = Time.local(2009, 3, 1, 12, 0, 0)
66
+ time = Time.gm(2009, 3, 1, 11, 0, 0).in_time_zone
65
67
  @product.published_at = '2009/03/01 12:00'
66
68
  assert_equal time, @product.published_at
67
69
 
68
70
  now = Time.current
69
- time = Time.local(now.year, now.month, now.day, 9, 0, 0)
71
+ time = Time.gm(now.year, now.month, now.day, 7, 0, 0).in_time_zone
70
72
  @product.cant_think_of_a_sensible_time_field = '09:00'
71
73
  assert_equal time, @product.cant_think_of_a_sensible_time_field
72
74
  end
@@ -131,6 +133,12 @@ class DelocalizeActiveRecordTest < ActiveRecord::TestCase
131
133
  @product.weight = "10,34"
132
134
  assert @product.weight_changed?
133
135
  end
136
+
137
+ test "should remember the value before type cast" do
138
+ @product.price = "asd"
139
+ assert_equal @product.price, 0
140
+ assert_equal @product.price_before_type_cast, "asd"
141
+ end
134
142
  end
135
143
 
136
144
  class DelocalizeActionViewTest < ActionView::TestCase
@@ -195,6 +203,12 @@ class DelocalizeActionViewTest < ActionView::TestCase
195
203
  text_field(:product, :cant_think_of_a_sensible_time_field, :format => :time)
196
204
  end
197
205
 
206
+ test "integer hidden fields shouldn't be formatted" do
207
+ @product.times_sold = 1000
208
+ assert_dom_equal '<input id="product_times_sold" name="product[times_sold]" type="hidden" value="1000" />',
209
+ hidden_field(:product, :times_sold)
210
+ end
211
+
198
212
  test "doesn't raise an exception when object is nil" do
199
213
  assert_nothing_raised {
200
214
  text_field(:not_here, :a_text_field)
@@ -216,6 +230,13 @@ class DelocalizeActionViewTest < ActionView::TestCase
216
230
  text_field(:product, :price, :value => "1.499,90")
217
231
  end
218
232
 
233
+ test "don't convert type if field has errors" do
234
+ @product = ProductWithValidation.new(:price => 'this is not a number')
235
+ @product.valid?
236
+ assert_dom_equal '<div class="fieldWithErrors"><input id="product_price" name="product[price]" size="30" type="text" value="this is not a number" /></div>',
237
+ text_field(:product, :price)
238
+ end
239
+
219
240
  test "doesn't raise an exception when object isn't an ActiveReccord" do
220
241
  @product = NonArProduct.new
221
242
  assert_nothing_raised {
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  ENV["RAILS_ENV"] = "test"
2
4
  #require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment")
3
5
  require File.expand_path(File.dirname(__FILE__) + "/rails_app/config/environment")
@@ -59,6 +61,11 @@ end
59
61
  class Product < ActiveRecord::Base
60
62
  end
61
63
 
64
+ class ProductWithValidation < Product
65
+ validates_numericality_of :price
66
+ validates_presence_of :price
67
+ end
68
+
62
69
  config = YAML.load_file(File.dirname(__FILE__) + '/database.yml')
63
70
  ActiveRecord::Base.establish_connection(config['test'])
64
71
 
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delocalize
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 6
9
+ version: 0.1.6
5
10
  platform: ruby
6
11
  authors:
7
12
  - Clemens Kofler
@@ -9,7 +14,7 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-01-17 00:00:00 +01:00
17
+ date: 2010-05-13 00:00:00 +02:00
13
18
  default_executable:
14
19
  dependencies: []
15
20
 
@@ -20,10 +25,9 @@ executables: []
20
25
  extensions: []
21
26
 
22
27
  extra_rdoc_files:
23
- - README
28
+ - README.markdown
24
29
  files:
25
30
  - MIT-LICENSE
26
- - README
27
31
  - Rakefile
28
32
  - VERSION
29
33
  - init.rb
@@ -43,6 +47,7 @@ files:
43
47
  - tasks/distribution.rb
44
48
  - tasks/documentation.rb
45
49
  - tasks/testing.rb
50
+ - README.markdown
46
51
  has_rdoc: true
47
52
  homepage: http://github.com/clemens/delocalize
48
53
  licenses: []
@@ -56,18 +61,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
56
61
  requirements:
57
62
  - - ">="
58
63
  - !ruby/object:Gem::Version
64
+ segments:
65
+ - 0
59
66
  version: "0"
60
- version:
61
67
  required_rubygems_version: !ruby/object:Gem::Requirement
62
68
  requirements:
63
69
  - - ">="
64
70
  - !ruby/object:Gem::Version
71
+ segments:
72
+ - 0
65
73
  version: "0"
66
- version:
67
74
  requirements: []
68
75
 
69
76
  rubyforge_project:
70
- rubygems_version: 1.3.5
77
+ rubygems_version: 1.3.6
71
78
  signing_key:
72
79
  specification_version: 3
73
80
  summary: Localized date/time and number parsing
data/README DELETED
@@ -1,117 +0,0 @@
1
- delocalize
2
- ==========
3
-
4
- delocalize provides localized date/time and number parsing functionality for Rails.
5
-
6
- Installation
7
- ============
8
-
9
- You can use delocalize either as a gem (preferred) or as a Rails plugin.
10
-
11
- To use the gem version, put the following gem requirement in your environment.rb:
12
-
13
- config.gem "delocalize", :source => 'http://gemcutter.org'
14
-
15
- To install it as a plugin, fire up your terminal, go to your Rails app and type:
16
-
17
- $ ruby script/plugin install git://github.com/clemens/delocalize.git
18
-
19
-
20
- What does it do? And how do I use it?
21
- =====================================
22
-
23
- Delocalize, just as the name suggest, does pretty much the opposite of localize.
24
-
25
- In the grey past, ff you want your users to be able to input localized data, such as dates and numbers, you had to manually override attribute accessors:
26
-
27
- def price=(price)
28
- write_attribute(:price, price.gsub(',', '.'))
29
- end
30
-
31
- delocalize does this under the covers - all you need is your regular translation data (as YAML or Ruby file) where you need Rails' standard translations:
32
-
33
- de:
34
- number:
35
- format:
36
- separator: ','
37
- delimiter: '.'
38
- date:
39
- input:
40
- formats: [:default, :long, :short] # <- this and ...
41
-
42
- formats:
43
- default: "%d.%m.%Y"
44
- short: "%e. %b"
45
- long: "%e. %B %Y"
46
- only_day: "%e"
47
-
48
- day_names: [Sonntag, Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag]
49
- abbr_day_names: [So, Mo, Di, Mi, Do, Fr, Sa]
50
- month_names: [~, Januar, Februar, März, April, Mai, Juni, Juli, August, September, Oktober, November, Dezember]
51
- abbr_month_names: [~, Jan, Feb, Mär, Apr, Mai, Jun, Jul, Aug, Sep, Okt, Nov, Dez]
52
- order: [ :day, :month, :year ]
53
-
54
- time:
55
- input:
56
- formats: [:long, :medium, :short, :default, :time] # <- ... this are the only non-standard keys
57
- formats:
58
- default: "%A, %e. %B %Y, %H:%M Uhr"
59
- short: "%e. %B, %H:%M Uhr"
60
- long: "%A, %e. %B %Y, %H:%M Uhr"
61
- time: "%H:%M"
62
-
63
- am: "vormittags"
64
- pm: "nachmittags"
65
-
66
- For dates and times, you have to define input formats which are taken from the actual formats. The important thing here is to define input formats sorted by descending complexity - in other words: The format which contains the most (preferably non-numeric) information should be first in the list because it can produce the most reliable match. Exception: If you think there most complex format is not the one that most users will input, you can put the most-used in front so you save unnecessary iterations.
67
-
68
- Careful with formats containing only numbers: It's very hard to produce reliable matches if you provide multiple strictly numeric formats!
69
-
70
- delocalize then overrides to_input_field_tag in ActionView's InstanceTag so you can use localized text fields:
71
-
72
- <% form_for @product do |f| %>
73
- <%= f.text_field :name %>
74
- <%= f.text_field :released_on %>
75
- <%= f.text_field :price %>
76
- <% end %>
77
-
78
- In this example, a user can enter the release date and the price just like he's used to in his language, for example:
79
-
80
- Name: "Couch"
81
- Released on: "12. Oktober 2009"
82
- Price: "2.999,90"
83
-
84
- When saved, ActiveRecord automatically converts these to a regular Ruby date and number.
85
-
86
- Edit forms then also show localized dates/numbers. By default, dates and times are localized using the format named :default in your locale file. So with the above locale file, dates would use "%d.%m.%Y" and times would use "%A, %e. %B %Y, %H:%M Uhr". Numbers are also formatted using your locale's thousands delimiter and decimal separator.
87
-
88
- You can also customize the output using some options:
89
-
90
- The price should always show two decimal digits and we don't need the delimiter:
91
- <%= f.text_field :price, :precision => 2, :delimiter => '' %>
92
-
93
- The released_on date should be shown in the :full format:
94
- <%= f.text_field :released_on, :format => :full %>
95
-
96
- Since I18n.localize supportes localizing strftime strings, we can also do this:
97
- <%= f.text_field :released_on, :format => "%B %Y" %>
98
-
99
- Note
100
- ====
101
-
102
- delocalize is most definitely not enterprise-ready! ;-)
103
- Or as Yaroslav says: Contains small pieces. Not good for children of age 3 and less. Not enterprise-ready.
104
-
105
- TODO
106
- ====
107
-
108
- * Improve test coverage
109
- * Separate Ruby/Rails stuff to make it usable outside Rails
110
- * Verify correct behavior with time zones
111
- * Decide on other ActionView hacks (e.g. text_field_tag)
112
- * Implement AM/PM support
113
- * Cleanup, cleanup, cleanup ...
114
-
115
- Copyright (c) 2009 Clemens Kofler <clemens@railway.at>
116
- www.railway.at
117
- Released under the MIT license