r18n-core 0.2.3 → 0.3

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 (47) hide show
  1. data/README.rdoc +157 -35
  2. data/base/cs.yml +34 -0
  3. data/base/de.yml +24 -0
  4. data/base/en.yml +24 -0
  5. data/base/fr.yml +24 -0
  6. data/base/pl.yml +24 -0
  7. data/base/ru.yml +30 -0
  8. data/lib/r18n-core/filters.rb +245 -0
  9. data/lib/r18n-core/i18n.rb +57 -40
  10. data/lib/r18n-core/locale.rb +116 -19
  11. data/lib/r18n-core/translated.rb +186 -0
  12. data/lib/r18n-core/translation.rb +33 -73
  13. data/lib/r18n-core/unsupported_locale.rb +27 -9
  14. data/lib/r18n-core/utils.rb +49 -0
  15. data/lib/r18n-core/version.rb +1 -1
  16. data/lib/r18n-core.rb +3 -15
  17. data/locales/cs.rb +23 -0
  18. data/locales/cs.yml +26 -0
  19. data/locales/de.yml +3 -8
  20. data/locales/en-us.rb +8 -0
  21. data/locales/en-us.yml +9 -0
  22. data/locales/en.rb +26 -0
  23. data/locales/en.yml +3 -8
  24. data/locales/eo.yml +3 -8
  25. data/locales/fr.rb +14 -0
  26. data/locales/fr.yml +3 -8
  27. data/locales/kk.yml +3 -8
  28. data/locales/pl.yml +4 -11
  29. data/locales/ru.yml +3 -8
  30. data/spec/filters_spec.rb +167 -0
  31. data/spec/i18n_spec.rb +61 -16
  32. data/spec/locale_spec.rb +46 -19
  33. data/spec/locales/cs_spec.rb +22 -0
  34. data/spec/locales/en-us_spec.rb +14 -0
  35. data/spec/locales/en_spec.rb +14 -0
  36. data/spec/locales/fr_spec.rb +10 -0
  37. data/spec/locales/pl_spec.rb +17 -17
  38. data/spec/locales/ru_spec.rb +2 -2
  39. data/spec/r18n_spec.rb +7 -3
  40. data/spec/spec_helper.rb +2 -0
  41. data/spec/translated_spec.rb +108 -0
  42. data/spec/translation_spec.rb +24 -56
  43. data/spec/translations/extension/{no_TR.yml → no-tr.yml} +0 -0
  44. data/spec/translations/general/en.yml +15 -2
  45. data/spec/translations/general/{no_LC.yml → no-lc.yml} +0 -0
  46. metadata +46 -31
  47. data/locales/en_US.yml +0 -14
data/README.rdoc CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  R18n is a i18n tool to translate your Ruby application in several languages.
4
4
 
5
- Use <tt>merb_r18n</tt> to localize Merb Web application and
5
+ Use <tt>sinatra-r18n</tt> or teamon’s +merb_i18n+ to localize Web applications and
6
6
  <tt>r18n-desktop</tt> to localize desktop application.
7
7
 
8
8
  == Features
@@ -15,36 +15,14 @@ Use <tt>merb_r18n</tt> to localize Merb Web application and
15
15
  month and week days name and give other locale information.
16
16
  * It has translation for commons words, like “OK”, “Cancel”, etc.
17
17
  * It storage translation in rich YAML format. You can put procedures and
18
- pluralization (“1 comment”, “5 comments”) in your translation.
18
+ pluralization (“1 comment”, “5 comments”) or create you own filters.
19
19
  * It can translate Web and desktop applications.
20
20
 
21
21
  == Usage
22
22
 
