Module: R18n::Filters

Defined in:
lib/r18n-core/filters.rb

Overview

Filter is a way, to process translations: escape HTML entries, convert from Markdown syntax, etc.

In translation file filtered content must be marked by YAML type:

filtered: !!custom_type
  This content will be processed by filter

Filter function will be receive filtered content as first argument, struct with filter config as second and filter parameters as next arguments. You can set passive filter, which will process translation only on loading.

R18n::Filters.add('custom_type', :no_space) do |content, config, replace|
  content.gsub(' ', replace)
end
R18n::Filters.add('custom_type', :passive => true) do |content, config|
  content + '!'
end

i18n.filtered('_') #=> "This_content_will_be_processed_by_filter!"

Use String class as type to add global filter for all translated strings:

R18n::Filters.add(String, :escape_html) do |content, config, params|
  escape_html(content)
end

Filter config contain two parameters: translation locale and path. But it is Hash and you can add you own parameter to cross-filter communications:

R18n::Filters.add(String, :hide_truth) do |content, config|
  return content if config[:censorship_check]

  if content.scan(CENSORSHIP_WORDS[config[:locale]]).empty?
    content
  else
    "Error in #{config[:path]}"
  end
end

R18n::Filters.add('passed', :show_lie) do |content, config|
  config[:censorship_check] = true
  content
end

You can disable, enabled and delete filters:

R18n::Filters.off(:no_space))
i18n.filtered('_') #=> "This content will be processed by filter!"
R18n::Filters.on(:no_space)
i18n.filtered('_') #=> "This_content_will_be_processed_by_filter!"
R18n::Filters.delete(:no_space)

You can enabled/disabled filters only for special I18n object:

R18n::I18n.new('en', nil, :on_filters  => [:untranslated_html, :no_space],
                          :off_filters => :untranslated )

Defined Under Namespace

Classes: Filter

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.active_enabledObject

Hash of types to enabled active filters.



90
91
92
# File 'lib/r18n-core/filters.rb', line 90

def active_enabled
  @active_enabled
end

.by_typeObject

Hash of types to all Filters.



87
88
89
# File 'lib/r18n-core/filters.rb', line 87

def by_type
  @by_type
end

.definedObject

Hash of filter names to Filters.



84
85
86
# File 'lib/r18n-core/filters.rb', line 84

def defined
  @defined
end

.enabledObject

Hash of types to enabled passive and active filters.



96
97
98
# File 'lib/r18n-core/filters.rb', line 96

def enabled
  @enabled
end

.passive_enabledObject

Hash of types to enabled passive filters.



93
94
95
# File 'lib/r18n-core/filters.rb', line 93

def passive_enabled
  @passive_enabled
end

Class Method Details

.add(types, name = nil, options = {}, &block) ⇒ Object

Add new filter for type with name and return filter object. You can use String class as type to add global filter for all translated string.

Filter content will be sent to block as first argument, struct with config as second and filters parameters will be in next arguments.

Options:

  • position – change order on processing several filters for same type.

    Note that passive filters will be always run before active.
    
  • passive – if true, filter will process only on translation loading. Note that you must add all passive before load translation.



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/r18n-core/filters.rb', line 128

def add(types, name = nil, options = {}, &block)
  options, name = name, nil if name.is_a? Hash
  types = Array(types)

  unless name
    @last_auto_name ||= 0
    begin
      @last_auto_name += 1
      name = @last_auto_name
    end while defined.has_key? name
  else
    delete(name)
  end

  filter = Filter.new(name, types, block, true, options[:passive])
  @defined[name] = filter

  types.each do |type|
    @by_type[type] = [] unless @by_type.has_key? type
    if options.has_key? :position
      @by_type[type].insert(options[:position], filter)
    else
      @by_type[type] << filter
    end
    rebuild_enabled! type
  end

  @new_filter_listener.call(filter) if @new_filter_listener
  filter
end

.delete(filter) ⇒ Object

Delete filter by name or Filter object.



160
161
162
163
164
165
166
167
168
169
# File 'lib/r18n-core/filters.rb', line 160

def delete(filter)
  filter = @defined[filter] unless filter.is_a? Filter
  return unless filter

  @defined.delete(filter.name)
  filter.types.each do |type|
    @by_type[type].delete(filter)
    rebuild_enabled! type
  end
end

.listen(&block) ⇒ Object

Return filters, which be added inside block.



190
191
192
193
194
195
196
# File 'lib/r18n-core/filters.rb', line 190

def listen(&block)
  filters = []
  @new_filter_listener = proc { |i| filters << i }
  yield
  @new_filter_listener = nil
  filters
end

.off(filter) ⇒ Object

Disable filter by name or Filter object.



172
173
174
175
176
177
178
# File 'lib/r18n-core/filters.rb', line 172

def off(filter)
  filter = @defined[filter] unless filter.is_a? Filter
  return unless filter

  filter.enabled = false
  filter.types.each { |type| rebuild_enabled! type }
end

.on(filter) ⇒ Object

Turn on disabled filter by name or Filter object.



181
182
183
184
185
186
187
# File 'lib/r18n-core/filters.rb', line 181

def on(filter)
  filter = @defined[filter] unless filter.is_a? Filter
  return unless filter

  filter.enabled = true
  filter.types.each { |type| rebuild_enabled! type }
end

.rebuild_enabled!(type) ⇒ Object

Rebuild active_enabled and passive_enabled for type.



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/r18n-core/filters.rb', line 99

def rebuild_enabled!(type)
  @passive_enabled[type] = []
  @active_enabled[type] = []
  @enabled[type] = []

  @by_type[type].each do |filter|
    if filter.enabled?
      @enabled[type] << filter
      if filter.passive?
        @passive_enabled[type] << filter
      else
        @active_enabled[type] << filter
      end
    end
  end
end