Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 390
- Log:
Initial import of Canvass, a donations-based poll application.
- Author:
- rool
- Date:
- Mon Mar 21 14:58:04 +0000 2011
- Size:
- 5853 Bytes
1 | module TranslatableColumns |
2 | |
3 | # A config class for TranslatableColumns |
4 | # Stores configuration options, so global settings can be changed. |
5 | # These options are available: |
6 | # |
7 | # <ul> |
8 | # <li>+full_locale+, when *true* it uses the full locale in |
9 | # the column names (e.g. _title_en_us_), when *false* (default!) it |
10 | # uses only the language part (e.g. _title_en_)</li> |
11 | # <li>+use_default+, when *false* it will not try to find a value |
12 | # from other languages, when the request locale is nil. (default = true) |
13 | # </li> |
14 | # </ul> |
15 | # |
16 | # To change the config globally, create an initializer or add to your |
17 | # environtment-file: |
18 | # |
19 | # ActiveRecord::Base.translatable_columns_config.full_locale = false |
20 | # ActiveRecord::Base.translatable_columns_config.set_default = true |
21 | # |
22 | class Config#nodoc: |
23 | attr_accessor :full_locale, :use_default |
24 | |
25 | def initialize |
26 | set_defaults |
27 | end |
28 | |
29 | def set_defaults |
30 | @full_locale = false |
31 | @use_default = true |
32 | end |
33 | |
34 | end |
35 | |
36 | module ClassMethods |
37 | |
38 | # Accessor for the config, which makes sure you read from the same config |
39 | # every time. See +Config+ |
40 | def translatable_columns_config |
41 | @@translatable_columns_config ||= TranslatableColumns::Config.new |
42 | end |
43 | |
44 | |
45 | # Used to define which columns can be translatable |
46 | # |
47 | # class Topic < ActiveRecord::Base |
48 | # translatable_columns :title, :body, :use_default => false |
49 | # end |
50 | # |
51 | # The use of the option +:use_default+ is optional and used to overwrite |
52 | # the global config. See +Config+ for that. |
53 | def translatable_columns(*columns) |
54 | |
55 | options = columns.extract_options! |
56 | options[:use_default] = translatable_columns_config.use_default unless options.has_key?(:use_default) |
57 | |
58 | columns.each do |column| |
59 | define_translated_setter(column) |
60 | if options[:use_default] |
61 | define_translated_getter_with_defaults(column) |
62 | else |
63 | define_translated_getter_without_defaults(column) |
64 | end |
65 | end |
66 | |
67 | end |
68 | |
69 | # Defines the method needed to get the translated value, defaults |
70 | # to values from other columns when needed. |
71 | # If a column doesn't exist, it'll default to the I18n.default_locale. |
72 | def define_translated_getter_with_defaults(column) |
73 | define_method column do |
74 | self.send(self.class.column_translated(column)) or |
75 | self.send(self.class.column_name_localized(column, I18n.default_locale)) or |
76 | self.find_translated_value_for(column) |
77 | end |
78 | end |
79 | |
80 | # Defines the method needed to get the translated value, but |
81 | # doesn't look beyond its own value, even if it's nil. It will still |
82 | # look for the column belonging to I18n.default_locale if the locale |
83 | # doesn't have it's own column. |
84 | def define_translated_getter_without_defaults(column) |
85 | define_method column do |
86 | self.send(self.class.column_translated(column)) |
87 | end |
88 | end |
89 | |
90 | # Defines the method needed to fill the proper column. Will set the |
91 | # default column if no column is found for this locale. |
92 | def define_translated_setter(column) |
93 | define_method :"#{column}=" do |value| |
94 | self.send(:"#{self.class.column_translated(column)}=", value) |
95 | end |
96 | end |
97 | |
98 | # Returns the column associated with the locale specified. |
99 | # |
100 | # column_translated("name") # => "name_en" |
101 | def column_translated(name, locale = I18n.locale) |
102 | translated_column_exists?(name, locale) ? column_name_localized(name, locale) : column_name_localized(name, I18n.default_locale) |
103 | end |
104 | |
105 | # Finds all localized columns belonging to the given column. |
106 | # |
107 | # available_translatable_columns_of("name") # => [ "name_en", "name_nl" ] |
108 | # |
109 | # TODO It will also find non localized columns, if they start with the same name as the translatable name. |
110 | def available_translatable_columns_of(name) |
111 | self.column_names.select { |column| column =~ /^#{name}_\w{2,}$/ } |
112 | end |
113 | |
114 | # Returns true if a column exist for the supplied attribute name. |
115 | def translated_column_exists?(name, locale = I18n.locale) |
116 | available_translatable_columns_of(name).include?(column_name_localized(name, locale)) |
117 | end |
118 | |
119 | # Makes the column |
120 | def column_name_localized(name, locale = I18n.locale) |
121 | "#{name}_#{column_locale(locale)}" |
122 | end |
123 | |
124 | # Returns the proper column name |
125 | def column_locale(locale = I18n.locale) |
126 | locale = locale.to_s.gsub( /[^A-Za-z_-]/, '' ) |
127 | translatable_columns_config.full_locale ? locale.to_s.gsub('-','_').downcase : locale.to_s.split('-').first |
128 | end |
129 | |
130 | # Validates presence of at least one of the localized columns. |
131 | # Usage is the same as +validates_presence_of+ |
132 | # |
133 | # Translation scope of the error message is: |
134 | # |
135 | # # activerecord.errors.models.topic.attributes.title.must_have_translation |
136 | # # activerecord.errors.models.topic.must_have_translation |
137 | # # activerecord.errors.messages.must_have_translation |
138 | # # activerecord.errors.messages.blank |
139 | def validates_translation_of(*attr_names) |
140 | configuration = { :on => :save } |
141 | configuration.update(attr_names.extract_options!) |
142 | send(validation_method(configuration[:on]), configuration) do |record| |
143 | attr_names.each do |attr_name| |
144 | if record.find_translated_value_for(attr_name).blank? |
145 | custom_message = configuration[:message] || :must_have_translation |
146 | record.errors.add(attr_name, :blank, :default => custom_message) |
147 | end |
148 | end |
149 | end |
150 | end |
151 | |
152 | end |
153 | |
154 | module InstanceMethods |
155 | |
156 | # Finds a value for a translatable column. Just iterates, returns first value found. |
157 | def find_translated_value_for(name) |
158 | self.class.available_translatable_columns_of(name).each do |column| |
159 | return send(column) unless send(column).blank? |
160 | end |
161 | nil |
162 | end |
163 | end |
164 | |
165 | end |