23
- === Locale
24
- All supported locales are storage in R18n gem at +locales+ dir. If you want to
25
- add your locale, please write me to andrey@sitnik.ru.
26
-
27
- To get information about locale create R18n::Locale instance:
28
-
29
- locale = R18n::Locale.load('en')
30
-
31
- You can get from locale:
32
- * Locale title and RFC 3066 code:
33
-
34
- locale['title'] #=> "English"
35
- locale['code'] #=> "en"
36
-
37
- * Language direction (left to right, or right to left for Arabic and Hebrew):
38
-
39
- locale['direction'] #=> "ltr"
40
-
41
- * Week start day ("sunday" or "monday")
42
-
43
- locale['week']['start'] #=> "sunday"
44
-
45
23
  === Translation
46
24
  Translation files use YAML format and has name like en.yml (English) or
47
- en_US.yml (USA English dialect) with language/country code (RFC 3066).
25
+ en-us.yml (USA English dialect) with language/country code (RFC 3066).
48
26
 
49
27
  In translation you can use:
50
28
  * Strings
@@ -58,8 +36,9 @@ In translation you can use:
58
36
  0: No robots
59
37
  1: One robot
60
38
  n: %1 robots
61
- * Procedures
62
- sum: !!proc |x, y| x + y
39
+ * Filters
40
+ filtered: !!custom_type
41
+ This content will be processed by filter
63
42
 
64
43
  To get translated string use method with key name or square brackets [] for
65
44
  keys, which is same with Object methods (+class+, +inspect+, etc):
@@ -105,6 +84,77 @@ See <tt>base/</tt> in dir in gem.
105
84
  i18n.cancel #=> "Cancel"
106
85
  i18n.delete #=> "Delete"
107
86
 
87
+ === Filters
88
+ You can also add you own filter for translations: escape HTML entries, convert
89
+ from Markdown syntax, etc.
90
+
91
+ R18n::Filters.add('custom_type', :filter_name) do |content, config, replace|
92
+ content.gsub(' ', replace)
93
+ end
94
+ R18n::Filters.add('custom_type') do |content, config, replace|
95
+ content + '!'
96
+ end
97
+
98
+ i18n.filtered('_') #=> "This_content_will_be_processed_by_filter!"
99
+
100
+ You can also add global filters for all translated strings:
101
+
102
+ R18n::Filters.add(String, :capitalize_ruby) do |content, config|
103
+ content.gsub(/ruby/i) { |i| i.swapcase }
104
+ end
105
+
106
+ ==== HTML Escape
107
+ R18n contain 2 filters to escape HTML entries: by YAML type and global. If you
108
+ need to escape HTML in some translations, just set <tt>!!escape</tt> YAML type:
109
+
110
+ greater: !!escape
111
+ 1 < 2 is true
112
+
113
+ i18n.greater #=> "1 &lt; 2 is true"
114
+
115
+ If you develop web application and want to escape HTML in all translations, just
116
+ activate global escape filter:
117
+
118
+ R18n::Filters.on(:global_escape_html)
119
+
120
+ If you enable global HTML escape, you may use <tt>!!html</tt> YAML type to
121
+ disable escaping in some special value.
122
+
123
+ warning: !!html
124
+ <b>Warning</b>
125
+
126
+ R18n::Filters.on(:global_escape_html)
127
+ i18n.warning #=> "<b>Warning</b>"
128
+
129
+ ==== Markdown
130
+ To use Markdown in your translations you must install maruku gem:
131
+
132
+ hi: !!markdown
133
+ **Hi**, people!
134
+
135
+ i18n.hi #=> "<p><strong>Hi</strong>, people!</p>"
136
+
137
+
138
+ ==== Textile
139
+ To use Textile in your translations you must install RedCloth gem:
140
+
141
+ alarm: !!textile
142
+ It will delete _all_ users!
143
+
144
+ i18n.alarm #=> "<p>It will delete <em>all</em> users!</p>"
145
+
146
+ ==== Lambdas
147
+ You can use lambdas in your translations.
148
+
149
+ sum: !!proc |x, y| x + y
150
+
151
+ i18n.sum(1, 2) #=> 3
152
+
153
+ If it isn’t secure in your application (for example, user can change
154
+ translations), you can disable it:
155
+
156
+ R18n::Filters.off(:procedure)
157
+
108
158
  === Localization
109
159
  You can print number and float according to the rules of the user locale:
110
160
 
@@ -116,18 +166,90 @@ non-break thin spaces (for locale, which use it as digit separator).
116
166
  You can translate months and week days names in Time, Date and DateTime by
117
167
  +strftime+ method:
118
168
 
119
- i18n.l Time.now, "%B" #=> "September"
169
+ i18n.l Time.now, '%B' #=> "September"
170
+
171
+ R18n has some time formats for locales: <tt>:human</tt>, <tt>:full</tt> and
172
+ <tt>:standard</tt> (by default):
173
+
174
+ i18n.l Time.now, :human #=> "now"
175
+ i18n.l Time.now, :full #=> "August 9th, 2009 21:47"
176
+ i18n.l Time.now #=> "08/09/2009 21:41"
177
+ i18n.l Time.now.to_date #=> "08/09/2009"
178
+
179
+ === Model
180
+ You can add i18n support to any classes, including ORM models:
181
+
182
+ require 'r18n-core/translated'
183
+
184
+ class Product
185
+ include DataMapper::Resource
186
+ property :title_ru, String
187
+ property :title_en, String
188
+
189
+ include R18n::Translated
190
+ translations :title
191
+ end
192
+
193
+ # For example, user know only Russian
194
+
195
+ # Set value to English (default) title
196
+ product.title_en = "Anthrax"
197
+ product.title #=> "Anthrax"
198
+
199
+ # Set value to title on user locale (Russian)
200
+ product.title = "Сибирская язва"
201
+ product.title #=> "Сибирская язва"
202
+
203
+ product.title_en #=> "Anthrax"
204
+ product.title_ru #=> "Сибирская язва"
205
+
206
+ See R18n::Translated for documentation.
120
207
 
121
- R18n has some time formats for locales: <tt>:month</tt>, <tt>:time</tt>,
122
- <tt>:date</tt>, <tt>:short_data</tt>, <tt>:long_data</tt>, <tt>:datetime</tt>,
123
- <tt>:short_datetime</tt> and <tt>:long_datetime</tt>:
208
+ === Locale
209
+ All supported locales are storage in R18n gem at +locales+ dir. If you want to
210
+ add your locale, please write me to andrey@sitnik.ru.
124
211
 
125
- i18n.l Time.now, :date #=> "09/21/2008"
212
+ To get information about locale create R18n::Locale instance:
213
+
214
+ locale = R18n::Locale.load('en')
126
215
 
127
- By default +strftime+ will be use <tt>:datetime</tt> format for Time and
128
- DateTime and <tt>:date</tt> for Date:
216
+ You can get from locale:
217
+ * Locale title and RFC 3066 code:
218
+
219
+ locale.title #=> "English"
220
+ locale.code #=> "en"
221
+
222
+ * Language direction (left to right, or right to left for Arabic and Hebrew):
223
+
224
+ locale.ltr? #=> true
225
+
226
+ * Week start day ("sunday" or "monday"):
227
+
228
+ locale['week']['start'] #=> "sunday"
129
229
 
130
- i18n.l Time.now #=> "Sun Sep 21 19:50:04 GMT 2008"
230
+ == Add locale
231
+ If R18n hasn’t locale file for your language, please add it. It’s very simple:
232
+ * Create in locales/ file _code_.yml for your language and describe locale.
233
+ Just copy from another locale and change different values.
234
+ * If your language is dialect or base on another (as American English (en-US)
235
+ base on English (en)) write <tt>include: _base_locale_</tt> and similar
236
+ values can be deleted.
237
+ * If in your country people mostly know another language (like in exUSSR
238
+ countries people know Russian), write
239
+ <tt>sublocales: [_another_locale_, en]</tt>. Else write only:
240
+ <tt>sublocales: [en]</tt>. For dialect put base locale to +sublocales+ too.
241
+ * Create in base/ file _code_.yml for your language and translate base messages.
242
+ Just copy file from language, which you know, and rewrite values.
243
+ * If you language need some special logic (for example, different pluralization
244
+ or time formatters) you can change Locale class. Create in locales/ file
245
+ _code_.rb and write R18n::Locales::_Code_ class, which must extend
246
+ R18n::Locale.
247
+ * Push files by GitHub (http://github.com/ai/r18n) or just write e-mail with
248
+ this files to me (andrey@sitnik.ru).
249
+
250
+ _Code_ is RFC 3066 code for your language (for example, “en” for English and
251
+ “fr_CA” for Canadian French). You can send to my e-mail any questions (on
252
+ http://sitnik.ru you find another contact addresses).
131
253
 
132
254
  == License
133
255
  R18n is licensed under the GNU Lesser General Public License version 3.
data/base/cs.yml ADDED
@@ -0,0 +1,34 @@
1
+ ok: OK
2
+ save: Uložit
3
+ cancel: Zrušit
4
+ yes: Ano
5
+ no: Ne
6
+ exit: Konec
7
+ delete: Smazat
8
+
9
+ human_time:
10
+ after_days: !!pl
11
+ 1: za %1 den
12
+ 2: za %1 dny
13
+ n: za %1 dnů
14
+ tomorrow: zítra
15
+ after_hours: !!pl
16
+ 1: za %1 hodinu
17
+ 2: za %1 hodiny
18
+ n: za %1 hodin
19
+ after_minutes: !!pl
20
+ 1: za %1 minutu
21
+ 2: za %1 minuty
22
+ n: za %1 minut
23
+ now: teď
24
+ today: dnes
25
+ minutes_ago: !!pl
26
+ 1: před %1 minutou
27
+ n: před %1 minutami
28
+ hours_ago: !!pl
29
+ 1: před %1 hodinou
30
+ n: před %1 hodinami
31
+ yesterday: včera
32
+ days_ago: !!pl
33
+ 1: před %1 dnem
34
+ n: před %1 dny
data/base/de.yml CHANGED
@@ -5,3 +5,27 @@ yes: Ja
5
5
  no: Nein
6
6
  exit: Ausgang
7
7
  delete: Löschen
8
+
9
+ human_time:
10
+ after_days: !!pl
11
+ 1: nach %1 Tag
12
+ n: nach %1 Tagen
13
+ tomorrow: morgen
14
+ after_hours: !!pl
15
+ 1: nach %1 Stunde
16
+ n: nach %1 Stunden
17
+ after_minutes: !!pl
18
+ 1: nach %1 Minute
19
+ n: nach %1 Minuten
20
+ now: jetzt
21
+ today: heute
22
+ minutes_ago: !!pl
23
+ 1: %1 Minute vor
24
+ n: %1 Minuten vor
25
+ hours_ago: !!pl
26
+ 1: %1 Stunde vor
27
+ n: %1 Stunden vor
28
+ yesterday: gestern
29
+ days_ago: !!pl
30
+ 1: %1 Tag vor
31
+ n: %1 Tagen vor
data/base/en.yml CHANGED
@@ -5,3 +5,27 @@ yes: Yes
5
5
  no: No
6
6
  exit: Exit
7
7
  delete: Delete
8
+
9
+ human_time:
10
+ after_days: !!pl
11
+ 1: after %1 day
12
+ n: after %1 days
13
+ tomorrow: tomorrow
14
+ after_hours: !!pl
15
+ 1: after %1 hour
16
+ n: after %1 hours
17
+ after_minutes: !!pl
18
+ 1: after %1 minute
19
+ n: after %1 minutes
20
+ now: now
21
+ today: today
22
+ minutes_ago: !!pl
23
+ 1: %1 minute ago
24
+ n: %1 minutes ago
25
+ hours_ago: !!pl
26
+ 1: %1 hour ago
27
+ n: %1 hours ago
28
+ yesterday: yesterday
29
+ days_ago: !!pl
30
+ 1: %1 day ago
31
+ n: %1 days ago
data/base/fr.yml CHANGED
@@ -5,3 +5,27 @@ yes: Oui
5
5
  no: Non
6
6
  exit: Sortie
7
7
  delete: Supprimer
8
+
9
+ human_time:
10
+ after_days: !!pl
11
+ 1: dans une jour
12
+ n: dans %1 jours
13
+ tomorrow: demain
14
+ after_hours: !!pl
15
+ 1: dans une heure
16
+ n: dans %1 heures
17
+ after_minutes: !!pl
18
+ 1: dans une minute
19
+ n: dans %1 minutes
20
+ now: maintenant
21
+ today: "aujourd'hui"
22
+ minutes_ago: !!pl
23
+ 1: il ya une minute
24
+ n: il ya %1 minutes
25
+ hours_ago: !!pl
26
+ 1: il ya une heure
27
+ n: il ya %1 heures
28
+ yesterday: hier
29
+ days_ago: !!pl
30
+ 1: il ya une jour
31
+ n: il ya %1 jours
data/base/pl.yml CHANGED
@@ -5,3 +5,27 @@ yes: Tak
5
5
  no: Nie
6
6
  exit: Wyjście
7
7
  delete: Usuń
8
+
9
+ human_time:
10
+ after_days: !!pl
11
+ 1: po %1 dniu
12
+ n: po %1 dniach
13
+ tomorrow: jutro
14
+ after_hours: !!pl
15
+ 1: po %1 godzinie
16
+ n: po %1 godzinach
17
+ after_minutes: !!pl
18
+ 1: po %1 minucie
19
+ n: po %1 minutach
20
+ now: teraz
21
+ today: dzisiaj
22
+ minutes_ago: !!pl
23
+ 1: %1 minutę temu
24
+ n: %1 minut temu
25
+ hours_ago: !!pl
26
+ 1: %1 godzinę temu
27
+ n: %1 godzin temu
28
+ yesterday: wczoraj
29
+ days_ago: !!pl
30
+ 1: %1 dzień temu
31
+ n: %1 dni temu
data/base/ru.yml CHANGED
@@ -5,3 +5,33 @@ yes: Да
5
5
  no: Нет
6
6
  exit: Выход
7
7
  delete: Удалить
8
+
9
+ human_time:
10
+ after_days: !!pl
11
+ 1: через %1 день
12
+ 2: через %1 дня
13
+ n: через %1 дней
14
+ tomorrow: завтра
15
+ after_hours: !!pl
16
+ 1: через %1 час
17
+ 2: через %1 часа
18
+ n: через %1 часов
19
+ after_minutes: !!pl
20
+ 1: через %1 минуту
21
+ 2: через %1 минуты
22
+ n: через %1 минут
23
+ now: сейчас
24
+ today: сегодня
25
+ minutes_ago: !!pl
26
+ 1: %1 минуту назад
27
+ 2: %1 минуты назад
28
+ n: %1 минут назад
29
+ hours_ago: !!pl
30
+ 1: %1 час назад
31
+ 2: %1 часа назад
32
+ n: %1 часов назад
33
+ yesterday: вчера
34
+ days_ago: !!pl
35
+ 1: %1 день назад
36
+ 2: %1 дня назад
37
+ n: %1 дней назад
@@ -0,0 +1,245 @@
1
+ # encoding: utf-8
2
+ =begin
3
+ Filters for translations content.
4
+
5
+ Copyright (C) 2009 Andrey “A.I.” Sitnik <andrey@sitnik.ru>
6
+
7
+ This program is free software: you can redistribute it and/or modify
8
+ it under the terms of the GNU Lesser General Public License as published by
9
+ the Free Software Foundation, either version 3 of the License, or
10
+ (at your option) any later version.
11
+
12
+ This program is distributed in the hope that it will be useful,
13
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ GNU Lesser General Public License for more details.
16
+
17
+ You should have received a copy of the GNU Lesser General Public License
18
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
19
+ =end
20
+
21
+ require 'rubygems'
22
+
23
+ module R18n
24
+ # Filter is a way, to process translations: escape HTML entries, convert from
25
+ # Markdown syntax, etc.
26
+ #
27
+ # In translation file filtered content must be marked by YAML type:
28
+ #
29
+ # filtered: !!custom_type
30
+ # This content will be processed by filter
31
+ #
32
+ # Filter function will be receive filtered content as first argument, struct
33
+ # with filter config as second and filter parameters as next arguments.
34
+ #
35
+ # R18n::Filters.add('custom_type', :no_space) do |content, config, replace|
36
+ # content.gsub(' ', replace)
37
+ # end
38
+ # R18n::Filters.add('custom_type') do |content, config, replace|
39
+ # content + '!'
40
+ # end
41
+ #
42
+ # i18n.filtered('_') #=> "This_content_will_be_processed_by_filter!"
43
+ #
44
+ # Use String class as type to add global filter for all translated strings:
45
+ #
46
+ # R18n::Filters.add(String, :escape_html) do |content, config, params|
47
+ # escape_html(content)
48
+ # end
49
+ #
50
+ # Filter config contain two parameters: translation locale and path. But it is
51
+ # OpenStruct and you can add you own parameter to cross-filter communications:
52
+ #
53
+ # R18n::Filters.add(String, :hide_truth) do |content, config|
54
+ # return content if config.censorship_check
55
+ #
56
+ # if content.scan(CENSORSHIP_WORDS[config.locale]).empty?
57
+ # content
58
+ # else
59
+ # "Error in #{config.path}"
60
+ # end
61
+ # end
62
+ #
63
+ # R18n::Filters.add('passed', :show_lie) do |content, config|
64
+ # config.censorship_check = true
65
+ # content
66
+ # end
67
+ #
68
+ # You can disable, enabled and delete filters:
69
+ #
70
+ # R18n::Filters.off(:no_space))
71
+ # i18n.filtered('_') #=> "This content will be processed by filter!"
72
+ # R18n::Filters.on(:no_space)
73
+ # i18n.filtered('_') #=> "This_content_will_be_processed_by_filter!"
74
+ # R18n::Filters.delete(:no_space)
75
+ module Filters
76
+ Filter = Struct.new(:name, :type, :block, :enabled) do
77
+ def call(*params)
78
+ block.call(*params)
79
+ end
80
+
81
+ def enabled?
82
+ enabled
83
+ end
84
+ end
85
+
86
+ class << self
87
+ # Hash of filter names to Filters.
88
+ def defined
89
+ @defined ||= {}
90
+ end
91
+
92
+ # Hash of types to enabled Filters.
93
+ def enabled
94
+ @enabled ||= Hash.new([])
95
+ end
96
+
97
+ # Hash of types to all Filters.
98
+ def by_type
99
+ @by_type ||= Hash.new([])
100
+ end
101
+
102
+ # Process +translation+ by global filters and filters for special +type+.
103
+ def process(translation, locale, path, type, params)
104
+ case translation
105
+ when Numeric, NilClass, FalseClass, TrueClass, Symbol
106
+ else
107
+ translation = translation.clone
108
+ end
109
+ config = OpenStruct.new(:locale => locale, :path => path)
110
+
111
+ if type
112
+ filters = Filters.enabled[type]
113
+ filters.each { |f| translation = f.call(translation, config, *params)}
114
+ end
115
+
116
+ if translation.is_a? String
117
+ Filters.enabled[String].each do |f|
118
+ translation = f.call(translation, config, *params)
119
+ end
120
+ return TranslatedString.new(translation, locale, path)
121
+ else
122
+ translation
123
+ end
124
+ end
125
+
126
+ # Add new filter for +type+ with +name+ and return filter object. You
127
+ # can use String class as +type+ to add global filter for all translated
128
+ # string.
129
+ #
130
+ # Several filters for same type will be call consecutively, but you can
131
+ # set +position+ in call list.
132
+ #
133
+ # Filter content will be sent to +block+ as first argument, struct with
134
+ # config as second and filters parameters will be in next arguments.
135
+ def add(type, name = nil, position = nil, &block)
136
+ unless name
137
+ @last_auto_name ||= 0
138
+ begin
139
+ @last_auto_name += 1
140
+ name = @last_auto_name
141
+ end while defined.has_key? name
142
+ else
143
+ delete(name)
144
+ end
145
+
146
+ filter = Filter.new(name, type, block, true)
147
+ defined[name] = filter
148
+
149
+ unless enabled.has_key? type
150
+ enabled[type] = []
151
+ by_type[type] = []
152
+ end
153
+ if position
154
+ enabled[type].insert(position, filter)
155
+ by_type[type].insert(position, filter)
156
+ else
157
+ enabled[type] << filter
158
+ by_type[type] << defined[name]
159
+ end
160
+
161
+ filter
162
+ end
163
+
164
+ # Delete +filter+ by name or Filter object.
165
+ def delete(filter)
166
+ filter = defined[filter] unless filter.is_a? Filter
167
+ return unless filter
168
+
169
+ defined.delete(filter.name)
170
+ by_type[filter.type].delete(filter)
171
+ enabled[filter.type].delete(filter)
172
+ end
173
+
174
+ # Disable +filter+ by name or Filter object.
175
+ def off(filter)
176
+ filter = defined[filter] unless filter.is_a? Filter
177
+ return unless filter
178
+
179
+ filter.enabled = false
180
+ enabled[filter.type].delete(filter)
181
+ end
182
+
183
+ # Turn on disabled +filter+ by name or Filter object.
184
+ def on(filter)
185
+ filter = defined[filter] unless filter.is_a? Filter
186
+ return unless filter
187
+
188
+ filter.enabled = true
189
+ enabled[filter.type] = by_type[filter.type].reject { |i| !i.enabled? }
190
+ end
191
+ end
192
+ end
193
+
194
+ Filters.add('proc', :procedure) do |content, config, *params|
195
+ eval("proc { #{content} }").call(*params)
196
+ end
197
+
198
+ Filters.add('pl', :pluralization) do |content, config, param|
199
+ type = config.locale.pluralize(param)
200
+ type = 'n' if not content.include? type
201
+ content[type]
202
+ end
203
+
204
+ Filters.add(String, :variables) do |content, config, *params|
205
+ content = content.clone
206
+ params.each_with_index do |param, i|
207
+ if param.is_a? Float
208
+ param = config.locale.format_float(param)
209
+ elsif param.is_a? Integer
210
+ param = config.locale.format_integer(param)
211
+ end
212
+ content.gsub! "%#{i+1}", param.to_s
213
+ end
214
+ content
215
+ end
216
+
217
+ Filters.add('escape', :escape_html) do |content, config|
218
+ config.dont_escape_html = true
219
+ Utils.escape_html(content)
220
+ end
221
+
222
+ Filters.add('html', :dont_escape_html) do |content, config|
223
+ config.dont_escape_html = true
224
+ content
225
+ end
226
+
227
+ Filters.add(String, :global_escape_html) do |content, config|
228
+ if config.dont_escape_html
229
+ content
230
+ else
231
+ Utils.escape_html(content)
232
+ end
233
+ end
234
+ Filters.off(:global_escape_html)
235
+
236
+ Filters.add('markdown', :maruku) do |content, config|
237
+ require 'maruku'
238
+ ::Maruku.new(content).to_html
239
+ end
240
+
241
+ Filters.add('textile', :redcloth) do |content, config|
242
+ require 'redcloth'
243
+ ::RedCloth.new(content).to_html
244
+ end
245
+ end